SpringBoot:如何優雅地處理全域性異常?
之前用springboot的時候,只知道捕獲異常使用try{}catch,一個介面一個try{}catch,這也是大多數開發人員異常處理的常用方式,雖然屢試不爽,但會造成一個問題,就是一個Controller下面,滿螢幕的try{}catch,看著一點都不優雅,一點都不符合小明的氣質,憋了這麼久,小明今天終於決定對所有異常實施統一處理的方案。
開發準備
JDK8、正常的springboot專案
程式碼編寫
通用異常處理
其實Spring系列的專案全域性異常處理方式早已存在,只不過我們一直忙於搬磚,很少停下腳步去審視這個日夜與我們相伴的朋友。為了貼合主題,本次主要針對SpringBoot全域性異常處理進行舉例說明。
SpringBoot中有一個@ControllerAdvice
的註解,使用該註解即表示開啟全域性異常捕獲,接下來我們只需在自定義的方法上使用@ExceptionHandler
註解,並定義捕獲異常的型別,對這種型別的異常進行統一的處理。
舉個例子:
假如我們需要針對NullException(空指標異常,是Java程式設計師最痛恨的異常,沒有之一)進行全域性處理(如下所示)。
@RestControllerAdvice public class GlobalExceptionHandler { /** * 處理空指標的異常 * @param req * @param e * @return */ @ExceptionHandler(value =NullPointerException.class) public BaseResponseFacade exceptionHandler(HttpServletRequest req, NullPointerException e){ log.error("發生空指標異常!原因是:",e); return ResponseUtil.error(ResponseCode.ERROR); } }
訥,就這麼簡單。其他可能發生的異常,都可以以這種方式處理快速處理。此處大家應該表現的十分興奮,但請不要高興太早,因為接下來,有更令激動人心的事情。
自定義異常處理
自定義一個異常
import lombok.AllArgsConstructor; import lombok.Data; import lombok.experimental.Accessors; /** * @Description 自定義異常 * @Date 2019-08-05 15:49 * @Created by 程式設計師小明 */ @Data @AllArgsConstructor @Accessors(chain = true) public class BizException extends RuntimeException { /** * 錯誤碼 */ protected Integer errorCode; /** * 錯誤資訊 */ protected String errorMsg; }
顯而易見,這個異常繼承了RuntimeException
,屬於執行時異常。細心的朋友已經發現,我使用了Lombok外掛,非常契合今天的主題,給大家簡單介紹一下:
lombok是一個可以幫助我們簡化java程式碼編寫的工具類,尤其是簡化javabean的編寫,即通過採用註解的方式,消除程式碼中的構造方法,getter/setter等程式碼,使我們寫的類更加簡潔(如果使用的IDE是idea,需要安裝外掛哈)。
定義過之後,我們就可以和之前處理NullException方式一樣處理我們自定義的異常。包括處理其他異常,都是這種方式。直接貼程式碼。
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 處理自定義的業務異常
* @param req
* @param e
* @return
*/
@ExceptionHandler(value = BizException.class)
public BaseResponseFacade bizExceptionHandler(HttpServletRequest req, BizException e){
log.error("發生業務異常!原因是:{}",e.getErrorMsg());
return ResponseUtil.error(e.getErrorCode(),e.getErrorMsg());
}
/**
* 處理空指標的異常
* @param req
* @param e
* @return
*/
@ExceptionHandler(value =NullPointerException.class)
public BaseResponseFacade exceptionHandler(HttpServletRequest req, NullPointerException e){
log.error("發生空指標異常!原因是:",e);
return ResponseUtil.error(ResponseCode.ERROR);
}
/**
* 處理其他異常
* @param req
* @param e
* @return
*/
@ExceptionHandler(value =Exception.class)
public BaseResponseFacade exceptionHandler(HttpServletRequest req, Exception e){
log.error("未知異常!原因是:",e);
return ResponseUtil.error(ResponseCode.INTERNAL_SERVER_ERROR);
}
}
整個全域性異常處理方式核心就是以上介紹這些。下面用一個Demo給大家舉個例子
@GetMapping("/test")
public BaseResponseFacade test(){
if(true){
throw new BizException(1,"error");
}
return ResponseUtil.success();
}
位址列請求,進入這個方法後,會丟擲異常,此時全域性異常生效,就會返回異常處理過後的資訊
{"errorCode":1,"errorMsg":"error","data":null}
到此整個流程都然跑通了。當然,好多地方都可以根據我們自身實際業務情況以此為基礎進一步豐富,比如返回資料可以改成跳轉某一個具體的頁面。這樣的出場方式是不是都很優雅?大家有什麼問題,期待各位留言