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>