Spring Boot @RestControllerAdvice 統一異常處理

在做前后端分離的項目時,后端通常都會拆分成多個獨立的微服務,這時候就會涉及每個服務返回給前端的數據格式問題了。下面就來實現一個比較常用的數據格式,統一所有服務的返回值格式。
一般返回的數據格式會包括4個部分,第一部分: 請求處理是否成功,第二部分:服務處理結果編碼,第三部分:編碼對應的文本信息,第四部分:返回值。如下所示:

{
    "result": true,
    "code": 1000,
    "message": "SUCCESS",
    "data": {
        "lantian": 17,
        "qingfen": 16,
        "baiyun": 18
    }
}

對于異常處理情況,我們也需要統一成上面的格式。如果我們在controller中通過try catch來處理異常的話,會出現一個問題就是每個函數里都加一個Try catch,代碼會變的很亂。下面我們就通過spring boot的注解來省略掉controller中的try-catch 幫助我們來封裝異常信息并返回給前端,這樣用戶也不會得到一些奇奇怪怪的錯誤提示。

{
    "result": false,
    "code": 3000,
    "message": "THIS IS AN UNKNOW EXCEPTION",
    "data": null
}

1:定義返回值結構信息(get, set函數省略)

public class CallResultMsg<T> {
    private boolean result;
    private int code;
    private String message;
    private T data;
}

2:定義返回值和對應code的信息(get, set函數省略)

public enum CodeAndMsg {
    SUCCESS(1000, "SUCCESS"),
    METHODFAIL(2000, "ENCOUNTER AN ERROR WHEN EXECUTE METHOD"),
    UNKNOWEXCEPTION(3000, "THIS IS AN UNKNOW EXCEPTION");

    private int code;
    private String msg;

    CodeAndMsg(int code, String msg){
        this.code = code;
        this.msg = msg;
    }
}

3:自定義異常

對于一些特別的異常,我們可以自定義Exception和Error Code,這里自定義一個異常(需要繼承RuntimeException)

public class UserDefinedException extends RuntimeException {
    private CodeAndMsg exception;

    public UserDefinedException(CodeAndMsg exception){
        this.exception = exception;
    }

    public CodeAndMsg getException() {
        return exception;
    }

    public void setException(CodeAndMsg exception) {
        this.exception = exception;
    }
}

4:RestControllerAdvice來捕獲全局異常,

@RestControllerAdvice都是對Controller進行增強的,可以全局捕獲spring mvc拋的異常。
@ExceptionHandler(value = Exception.class)
ExceptionHandler的作用是用來捕獲指定的異常。

@RestControllerAdvice(annotations = RestController.class)
public class UniformReponseHandler<T> {

    @ResponseStatus(HttpStatus.OK)
    public CallResultMsg sendSuccessResponse(){
        return new CallResultMsg(true, CodeAndMsg.SUCCESS, null);
    }

    @ResponseStatus(HttpStatus.OK)
    public CallResultMsg sendSuccessResponse(T data) {
        return new CallResultMsg(true, CodeAndMsg.SUCCESS, data);
    }

    @ExceptionHandler(UserDefinedException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public CallResultMsg sendErrorResponse_UserDefined(Exception exception){
        return new CallResultMsg(false, ((UserDefinedException)exception).getException(), null);
    }

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public CallResultMsg sendErrorResponse_System(Exception exception){
        if (exception instanceof UserDefinedException) {
            return this.sendErrorResponse_UserDefined(exception);
        }

        return new CallResultMsg(false, CodeAndMsg.UNKNOWEXCEPTION, null);
    }
}

通過上面的一波操作,我們的controller中就不需要再去寫大量的try-catch了,RestControllerAdvice會自動幫助catch,并匹配相應的ExceptionHandler,然后重新封裝異常信息,返回值,統一格式返回給前端。
\color{ red }{ 當然也可以單獨寫成一個jar包,供其他微服務的使用。 }

5:ControllerAdvice 和 RestControllerAdvice的區別

@ControllerAdvice 和 @RestControllerAdvice都是對Controller進行增強的,可以全局捕獲spring mvc拋的異常。
RestControllerAdvice = ControllerAdvice + ResponseBody
6:測試統一異常捕獲功能

@GetMapping("/doTestObject")
public CallResultMsg testObjectReturn(){
    Map<String, Integer> map = new HashMap();
    map.put("qingfen", 16);
    map.put("lantian", 17);
    map.put("baiyun", 18);
    return new UniformReponseHandler<Map>().sendSuccessResponse(map);
}


@GetMapping("/doTestException/{x}")
public int testExceptionResturn(@PathVariable int x){
    if (0 < x && x < 10){
        throw new UserDefinedException(CodeAndMsg.METHODFAIL);
    } else {
        return  1/0;
    }
}

返回結果:

{
    "result": true,
    "code": 1000,
    "message": "SUCCESS",
    "data": {
        "lantian": 17,
        "qingfen": 16,
        "baiyun": 18
    }
}
{
    "result": false,
    "code": 2000,
    "message": "ENCOUNTER AN ERROR WHEN EXECUTE METHOD ",
    "data": null
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容