spring mvc 異常處理機制和統一異常處理

1、異常處理機制

Spring MVC 是經過 HandlerExceptionResolver 處理程序的異常,包括請求映射、數據綁定以及處理器執行時發生的異常html

一、HandlerExceptionResolver

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 異常處理類結構圖
spring mvc 異常處理類結構瀏覽器

上圖咱們能夠看到 AbstractHandlerExceptionResolver 實現了 Ordered 接口,這樣造成了一個異常處理鏈,DispatcherServlet 把異常委託給 HandlerExceptionResolver 解析鏈以解決異常並提供替代處理。這個與視圖解析器是類似的。mvc

能夠經過HandlerExceptionResolver 在Spring配置中聲明多個bean並根據須要設置 order 屬性來造成異常解析鏈。order 的值越高,異常解析器定位的越晚。app

HandlerExceptionResolver 有三種返回狀況:url

  • 處理後返回 ModelAndView 指向錯誤視圖spa

  • 若是異常在解析器中已經處理完,則返回空的 ModelAndView

  • 返回 null,代表異常仍未解決,則由後續解析器繼續處理,若是異常最後還在,則容許冒泡到Servlet容器

2、異常處理

  • 直接實現 HandlerExceptionResolver
  • 使用@ExceptionHandler註解
  • @ControllerAdvice+@ExceptionHandler

一、使用@ExceptionHandler註解

@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

二、@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;
        }
    }
}

3、容器錯誤頁面

若是異常最後未被任何 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>
相關文章
相關標籤/搜索