SpringBoot項目優雅的全局異常處理方式(全網最新)

前言

在日常項目開發中,異常是常見的,但是如何更高效的處理好異常信息,讓我們能快速定位到BUG,是很重要的,不僅能夠提高我們的開發效率,還能讓你代碼看上去更舒服,SpringBoot的項目已經對有一定的異常處理瞭,但是對於我們開發者而言可能就不太合適瞭,因此我們需要對這些異常進行統一的捕獲並處理。

一、全局異常處理方式一

SpringBoot中,@ControllerAdvice 即可開啟全局異常處理,使用該註解表示開啟瞭全局異常的捕獲,我們隻需在自定義一個方法使用@ExceptionHandler註解然後定義捕獲異常的類型即可對這些捕獲的異常進行統一的處理。

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 "全局異常捕獲,錯誤原因>>>"+e.getMessage();
    }
}

1.2 手動拋出異常

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

1.3 測試打印

在這裡插入圖片描述

在這裡插入圖片描述

很顯然這樣的用戶體驗效果是極差的,雖然這種能夠讓我們知道異常的原因,但是在很多的情況下來說,可能還是不夠人性化,不符合我們的要求。

二、全局異常處理方式二

2.1 定義基礎接口類

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

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

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

2.2 定義枚舉類

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

    /**
     * 錯誤碼
     */
    private final String resultCode;

    /**
     * 錯誤描述
     */
    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;

    /**
     * 錯誤碼
     */
    protected String errorCode;
    /**
     * 錯誤信息
     */
    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 自定義數據傳輸

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

    /**
     * 響應消息
     */
    private String message;

    /**
     * 響應結果
     */
    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);

    /**
     * 處理自定義的業務異常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = BizException.class)
    @ResponseBody
    public ResultResponse bizExceptionHandler(HttpServletRequest req, BizException e){
        logger.error("發生業務異常!原因是:{}",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("發生空指針異常!原因是:",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 測試代碼

@PostMapping("/add")
public boolean add(@RequestBody User user) {
    //如果姓名為空就手動拋出一個自定義的異常!
    if(user.getName()==null){
        throw  new BizException("-1","用戶姓名不能為空!");
    }
    return true;
}

在這裡插入圖片描述

 @PutMapping("/update")
public boolean update(@RequestBody User user) {
    //這裡故意造成一個空指針的異常,並且不進行處理
    String str = null;
    str.equals("111");
    return true;
}

在這裡插入圖片描述

 @DeleteMapping("/delete")
public boolean delete(@RequestBody User user)  {
    //這裡故意造成一個異常,並且不進行處理
    Integer.parseInt("abc123");
    return true;
}

在這裡插入圖片描述

如果我們想捕獲這個類型轉換異常,是不是再添加一個遺產處理方法就可瞭。

在這裡插入圖片描述

/**
* 處理類型轉換異常
 * @param req
 * @param e
 * @return
 */
@ExceptionHandler(value = NumberFormatException.class)
@ResponseBody
public ResultResponse exceptionHandler(HttpServletRequest req, NumberFormatException e){
    logger.error("發生類型轉換異常!原因是:",e);
    return ResultResponse.error(ExceptionEnum.PARAMS_NOT_CONVERT);
}
PARAMS_NOT_CONVERT("4002","類型轉換不對!"),

在這裡插入圖片描述

自定義全局異常處理除瞭可以處理上述的數據格式之外,也可以處理頁面的跳轉,隻需在新增的異常方法的返回處理上填寫該跳轉的路徑並不使用ResponseBody 註解即可。

總結

異常處理,能夠減少代碼的重復度和復雜度,有利於代碼的維護,並且能夠快速定位到BUG,大大提高我們的開發效率。

到此這篇關於SpringBoot項目優雅的全局異常處理方式(全網最新)的文章就介紹到這瞭,更多相關SpringBoot 全局異常處理 內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!