Spring Boot項(xiàng)目?jī)?yōu)雅的全局異常處理方式(全網(wǎng)最新)

前言

在日常項(xiàng)目開發(fā)中丧凤,異常是常見的,但是如何更高效的處理好異常信息俘陷,讓我們能快速定位到BUG罗捎,是很重要的,不僅能夠提高我們的開發(fā)效率拉盾,還能讓你代碼看上去更舒服桨菜,SpringBoot的項(xiàng)目已經(jīng)對(duì)有一定的異常處理了,但是對(duì)于我們開發(fā)者而言可能就不太合適了捉偏,因此我們需要對(duì)這些異常進(jìn)行統(tǒng)一的捕獲并處理倒得。


一、全局異常處理方式一

SpringBoot中夭禽,@ControllerAdvice 即可開啟全局異常處理霞掺,使用該注解表示開啟了全局異常的捕獲,我們只需在自定義一個(gè)方法使用@ExceptionHandler注解然后定義捕獲異常的類型即可對(duì)這些捕獲的異常進(jìn)行統(tǒng)一的處理讹躯。

1.1 自定義全局異常類

/**
 * @description: 自定義異常處理
 * @author: DT
 * @date: 2021/4/19 21:17
 * @version: v1.0
 */
@ControllerAdvice
public class MyExceptionHandler {

    @ExceptionHandler(value =Exception.class)
    @ResponseBody
    public String exceptionHandler(Exception e){
        System.out.println("全局異常捕獲>>>:"+e);
        return "全局異常捕獲,錯(cuò)誤原因>>>"+e.getMessage();
    }
}

1.2 手動(dòng)拋出異常

 @GetMapping("/getById/{userId}")
public CommonResult<User> getById(@PathVariable Integer userId){
    // 手動(dòng)拋出異常
    int a = 10/0;
    return CommonResult.success(userService.getById(userId));
}

1.3 測(cè)試打印

image

在這里插入圖片描述

很顯然這樣的用戶體驗(yàn)效果是極差的菩彬,雖然這種能夠讓我們知道異常的原因缠劝,但是在很多的情況下來(lái)說(shuō),可能還是不夠人性化骗灶,不符合我們的要求惨恭。

二、全局異常處理方式二

2.1 定義基礎(chǔ)接口類

/**
 * @description: 服務(wù)接口類
 * @author: DT
 * @date: 2021/4/19 21:39
 */
public interface BaseErrorInfoInterface {

    /**
     *  錯(cuò)誤碼
     * @return
     */
    String getResultCode();

    /**
     * 錯(cuò)誤描述
     * @return
     */
    String getResultMsg();
}

2.2 定義枚舉類

/**
 * @description: 異常處理枚舉類
 * @author: DT
 * @date: 2021/4/19 21:41
 * @version: v1.0
 */
public enum ExceptionEnum implements BaseErrorInfoInterface{
    
    // 數(shù)據(jù)操作錯(cuò)誤定義
    SUCCESS("2000", "成功!"),
    BODY_NOT_MATCH("4000","請(qǐng)求的數(shù)據(jù)格式不符!"),
    SIGNATURE_NOT_MATCH("4001","請(qǐng)求的數(shù)字簽名不匹配!"),
    NOT_FOUND("4004", "未找到該資源!"),
    INTERNAL_SERVER_ERROR("5000", "服務(wù)器內(nèi)部錯(cuò)誤!"),
    SERVER_BUSY("5003","服務(wù)器正忙耙旦,請(qǐng)稍后再試!");

    /**
     * 錯(cuò)誤碼
     */
    private final String resultCode;

    /**
     * 錯(cuò)誤描述
     */
    private final String resultMsg;

    ExceptionEnum(String resultCode, String resultMsg) {
        this.resultCode = resultCode;
        this.resultMsg = resultMsg;
    }

    @Override
    public String getResultCode() {
        return resultCode;
    }

    @Override
    public String getResultMsg() {
        return resultMsg;
    }
}

2.3 自定義異常類

/**
 * @description: 自定義異常類
 * @author: DT
 * @date: 2021/4/19 21:44
 * @version: v1.0
 */
