對於前後端分離項目,前端按照約定的URL路徑請求數據,後端根據前端傳過來的參數,處理業務,並返回結果。下面來介紹下,後端應該如何把數據返回給前端。
返回的數據格式
前後端數據傳輸一般用json格式,如下
{
//狀態碼
code : string,
// 信息描述
message : string,
// 返回數據
data : object
}
code狀態碼,對照http的狀態碼,我們設計自己的狀態碼
分類 | 分類描述 |
---|---|
1* | 信息,服務器收到請求,需要請求者繼續執行操作 |
2* | 成功,操作被成功接收並處理 |
3* | 重定向,需要進一步的操作以完成請求 |
4* | 客戶端錯誤,請求包含語法錯誤或無法完成請求 |
5* | 服務器錯誤,服務器在處理請求的過程中發生了錯誤 |
我們用四位數作爲我們的狀態碼
區間 | 分類描述 |
---|---|
1000 - 1999 | 信息,服務器收到請求,需要請求者繼續執行操作 |
2000 - 2999 | 成功,操作被成功接收並處理 |
3000 - 3999 | 重定向,需要進一步的操作以完成請求 |
4000 - 4999 | 客戶端錯誤,請求包含語法錯誤或無法完成請求 |
5000 - 5999 | 服務器錯誤,服務器在處理請求的過程中發生了錯誤 |
代碼實現
返回體
/**
* 通用的api返回格式
*
* @param <T>
*/
@Data
@AllArgsConstructor
public class ResponseObject<T> {
private String code;
private String message;
private T data;
public static <T> ResponseObject<T> success(T data) {
return new ResponseObject<T>("2000", "success", data);
}
}
Controller
用Controller層來控制返回的數據格式,一般在項目中,還會有sevice層來做業務處理。
@RestController
@RequestMapping("/simple")
public class SimpleApiController {
@RequestMapping("/article")
public Article article() {
return new Article("內容", "標題", "作者");
}
}
下面來改造一下返回的數據格式
@RestController
@RequestMapping("/simple")
public class SimpleApiController {
@RequestMapping("/article")
public ResponseObject<Article> article() {
return ResponseObject.success(new Article("內容", "標題", "作者"));
}
}
用ResponseObject對Article包裝賦值,然後進行返回。但是每次都要這樣寫,沒有第一種來得直接
優雅優化
優化思路
-
定義一個註解@ResponseResult,表示這個接口返回的值需要包裝一下
-
實現接口ResponseBodyAdvice和@ControllerAdvice,判斷方法或Controller是否有@ResponseResult註解,有就把Controller接口的返回值進行包裝。
具體實現
自定義註解ResponseResult
/**
* 放在需要被包裝返回值的Controller或方法上
*/
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ResponseResult {
}
對含有註解ResponseResult的類或方法的返回值進行包裝
/**
* 通用的返回體處理
*/
@ControllerAdvice
public class ResponseResultAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
// 當類或方法上含有ResponseResult註解時
return returnType.getDeclaringClass().isAnnotationPresent(ResponseResult.class) || returnType.hasMethodAnnotation(ResponseResult.class);
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
// 包裝返回值
return ResponseObject.success(body);
}
}
添加通用的錯誤處理
/**
* 通用的錯誤處理
*/
@RestControllerAdvice
public class ErrorControllerAdvice {
@ExceptionHandler(Throwable.class)
public ResponseObject<String> error() {
return new ResponseObject<>("5000", "服務器錯誤", null);
}
}
改寫之前的controller
@RestController
@ResponseResult
@RequestMapping("/grace")
public class GraceApiController {
@RequestMapping("/article")
public Article article() {
return new Article("內容", "標題", "作者");
}
@RequestMapping("/error")
public Article error() {
int a = 1 / 0;
return new Article("內容", "標題", "作者");
}
}
到此就可以了
源碼地址:[email protected]:liuyu_cupid/zeus.git