統一處理某一類異常,能夠減少代碼的重復度和復雜度,有利於代碼的維護。springmvc統一處理異常有三種方式
- @ExceptionHandler
使用@ExceptionHandler注解作用在方法上面,參數是具體的異常類型。一旦系統拋出這種類型的異常時,會引導到該方法來處理。但是它的缺陷很明顯
處理異常的方法和出錯的方法(或者異常最終拋出來的地方)必須在同一個controller,不能全局控制。
@RequestMapping(value = "/error111",method = RequestMethod.GET) @ResponseBody public ResultBean error111(){ service.test(); // int i = 1/0; return null; } @ExceptionHandler(RuntimeException.class) @ResponseBody public String error3(){ return "run time exception"; } @org.springframework.stereotype.Service public class Service { public void test(){ int i = 1/0; } }
- @ControllerAdvice + @ExceptionHandler
使用@ControllerAdvice 和@ExceptionHandler 可以全局控制異常,使業務邏輯和異常處理分隔開。
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MyException.class) @ResponseBody public ResultBean handleMyException(MyException e){ System.out.println("handleMyException...."); return new ResultBean(e.getErrorEnum().getCode(),e.getErrorEnum().getMsg()); } } public class MyException extends RuntimeException { private ErrorEnum errorEnum; public MyException(ErrorEnum errorEnum){ this.errorEnum = errorEnum; } public ErrorEnum getErrorEnum() { return errorEnum; } } public enum ErrorEnum { SystemError("999","系統異常,請聯系管理員"), MyError1("001","自定義異常1"), MyError2("002","自定義異常2"), MyError3("003","自定義異常3"); private String code; private String msg; ErrorEnum(String code,String msg){ this.code = code; this.msg = msg; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } } @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) public class ResultBean <T>{ private final String SUCCESSCODE = "000"; private final String SUCCESSMSG = "請求成功"; /** *999 : 請求失敗 (系統異常:這時候具體問題原因要去看日志) *000 : 請求成功 * *001 : 自定義異常1,用戶一眼就能看出問題在哪 *002 : 自定義異常2,用戶一眼就能看出問題在哪 *003 : 自定義異常3,用戶一眼就能看出問題在哪 * * * */ public String code; public String message; public T data; public ResultBean(){ this.code = SUCCESSCODE; this.message = SUCCESSMSG; } public ResultBean(String code, String message) { this.code = code; this.message = message; } public ResultBean(T data) { this(); this.data = data; } }
- 實現 HandlerExceptionResolver 接口
@Component public class MyException implements HandlerExceptionResolver{ /** * TODO 簡單描述該方法的實現功能(可選). * @see org.springframework.web.servlet.HandlerExceptionResolver#resolveException(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception) */ public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println("This is exception handler method!"); return null; } }
優先級
既然在SpringMVC中有兩種處理異常的方式,那么就存在一個優先級的問題:
當發生異常的時候,SpringMVC會如下處理:
(1)SpringMVC會先從配置文件找異常解析器HandlerExceptionResolver
(2)如果找到了異常異常解析器,那么接下來就會判斷該異常解析器能否處理當前發生的異常
(3)如果可以處理的話,那么就進行處理,然后給前台返回對應的異常視圖
(4)如果沒有找到對應的異常解析器或者是找到的異常解析器不能處理當前的異常的時候,就看當前的Controller中有沒有提供對應的異常處理器,如果提供了就由Controller自己進行處理並返回對應的視圖
(5)如果配置文件里面沒有定義對應的異常解析器,而當前Controller中也沒有定義的話,就看有沒有全局ControllerAdvice提供的全局異常處理器,如果沒有那么該異常就會被拋出來。