文章目錄
- 1. 全局異常處理
- 2. 項目異常處理方案
- 2.1 異常分類
- 2.2 異常解決方案
- 2.3 異常解決方案具體實現
1. 全局異常處理
-
問題:當我們在SpingMVC代碼中沒有對異常進行處理時,三層架構的默認處理異常方案是將異常拋給上級調用者。也就是說Mapper層報錯會將異常上拋給Service層,Service層報錯會將異常上拋給Controller層,最終拋給框架之后會把各種各樣的錯誤信息直接返回給前端,前端往往難以解析這些五花八門的異常。
-
解決方案:SpingMVC提供了全局異常處理器,捕獲不同的異常進行特定的處理。
-
實現方法:
-
在類上加
@RestControllerAdvice
注解,加上這個注解就代表我們定義了一個全局異常處理器,同時需要確保該類能夠被Spring容器掃描到。@RestControllerAdvice
=@ControllerAdvice
+@ResponseBody
處理異常的方法返回值會轉換為Json后再響應給前端
-
在全局異常處理器當中,需要定義一個方法來捕獲異常,在這個方法上需要加上注解
@ExceptionHandler
。通過@ExceptionHandler
注解當中的value屬性來指定我們要捕獲的是哪一類型的異常。@RestControllerAdvice public class GlobalExceptionHandler {//處理異常@ExceptionHandler(Exception.class) //指定能夠處理的異常類型public Result ex(Exception e){e.printStackTrace(); //打印堆棧中的異常信息//捕獲到異常之后,響應一個標準的Resultreturn Result.error("對不起,操作失敗,請聯系管理員");} }
-
2. 項目異常處理方案
2.1 異常分類
-
因為異常的種類有很多,如果每一個異常都對應一個
@ExceptionHandler
,那得寫多少個方法來處理各自的異常,所以我們在處理異常之前,需要對異常進行一個分類:-
業務異常(BusinessException)
-
規范的用戶行為產生的異常
-
用戶在頁面輸入內容的時候未按照指定格式進行數據填寫,如在年齡框輸入的是字符串
-
-
不規范的用戶行為操作產生的異常
-
如用戶故意傳遞錯誤數據
-
-
-
系統異常(SystemException)
- 項目運行過程中可預計但無法避免的異常
- 比如數據庫或服務器宕機
- 項目運行過程中可預計但無法避免的異常
-
其他異常(Exception)
-
編程人員未預期到的異常,如:用到的文件不存在
-
將異常分類以后,針對不同類型的異常,要提供具體的解決方案:
-
2.2 異常解決方案
- 業務異常(BusinessException)
- 發送對應消息傳遞給用戶,提醒規范操作
- 大家常見的就是提示用戶名已存在或密碼格式不正確等
- 發送對應消息傳遞給用戶,提醒規范操作
- 系統異常(SystemException)
- 發送固定消息傳遞給用戶,安撫用戶
- 系統繁忙,請稍后再試
- 系統正在維護升級,請稍后再試
- 系統出問題,請聯系系統管理員等
- 發送特定消息給運維人員,提醒維護
- 可以發送短信、郵箱或者是公司內部通信軟件
- 記錄日志
- 發消息和記錄日志對用戶來說是不可見的,屬于后臺程序
- 發送固定消息傳遞給用戶,安撫用戶
- 其他異常(Exception)
- 發送固定消息傳遞給用戶,安撫用戶
- 發送特定消息給編程人員,提醒維護(納入預期范圍內)
- 一般是程序沒有考慮全,比如未做非空校驗等
- 記錄日志
2.3 異常解決方案具體實現
-
自定義異常類:添加code屬性以區分異常來自哪個業務。
//自定義異常處理器,用于封裝異常信息,對異常進行分類 @Data public class SystemException extends RuntimeException{private Integer code;public SystemException(Integer code, String message) {super(message);this.code = code;}public SystemException(Integer code, String message, Throwable cause) {super(message, cause);this.code = code;} }//自定義異常處理器,用于封裝異常信息,對異常進行分類 @Data public class BusinessException extends RuntimeException{private Integer code;public BusinessException(Integer code, String message) {super(message);this.code = code;}public BusinessException(Integer code, String message, Throwable cause) {super(message, cause);this.code = code;} }
//狀態碼 public class Code {public static final Integer SAVE_OK = 20011;public static final Integer DELETE_OK = 20021;public static final Integer UPDATE_OK = 20031;public static final Integer GET_OK = 20041;public static final Integer SAVE_ERR = 20010;public static final Integer DELETE_ERR = 20020;public static final Integer UPDATE_ERR = 20030;public static final Integer GET_ERR = 20040;public static final Integer SYSTEM_ERR = 50001;public static final Integer SYSTEM_TIMEOUT_ERR = 50002;public static final Integer SYSTEM_UNKNOW_ERR = 59999;public static final Integer BUSINESS_ERR = 60002; }
-
將其他異常換成自定義異常:
public Book getById(Integer id) {//模擬業務異常,包裝成自定義異常if(id == 1){throw new BusinessException(Code.BUSINESS_ERR,"業務異常,用戶注意相關格式");}//模擬系統異常,將可能出現的異常進行包裝,轉換成自定義異常try{int i = 1/0;}catch (Exception e){throw new SystemException(Code.SYSTEM_TIMEOUT_ERR,"服務器訪問超時,請重試!",e);}return bookDao.getById(id); }
-
處理器類中處理自定義異常:
//@RestControllerAdvice用于標識當前類為REST風格對應的異常處理器 @RestControllerAdvice public class ProjectExceptionAdvice {@ExceptionHandler(SystemException.class)public Result doSystemException(SystemException ex){//記錄日志//發送消息給運維//發送郵件給開發人員,ex對象發送給開發人員return new Result(ex.getCode(),null,ex.getMessage());}@ExceptionHandler(BusinessException.class)public Result doBusinessException(BusinessException ex){return new Result(ex.getCode(),null,ex.getMessage());}//除了自定義的異常處理器,保留對Exception類型的異常處理,用于處理非預期的異常@ExceptionHandler(Exception.class)public Result doOtherException(Exception ex){//記錄日志//發送消息給運維//發送郵件給開發人員,ex對象發送給開發人員return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系統繁忙,請稍后再試!");} }