Spring Boot 統一返回資料結構以及全域性異常處理
阿新 • • 發佈:2018-12-16
前言
看了廖師兄的視訊後,結合自己以前的程式設計經驗總結下 :
在 web 開發過程中, 後端要統一返回的資料結構,便於前端處理。例如每個請求,我們都需要知道 :
- code : 伺服器返回的狀態碼(主要給程式設計師看)。例如 : 200 : 請求成功。 500 : 伺服器內部錯誤。
- status : 0 或者 1 (用於給前端判斷) 。 1 : 處理成功。 0 : 處理失敗 。這裡要和 code 做區分。status 是邏輯上的錯誤。例如使用者想要刪除某一個帖子,使用者手滑,連續發了兩個請求, 第一個請求成功, 伺服器返回 code: 200 , status : 1 。第二個請求成功,但是帖子已經被刪除了。因此返回 code : 200 , status : 0 ,msg: “帖子不存在”
- msg : 伺服器的錯誤資訊 ,主要返回給使用者看。
- data : 伺服器返回的資料。
返回的資料格式如下 :
這樣封裝的對前端有很多好處,前端可以直接判斷,比如 :
if(status == 1(
...//直接拿 data 裡面的資料處理。
)else {
// 直接對話方塊或者 Toast 顯示 msg 給使用者,客戶端不需要再做邏輯判斷。
}
code: 用於前後端撕逼。 例如使用者登入伺服器返回以下資料 :
客戶端只需要判斷, status 為 0 , 然後直接給使用者顯示 msg 即可。 code : 103 為 前端和後端約定好的錯誤碼。 例如 : 103 表示使用者賬號已被封號之類…
程式碼片段
例如介面定義如下 :
@GetMapping(path = "/user/findAll")
public BaseResult<List<User>> findAllUsers() {
List<User> users = userDao.findAll();
return ResultUtil.success(users);
}
BaseResult :
public class BaseResult<T> { private Integer code; private Integer status; private String msg; private T data; public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public T getData() { return data; } public void setData(T data) { this.data = data; } }
ResultUtil :
public class ResultUtil {
public static <T> BaseResult<T> success(T data) {
return commonResult(1, 200, "請求成功", data);
}
public static <T> BaseResult<T> error(String errorMsg) {
return error(200, errorMsg);
}
public static <T> BaseResult<T> error(Integer code, String errorMsg) {
return commonResult(0, code, errorMsg, null);
}
private static <T> BaseResult<T> commonResult(Integer status, Integer code, String errMsg, T data) {
BaseResult<T> result = new BaseResult<>();
result.setStatus(status);
result.setCode(code);
result.setMsg(errMsg);
result.setData(data);
return result;
}
}
統一的異常處理
Spring Boot 在有異常發生時,預設返回的 Json 資料結構如下 : (用 Postman 測試介面)
{
"timestamp": "2018-10-20T02:39:20.506+0000",
"status": 500,
"error": "Internal Server Error",
"message": "No message available",
"path": "/user/findAll"
}
很明顯上面 Json 返回的欄位不是我們想要的型別。 我們可以處理下。
新建一個 BaseException : 這個異常為服務端主動丟擲 , 例如使用者沒有登入,輸入密碼錯誤直接丟擲該異常即可…
public class BaseException extends RuntimeException {
// 錯誤資訊
private String errorMsg;
// 伺服器狀態碼
private Integer code;
public BaseException(String errorMsg) {
super(errorMsg);
this.errorMsg = errorMsg;
}
public BaseException(Integer code, String errorMsg) {
super(errorMsg);
this.errorMsg = errorMsg;
this.code = code;
}
public String getErrorMsg() {
return errorMsg;
}
public Integer getCode() {
return code;
}
}
全域性捕獲異常 :
@ControllerAdvice
public class GlobalExceptionHandle {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public <T> BaseResult<T> handle(Exception e) {
if (e instanceof BaseException) {
Integer code = 104;
BaseException exception = (BaseException) e;
if (exception.getCode() != 0) {
code = exception.getCode();
}
return ResultUtil.error(code, e.getMessage());
}
return ResultUtil.error(500, e.getMessage() == null ? "伺服器內部錯誤" : e.getMessage());
}
}
我這裡的 104 為 前端和後端約定好的返回碼 。