java實現統一異常處理的示例
對於Dao層 和Service產生的異常要一直網上拋,直至Controller層,但是對於controller層不能處理的異常也不能直接拋給前端。
為什麼不能在service處理異常?
答:Service 層往往涉及數據庫事務,出現異常同樣不適合捕獲,否則事務無法自動回滾。此外 Service 層涉及業務邏輯,有些業務邏輯執行中遇到業務異常,可能需要在異常後轉入分支業務流程。如果業務異常都被框架捕獲瞭,業務功能就會不正常。【引用:極客時間的Java業務開發常見錯誤100例】
實現統一異常處理:
在spring框架下實現一個異常處理的類,用 @RestControllerAdvice + @ExceptionHandler
進行修飾:
即@RestControllerAdvice默認會攔截 controller類上拋出的不能處理的異常
一個全局異常處理類需要處理三類異常: 1.業務類異常,2.運行時異常 ,3.Error
1.運行時異常
/** * @創建人: liup * @創建時間: 2021/6/18 * @描述 全局異常捕獲處理類 */ @RestControllerAdvice @Slf4j public class GlobalExceptionHandler { /** * @Author: liup * @date: 2021/6/18 14:34 方法實現說明: 攔截運行時異常 */ @ExceptionHandler(value = RuntimeException.class) public R runtimeExceptionHandle(RuntimeException e){ log.error("捕捉到運行時異常",e); return R.failed("未知錯誤"); } }
目前僅是攔截運行時異常
R 是返回的消息體:
那如果不使用GlobalExceptionHandler,會報出什麼錯誤呢?
這個錯誤是在service層拋出的,當從redis 通過key獲取一個已刪除的value時,redis返回的是null,但是我沒有判斷這個value是否為null,就將其打印出來:
log.info(authInfoVo.toString());
註意:這是要返回給前端的,msg的內容,是對用戶十分不友好的。
2.Error
RuntimeException隻是異常中的一個類,不能包含所有的異常體系,還有一大類是叫Error(系統級異常),所以需要有一個兜底的異常捕獲:
/** * @Author: liup * @date: 2021/6/18 15:01 方法實現說明: 捕獲系統級異常 */ @ExceptionHandler(value = Throwable.class) public R throwableHandle(Throwable th){ log.error("捕捉到Throwable異常",th); return R.failed("系統異常"); }
和上面那個運行時異常同時存在 。
3.業務類異常
【自己定義的異常】
首先創建業務異常類
/** * @創建人: liup * @創建時間: 2021/6/18 * @描述 業務類異常 */ public class BusinessException extends RuntimeException{ @Getter private final String code; /** * @Author: liup * @date: 2021/6/18 15:10 方法實現說明: 根據消息碼【可用枚舉類】 構造業務類異常 */ public BusinessException(String code) { this.code = code; } /** * @Author: liup * @date: 2021/6/18 15:08 方法實現說明: 自定義消息體構造業務類異常 */ public BusinessException(String code,String message) { super(message); this.code = code; } /** * @Author: liup * @date: 2021/6/18 15:09 方法實現說明: 根據異常 構造業務類異常 */ public BusinessException(String code,Throwable cause) { super(cause); this.code = code; } }
三種異常攔截同時存在;
/** * @創建人: liup * @創建時間: 2021/6/18 * @描述 全局異常捕獲處理類 */ @RestControllerAdvice @Slf4j public class GlobalExceptionHandler { /** * @Author: liup * @date: 2021/6/18 15:14 方法實現說明: 攔截業務類異常 */ @ExceptionHandler(value = BusinessException.class) public R businessExceptionHandle(BusinessException e){ log.error("捕獲業務類異常:",e); return R.failed("業務類異常:"+e.getMessage()); } /** * @Author: liup * @date: 2021/6/18 14:34 方法實現說明: 攔截運行時異常 // */ @ExceptionHandler(value = RuntimeException.class) public R runtimeExceptionHandle(RuntimeException e){ log.error("捕捉到運行時異常",e); return R.failed("未知錯誤:"); } /** * @Author: liup * @date: 2021/6/18 15:01 方法實現說明: 捕獲系統級異常 */ @ExceptionHandler(value = Throwable.class) public R throwableHandle(Throwable th){ log.error("捕捉到Throwable異常",th); return R.failed("系統異常"); } }
4.對服務器友好:
以上是對前端友好,但是在服務器上,不是容易定位錯誤,
但是若是在參數上添加上HttpServletRequest req, HandlerMethod method,就很容易定位到錯誤
private static int GENERIC_SERVER_ERROR_CODE = 2000; private static String GENERIC_SERVER_ERROR_MESSAGE = "服務器忙,請稍後再試"; @ExceptionHandler public R handle(HttpServletRequest req, HandlerMethod method, Exception ex) { if (ex instanceof BusinessException) { BusinessException exception = (BusinessException) ex; log.warn(String.format("訪問 %s -> %s 出現業務異常!", req.getRequestURI(), method.toString()), ex); return R.failed(GENERIC_SERVER_ERROR_MESSAGE); } else if (ex instanceof RuntimeException){ log.error(String.format("訪問 %s -> %s 出現運行時異常!", req.getRequestURI(), method.toString()), ex); return R.failed(GENERIC_SERVER_ERROR_MESSAGE); } else { log.error(String.format("訪問 %s -> %s 出現系統異常!", req.getRequestURI(), method.toString()), ex); return R.failed(GENERIC_SERVER_ERROR_MESSAGE); } }
到此這篇關於java實現統一異常處理的文章就介紹到這瞭,更多相關java異常處理內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- springboot 自定義異常並捕獲異常返給前端的實現代碼
- Spring Boot全局統一異常處理器
- SpringBoot中controller深層詳細講解
- java使用枚舉封裝錯誤碼及錯誤信息詳解
- 解決spring @ControllerAdvice處理異常無法正確匹配自定義異常