SpringBoot整合SpringMVC之全局異常處理

這個例子將模仿拋出各種exception,幷包裝在CommonResult中進行統一的返回


我們先來給出項目中的錯誤碼的枚舉類,這裏挖坑,後面填

//枚舉項目中的錯誤碼
public enum ServiceExceptionEnum {

//錯誤碼設計的規則
    /**
     * 服務異常
     *
     * 參考 https://www.kancloud.cn/onebase/ob/484204 文章
     *
     * 一共 10 位,分成四段
     *
     * 第一段,1 位,類型
     *      1 - 業務級別異常
     *      2 - 系統級別異常
     * 第二段,3 位,系統類型
     *      001 - 用戶系統
     *      002 - 商品系統
     *      003 - 訂單系統
     *      004 - 支付系統
     *      005 - 優惠劵系統
     *      ... - ...
     * 第三段,3 位,模塊
     *      不限制規則。
     *      一般建議,每個系統裏面,可能有多個模塊,可以再去做分段。以用戶系統爲例子:
     *          001 - OAuth2 模塊
     *          002 - User 模塊
     *          003 - MobileCode 模塊
     * 第四段,3 位,錯誤碼
     *       不限制規則。
     *       一般建議,每個模塊自增。
     */

    //===========系統級別============
    SUCCESS(0, "成功"),
    SYS_ERROR(2001001000,"服務端發生異常"),
    MISSING_REQUEST_PARAM_ERROR(2001001001,"參數缺失"),

    //===========用戶級別============
    USER_NOT_FOUND(1001002000,"用戶不存在"),

    //===========訂單級別============

    //===========訂單級別============
    ;

    /**
     * 錯誤碼
     */
    private int code;

    /**
     * 錯誤提示
     */
    private String message;

    ServiceExceptionEnum(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

這裏的返回錯誤的返回格式也基本是錯誤碼code+錯誤提示message,這裏的錯誤碼設計的原則卸載了註釋裏面


下面引入與Service邏輯異常有關的錯誤,這裏選擇的方式還是,封裝通用的返回類

//service中的異常
public final class ServiceException extends RuntimeException{

    /**
     * 錯誤碼
     */
    private final Integer code;

    public ServiceException(ServiceExceptionEnum serviceExceptionEnum) {
        //使用父類的message字段
        super(serviceExceptionEnum.getMessage());
        //設置錯誤碼
        this.code = serviceExceptionEnum.getCode();
    }

    public Integer getCode() {
        return code;
    }
}

這裏後續需要補充各種常見異常類這個坑。

這裏的意思呢,顯然異常類中是有一個message的信息的,然後加上我們自定義的錯誤碼,這裏的錯誤碼呢,會引用我們定義的枚舉類型中的錯誤碼,說實話,寫到這裏,我覺得枚舉類好像也挺好理解的了,就是封裝一連串的final對象,然後就那幾個給定的狀態,比起普通類來說,多了一個枚舉定義的過程。


下一步需要定義一個統一返回的處理器

@ControllerAdvice(basePackages = "com.zzaxg.springboot.controller")
public class GlobalExceptionHandler {

    private Logger logger = LoggerFactory.getLogger(getClass());

    //使用該異常的code+message屬性,構建CommonResult對象來返回

    /**
     * 處理ServiceException異常
     *
     * @param request
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = ServiceException.class)
    public CommonResult serviceExceptionHandler(HttpServletRequest request, ServiceException ex) {
        logger.debug("[serviceException]", ex);
        //包裝CommonResult結果
        return CommonResult.error(ex.getCode(), ex.getMessage());
    }

    /**
     * 處理 MissingServletRequestParameterException 異常
     *
     * SpringMVC參數不正確
     */
    @ResponseBody
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public CommonResult MissingServletRequestParameterException(HttpServletRequest request, MissingServletRequestParameterException ex) {
        logger.debug("[missingServletRequestParameterException]", ex);
        //包裝CommonResult結果
        return CommonResult.error(ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getCode(), ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getMessage());
    }

    //兜底的異常處理

    /**
     * 處理其他 Exception 異常
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public CommonResult exceptionHandler(HttpServletRequest request, Exception e) {
        //記錄異常日誌
        logger.debug("[exceptionHandler]", e);
        //包裝CommonResult結果
        return CommonResult.error(ServiceExceptionEnum.SYS_ERROR.getCode(), ServiceExceptionEnum.SYS_ERROR.getMessage());
    }

}

同樣是定義了可一個切面,但這裏不需要攔截接口返回結果,所以不需要定義ResponseBodyHandler接口

通過@ExceptionHandler註解定義每個方法對應處理的異常,@ResponseBody註解呢,標記直接使用返回結果作爲API的響應

這裏的logger.debug呢,打印了錯誤日誌


下面寫一個controller進行錯誤的throw

/**
     * 測試拋出NullPointerException異常
     *
     * @return
     */
    @GetMapping("/exception-01")
    public UserVO exception01() {
        throw new NullPointerException("週週不在呢");
    }

    /**
     * 測試拋出ServiceException異常
     *
     */
    @GetMapping("/exception-02")
    public UserVO exception02() {
        throw new ServiceException(ServiceExceptionEnum.USER_NOT_FOUND);
    }

返回的結果呢,分別是

{
    "code": 2001001000,
    "message": "服務端發生異常",
    "data": null
}
{
    "code": 1001002000,
    "message": "用戶不存在",
    "data": null
}

原文參考芋道源碼

謝謝觀看

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章