java實現(xiàn)統(tǒng)一異常處理的示例
對于Dao層 和Service產(chǎn)生的異常要一直網(wǎng)上拋,直至Controller層,但是對于controller層不能處理的異常也不能直接拋給前端。
為什么不能在service處理異常?
答:Service 層往往涉及數(shù)據(jù)庫事務(wù),出現(xiàn)異常同樣不適合捕獲,否則事務(wù)無法自動回滾。此外 Service 層涉及業(yè)務(wù)邏輯,有些業(yè)務(wù)邏輯執(zhí)行中遇到業(yè)務(wù)異常,可能需要在異常后轉(zhuǎn)入分支業(yè)務(wù)流程。如果業(yè)務(wù)異常都被框架捕獲了,業(yè)務(wù)功能就會不正常?!?strong>引用:極客時間的Java業(yè)務(wù)開發(fā)常見錯誤100例】
實現(xiàn)統(tǒng)一異常處理:
在spring框架下實現(xiàn)一個異常處理的類,用 @RestControllerAdvice + @ExceptionHandler
進(jìn)行修飾:
即@RestControllerAdvice默認(rèn)會攔截 controller類上拋出的不能處理的異常
一個全局異常處理類需要處理三類異常: 1.業(yè)務(wù)類異常,2.運(yùn)行時異常 ,3.Error
1.運(yùn)行時異常
/**
* @創(chuàng)建人: liup
* @創(chuàng)建時間: 2021/6/18
* @描述 全局異常捕獲處理類
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* @Author: liup
* @date: 2021/6/18 14:34
方法實現(xiàn)說明: 攔截運(yùn)行時異常
*/
@ExceptionHandler(value = RuntimeException.class)
public R runtimeExceptionHandle(RuntimeException e){
log.error("捕捉到運(yùn)行時異常",e);
return R.failed("未知錯誤");
}
}
目前僅是攔截運(yùn)行時異常
R 是返回的消息體:

那如果不使用GlobalExceptionHandler,會報出什么錯誤呢?
這個錯誤是在service層拋出的,當(dāng)從redis 通過key獲取一個已刪除的value時,redis返回的是null,但是我沒有判斷這個value是否為null,就將其打印出來:
log.info(authInfoVo.toString());

