Spring MVC 是经过 HandlerExceptionResolver
处理程序的异常,包括请求映射、数据绑定以及处理器执行时发生的异常html
HandlerExceptionResolver
只有一个接口方法java
public interface HandlerExceptionResolver { ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex); }
resolveException
方法尝试解决在处理程序执行期间引起的异常,处理以后返回 ModelAndView,转到对应的视图做为异常报告反馈给用户web
下面是可用的 HandlerExceptionResolver 实现:ajax
HandlerExceptionResolver | 描述 |
---|---|
SimpleMappingExceptionResolver | 异常类名称和错误视图名称之间的映射,用于在浏览器应用程序中呈现错误页面 |
DefaultHandlerExceptionResolver | 解决Spring MVC引起的异常,并将它们映射到HTTP状态代码 |
ResponseStatusExceptionResolver | 使用@ResponseStatus注解解析异常,并根据注解中的值将它们映射到 HTTP 状态代码 |
ExceptionHandlerExceptionResolver | 经过调用或类中的 @ExceptionHandler 方法来解决异常 |
Spring MVC 默认注册了这些内置异常解析器,用于支持 @ResponseStatus 注释异常和@ExceptionHandler方法spring
spring mvc 异常处理类结构图
浏览器
上图咱们能够看到 AbstractHandlerExceptionResolver 实现了 Ordered 接口,这样造成了一个异常处理链,DispatcherServlet 把异常委托给 HandlerExceptionResolver 解析链以解决异常并提供替代处理。这个与视图解析器是类似的。mvc
能够经过HandlerExceptionResolver 在Spring配置中声明多个bean并根据须要设置 order 属性来造成异常解析链。order 的值越高,异常解析器定位的越晚。app
HandlerExceptionResolver
有三种返回状况:url
处理后返回 ModelAndView 指向错误视图spa
若是异常在解析器中已经处理完,则返回空的 ModelAndView
返回 null,代表异常仍未解决,则由后续解析器继续处理,若是异常最后还在,则容许冒泡到Servlet容器
@ExceptionHandler
方法是在 @Controller 和 @ControllerAdvice 类中定义的,用来处理来自控制器方法的异常
若是 @ExceptionHandler
方法是在控制器内部定义的,那么它会接收并处理由控制器(或其任何子类)中的 @RequestMapping 方法抛出的异常;若是是定义在 @ControllerAdvice 类中,那么它会处理相关控制器中抛出的异常
@Controller public class SimpleController { // ... @ExceptionHandler public ResponseEntity<String> handle(IOException ex) { // ... } }
@ExceptionHandler
方法的方法参数和返回值能够很灵活。好比,在Servlet环境下方法能够接收HttpServletRequest
参数。返回值能够是String
类型(会被解析为视图名)、能够是ModelAndView
类型的对象,也能够是ResponseEntity
。
@Controller public class SimpleController { @ExceptionHandler(RuntimeException.class) public ModelAndView error(RuntimeException error, HttpServletRequest request) { ModelAndView mav = new ModelAndView(); mav.setViewName("error"); mav.addObject("param", "Runtime error"); return mav; } @ExceptionHandler() public ModelAndView error(Exception error, HttpServletRequest request, HttpServletResponse response) { ModelAndView mav = new ModelAndView(); mav.setViewName("error"); mav.addObject("param", "Exception error"); return mav; } }
@ExceptionHandler
只能处理同一个 Controller 里的异常,想要设置全局的异常处理,可把 @ExceptionHandler
方法写在一个 BaseController 里面,让其余 Controller 继承它。另外还可使用 @ControllerAdvice
+@ExceptionHandler
这里咱们使用 @RestControllerAdvice
,至关于 @ControllerAdvice
和 @ResponseBody
同时处理 web 和 ajax 异常
@RestControllerAdvice public class ExceptionHandle { @ExceptionHandler public Object handle(HttpServletRequest request, HttpServletResponse response,Exception e){ if(request.getHeader("X-Requested-With")!=null &&"XMLHttpRequest".equals(request.getHeader("X-Requested-With").toString())){ return JSONResult.error(e.getMessage()); }else{ ModelAndView mv = new ModelAndView(); mv.addObject("exception",e); mv.addObject("url",request.getRequestURL()); mv.setViewName("/error"); return mv; } } }
若是异常最后未被任何 HandlerExceptionResolver
解决,而且所以将其传播或者若是响应状态设置为错误状态(即4xx,5xx),则Servlet容器能够在HTML中呈现默认错误页面。能够在 web.xml 中声明错误页面映射
web.xml
<error-page> <location>/error</location> </error-page>
<error-page> <error-code>404</error-code> <location>/resources/error/404.html</location> </error-page> <error-page> <error-code>500</error-code> <location>/resources/error/500.html</location> </error-page>