1. 程式人生 > >Spring Boot 統一返回資料結構以及全域性異常處理

Spring Boot 統一返回資料結構以及全域性異常處理

前言

看了廖師兄的視訊後,結合自己以前的程式設計經驗總結下 :

在 web 開發過程中, 後端要統一返回的資料結構,便於前端處理。例如每個請求,我們都需要知道 :

  1. code : 伺服器返回的狀態碼(主要給程式設計師看)。例如 : 200 : 請求成功。 500 : 伺服器內部錯誤。
  2. status : 0 或者 1 (用於給前端判斷) 。 1 : 處理成功。 0 : 處理失敗 。這裡要和 code 做區分。status 是邏輯上的錯誤。例如使用者想要刪除某一個帖子,使用者手滑,連續發了兩個請求, 第一個請求成功, 伺服器返回 code: 200 , status : 1 。第二個請求成功,但是帖子已經被刪除了。因此返回 code : 200 , status : 0 ,msg: “帖子不存在”
  3. msg : 伺服器的錯誤資訊 ,主要返回給使用者看。
  4. 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 為 前端和後端約定好的返回碼 。