public class BizException extends RuntimeException{

    private static final long serialVersionUID = 1L;

    /**
     * 錯(cuò)誤碼
     */
    protected String errorCode;
    /**
     * 錯(cuò)誤信息
     */
    protected String errorMsg;

    public BizException() {
        super();
    }

    public BizException(BaseErrorInfoInterface errorInfoInterface) {
        super(errorInfoInterface.getResultCode());
        this.errorCode = errorInfoInterface.getResultCode();
        this.errorMsg = errorInfoInterface.getResultMsg();
    }

    public BizException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) {
        super(errorInfoInterface.getResultCode(), cause);
        this.errorCode = errorInfoInterface.getResultCode();
        this.errorMsg = errorInfoInterface.getResultMsg();
    }

    public BizException(String errorMsg) {
        super(errorMsg);
        this.errorMsg = errorMsg;
    }

    public BizException(String errorCode, String errorMsg) {
        super(errorCode);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }

    public BizException(String errorCode, String errorMsg, Throwable cause) {
        super(errorCode, cause);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }


    public String getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    @Override
    public Throwable fillInStackTrace() {
        return this;
    }
}

2.4 自定義數(shù)據(jù)傳輸

/**
 * @description: 自定義數(shù)據(jù)傳輸
 * @author: DT
 * @date: 2021/4/19 21:47
 * @version: v1.0
 */
public class ResultResponse {
    /**
     * 響應(yīng)代碼
     */
    private String code;

    /**
     * 響應(yīng)消息
     */
    private String message;

    /**
     * 響應(yīng)結(jié)果
     */
    private Object result;

    public ResultResponse() {
    }

    public ResultResponse(BaseErrorInfoInterface errorInfo) {
        this.code = errorInfo.getResultCode();
        this.message = errorInfo.getResultMsg();
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }

    /**
     * 成功
     *
     * @return
     */
    public static ResultResponse success() {
        return success(null);
    }

    /**
     * 成功
     * @param data
     * @return
     */
    public static ResultResponse success(Object data) {
        ResultResponse rb = new ResultResponse();
        rb.setCode(ExceptionEnum.SUCCESS.getResultCode());
        rb.setMessage(ExceptionEnum.SUCCESS.getResultMsg());
        rb.setResult(data);
        return rb;
    }

    /**
     * 失敗
     */
    public static ResultResponse error(BaseErrorInfoInterface errorInfo) {
        ResultResponse rb = new ResultResponse();
        rb.setCode(errorInfo.getResultCode());
        rb.setMessage(errorInfo.getResultMsg());
        rb.setResult(null);
        return rb;
    }

    /**
     * 失敗
     */
    public static ResultResponse error(String code, String message) {
        ResultResponse rb = new ResultResponse();
        rb.setCode(code);
        rb.setMessage(message);
        rb.setResult(null);
        return rb;
    }

    /**
     * 失敗
     */
    public static ResultResponse error( String message) {
        ResultResponse rb = new ResultResponse();
        rb.setCode("-1");
        rb.setMessage(message);
        rb.setResult(null);
        return rb;
    }

    @Override
    public String toString() {
        return JSONObject.toJSONString(this);
    }

}

2.5 自定義全局異常處理

