一、前言
在搭建工程的時候,統一處理拋出的異常會讓我們的程序看起來更加整潔,有序,方便管理。所以我打算在我的項目中配置使用統一異常處理。
二、步驟
一般來說有三個步驟:
1. 定義錯誤
2. 將錯誤映射成異常
3. 處理異常,然后讓異常以自己需要的形式返回到前端。
三、 具體實現
1. 定義錯誤
public enum Error { NO_TOKEN_FOUND(1, "No token found"), NO_VALID_TOKEN(2, "Token is not valid"); public final int errorCode; public final String errorMessage; private Error(int errorCode, String errorMessage) { this.errorCode = errorCode; this.errorMessage = errorMessage; } public int getErrorCode() { return errorCode; } public String getErrorMessage() { return errorMessage; } }
2. 將錯誤映射成異常
public class RequestException extends Exception{ private static final long serialVersionUID = 1L; private final Error error; public RequestException(Error err) { super(err.getErrorMessage()); this.error = err; } public Error getError() { return error; } }
3. 處理異常,然后讓異常以自己需要的形式返回到前端。(這里我是直接返回的是Map形式的數據)
@ControllerAdvice public class ExceptionHandle { @ExceptionHandler(value = Exception.class) @ResponseBody public Map<String, String> handler( Exception e){ RequestException requestException = (RequestException) e; Map map = new HashMap<String, String>(); map.put(requestException.getError().errorCode,requestException.getError().errorMessage); return map; } }
4. 使用我們定義的異常
User user = userRespository.findOne(userId); if (user == null) { throw new RequestException(Error.USER_DOES_NOT_EXIST);//這里會產生一個新的異常,然后步驟三的操作會捕捉到異常,以我們定義的形式返回到前端 }
四、擴展延伸
- @ExceptionHandler:統一處理某一類異常,從而能夠減少代碼重復率和復雜度
- @ControllerAdvice:異常集中處理,更好的使業務邏輯與異常處理剝離開
- @ResponseStatus:可以將某種異常映射為HTTP狀態碼
@ExceptionHandler
源碼如下:
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ExceptionHandler { Class<? extends Throwable>[] value() default {}; }
該注解作用對象為方法,並且在運行時有效,value()可以指定異常類。由該注解注釋的方法可以具有靈活的輸入參數(詳細參見Spring API):
- 異常參數:包括一般的異常或特定的異常(即自定義異常),如果注解沒有指定異常類,會默認進行映射。
- 請求或響應對象 (Servlet API or Portlet API): 你可以選擇不同的類型,如ServletRequest/HttpServletRequest或PortleRequest/ActionRequest/RenderRequest
。
- Session對象(Servlet API or Portlet API): HttpSession或PortletSession。
- WebRequest或NativeWebRequest
- Locale
- InputStream/Reader
- OutputStream/Writer
Model
方法返回值可以為:
- ModelAndView對象
- Model對象
- Map對象
- View對象
- String對象
- 還有@ResponseBody、HttpEntity<?>或ResponseEntity<?>,以及void
@ControllerAdvice
源碼如下:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface ControllerAdvice { @AliasFor("basePackages") String[] value() default {}; @AliasFor("value") String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; Class<?>[] assignableTypes() default {}; Class<? extends Annotation>[] annotations() default {}; }
該注解作用對象為TYPE,包括類、接口和枚舉等,在運行時有效,並且可以通過Spring掃描為bean組件。其可以包含由@ExceptionHandler、@InitBinder 和@ModelAttribute標注的方法,可以處理多個Controller類,這樣所有控制器的異常可以在一個地方進行處理。