注意:這是要返回給前端的,msg的內(nèi)容,是對用戶十分不友好的。
2.Error
RuntimeException只是異常中的一個類,不能包含所有的異常體系,還有一大類是叫Error(系統(tǒng)級異常),所以需要有一個兜底的異常捕獲:
/**
* @Author: liup
* @date: 2021/6/18 15:01
方法實現(xiàn)說明: 捕獲系統(tǒng)級異常
*/
@ExceptionHandler(value = Throwable.class)
public R throwableHandle(Throwable th){
log.error("捕捉到Throwable異常",th);
return R.failed("系統(tǒng)異常");
}
和上面那個運(yùn)行時異常同時存在 。
3.業(yè)務(wù)類異常
【自己定義的異?!?/p>
首先創(chuàng)建業(yè)務(wù)異常類
/**
* @創(chuàng)建人: liup
* @創(chuàng)建時間: 2021/6/18
* @描述 業(yè)務(wù)類異常
*/
public class BusinessException extends RuntimeException{
@Getter
private final String code;
/**
* @Author: liup
* @date: 2021/6/18 15:10
方法實現(xiàn)說明: 根據(jù)消息碼【可用枚舉類】 構(gòu)造業(yè)務(wù)類異常
*/
public BusinessException(String code) {
this.code = code;
}
/**
* @Author: liup
* @date: 2021/6/18 15:08
方法實現(xiàn)說明: 自定義消息體構(gòu)造業(yè)務(wù)類異常
*/
public BusinessException(String code,String message) {
super(message);
this.code = code;
}
/**
* @Author: liup
* @date: 2021/6/18 15:09
方法實現(xiàn)說明: 根據(jù)異常 構(gòu)造業(yè)務(wù)類異常
*/
public BusinessException(String code,Throwable cause) {
super(cause);
this.code = code;
}
}
三種異常攔截同時存在;
/**
* @創(chuàng)建人: liup
* @創(chuàng)建時間: 2021/6/18
* @描述 全局異常捕獲處理類
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* @Author: liup
* @date: 2021/6/18 15:14
方法實現(xiàn)說明: 攔截業(yè)務(wù)類異常
*/
@ExceptionHandler(value = BusinessException.class)
public R businessExceptionHandle(BusinessException e){
log.error("捕獲業(yè)務(wù)類異常:",e);
return R.failed("業(yè)務(wù)類異常:"+e.getMessage());
}
/**
* @Author: liup
* @date: 2021/6/18 14:34
方法實現(xiàn)說明: 攔截運(yùn)行時異常
// */
@ExceptionHandler(value = RuntimeException.class)
public R runtimeExceptionHandle(RuntimeException e){
log.error("捕捉到運(yùn)行時異常",e);
return R.failed("未知錯誤:");
}
/**
* @Author: liup
* @date: 2021/6/18 15:01
方法實現(xiàn)說明: 捕獲系統(tǒng)級異常
*/
@ExceptionHandler(value = Throwable.class)
public R throwableHandle(Throwable th){
log.error("捕捉到Throwable異常",th);
return R.failed("系統(tǒng)異常");
}
}
4.對服務(wù)器友好:
以上是對前端友好,但是在服務(wù)器上,不是容易定位錯誤,
但是若是在參數(shù)上添加上HttpServletRequest req, HandlerMethod method,就很容易定位到錯誤
private static int GENERIC_SERVER_ERROR_CODE = 2000;
private static String GENERIC_SERVER_ERROR_MESSAGE = "服務(wù)器忙,請稍后再試";
@ExceptionHandler
public R handle(HttpServletRequest req, HandlerMethod method, Exception ex) {
if (ex instanceof BusinessException) {
BusinessException exception = (BusinessException) ex;
log.warn(String.format("訪問 %s -> %s 出現(xiàn)業(yè)務(wù)異常!", req.getRequestURI(), method.toString()), ex);
return R.failed(GENERIC_SERVER_ERROR_MESSAGE);
} else if (ex instanceof RuntimeException){
log.error(String.format("訪問 %s -> %s 出現(xiàn)運(yùn)行時異常!", req.getRequestURI(), method.toString()), ex);
return R.failed(GENERIC_SERVER_ERROR_MESSAGE);
}
else {
log.error(String.format("訪問 %s -> %s 出現(xiàn)系統(tǒng)異常!", req.getRequestURI(), method.toString()), ex);
return R.failed(GENERIC_SERVER_ERROR_MESSAGE);
}
}

到此這篇關(guān)于java實現(xiàn)統(tǒng)一異常處理的文章就介紹到這了,更多相關(guān)java異常處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解SpringBoot實現(xiàn)ApplicationEvent事件的監(jiān)聽與發(fā)布
這篇文章主要為大家詳細(xì)介紹了SpringBoot如何實現(xiàn)ApplicationEvent事件的監(jiān)聽與發(fā)布,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-03-03
使用mybatis報Invalid bound statement解決分析
這篇文章主要為大家介紹了使用mybatis報Invalid bound statement原因解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
關(guān)于Mybatis-Plus字段策略與數(shù)據(jù)庫自動更新時間的一些問題
這篇文章主要介紹了關(guān)于Mybatis-Plus字段策略與數(shù)據(jù)庫自動更新時間的一些問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
SpringBoot實現(xiàn)微服務(wù)通信的多種方式
微服務(wù)通信是指在分布式系統(tǒng)中,各個微服務(wù)之間進(jìn)行數(shù)據(jù)交互和通信的過程,今天我們將探討在Spring Boot中實現(xiàn)微服務(wù)通信的多種方式,文章通過代碼示例給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-07-07
java實現(xiàn)人民幣大小寫轉(zhuǎn)換方法分享
本文介紹java人民幣數(shù)字大小寫轉(zhuǎn)換方法,代碼中有注釋,大家直接看代碼吧2014-01-01