/**
 * @description: 自定義異常處理
 * @author: DT
 * @date: 2021/4/19 21:51
 * @version: v1.0
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 處理自定義的業(yè)務(wù)異常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = BizException.class)
    @ResponseBody
    public ResultResponse bizExceptionHandler(HttpServletRequest req, BizException e){
        logger.error("發(fā)生業(yè)務(wù)異常脱羡!原因是:{}",e.getErrorMsg());
        return ResultResponse.error(e.getErrorCode(),e.getErrorMsg());
    }

    /**
     * 處理空指針的異常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =NullPointerException.class)
    @ResponseBody
    public ResultResponse exceptionHandler(HttpServletRequest req, NullPointerException e){
        logger.error("發(fā)生空指針異常!原因是:",e);
        return ResultResponse.error(ExceptionEnum.BODY_NOT_MATCH);
    }

    /**
     * 處理其他異常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =Exception.class)
    @ResponseBody
    public ResultResponse exceptionHandler(HttpServletRequest req, Exception e){
        logger.error("未知異常母廷!原因是:",e);
        return ResultResponse.error(ExceptionEnum.INTERNAL_SERVER_ERROR);
    }
}

2.6 測(cè)試代碼

@PostMapping("/add")
public boolean add(@RequestBody User user) {
    //如果姓名為空就手動(dòng)拋出一個(gè)自定義的異常轻黑!
    if(user.getName()==null){
        throw  new BizException("-1","用戶姓名不能為空!");
    }
    return true;
}
在這里插入圖片描述
 @PutMapping("/update")
public boolean update(@RequestBody User user) {
    //這里故意造成一個(gè)空指針的異常琴昆,并且不進(jìn)行處理
    String str = null;
    str.equals("111");
    return true;
}
在這里插入圖片描述
 @DeleteMapping("/delete")
public boolean delete(@RequestBody User user)  {
    //這里故意造成一個(gè)異常氓鄙,并且不進(jìn)行處理
    Integer.parseInt("abc123");
    return true;
}
在這里插入圖片描述

如果我們想捕獲這個(gè)類型轉(zhuǎn)換異常,是不是再添加一個(gè)遺產(chǎn)處理方法就可了业舍。


在這里插入圖片描述
/**
* 處理類型轉(zhuǎn)換異常
 * @param req
 * @param e
 * @return
 */
@ExceptionHandler(value = NumberFormatException.class)
@ResponseBody
public ResultResponse exceptionHandler(HttpServletRequest req, NumberFormatException e){
    logger.error("發(fā)生類型轉(zhuǎn)換異常抖拦!原因是:",e);
    return ResultResponse.error(ExceptionEnum.PARAMS_NOT_CONVERT);
}
PARAMS_NOT_CONVERT("4002","類型轉(zhuǎn)換不對(duì)!"),

在這里插入圖片描述

自定義全局異常處理除了可以處理上述的數(shù)據(jù)格式之外,也可以處理頁(yè)面的跳轉(zhuǎn)舷暮,只需在新增的異常方法的返回處理上填寫該跳轉(zhuǎn)的路徑并不使用ResponseBody 注解即可态罪。

總結(jié)

異常處理,能夠減少代碼的重復(fù)度和復(fù)雜度下面,有利于代碼的維護(hù)复颈,并且能夠快速定位到BUG,大大提高我們的開發(fā)效率沥割。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末耗啦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子机杜,更是在濱河造成了極大的恐慌帜讲,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件椒拗,死亡現(xiàn)場(chǎng)離奇詭異似将,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蚀苛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門在验,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人枉阵,你說(shuō)我怎么就攤上這事译红。” “怎么了兴溜?”我有些...
    開封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵侦厚,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我拙徽,道長(zhǎng)刨沦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任膘怕,我火速辦了婚禮想诅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘岛心。我一直安慰自己来破,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開白布忘古。 她就那樣靜靜地躺著徘禁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪髓堪。 梳的紋絲不亂的頭發(fā)上送朱,一...
    開封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音干旁,去河邊找鬼驶沼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛争群,可吹牛的內(nèi)容都是我干的回怜。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼换薄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼玉雾!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起专控,我...
    開封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤抹凳,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后伦腐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赢底,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年柏蘑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了幸冻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡咳焚,死狀恐怖洽损,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情革半,我是刑警寧澤碑定,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布流码,位于F島的核電站,受9級(jí)特大地震影響延刘,放射性物質(zhì)發(fā)生泄漏漫试。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一碘赖、第九天 我趴在偏房一處隱蔽的房頂上張望驾荣。 院中可真熱鬧,春花似錦普泡、人聲如沸播掷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)歧匈。三九已至,卻和暖如春权烧,著一層夾襖步出監(jiān)牢的瞬間眯亦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工般码, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留妻率,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓板祝,卻偏偏與公主長(zhǎng)得像宫静,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子券时,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容