[SpringBoot]使用ResponseBodyAdvice统一包装RestController返回结果

仓库

仓库案例:springboot_apiresult

为什么要统一格式

在我们使用SpringBoot编写接口的时候,最好是返回一个统一格式的JSON,该格式包含错误码,附带信息,以及携带的数据。这样前端在解析的时候就能统一解析,同时携带错误码可以更加容易的排查错误。

定义包装类ApiResult

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.karoy.springboot.common;

public class ApiResult {
/**
* @description 响应码
*/
private int code;

/**
* @description 响应消息
*/
private String message;

/**
* @description 数据
*/
private Object data;

public final int getCode() {
return this.code;
}

public final void setCode(int code) {
this.code = code;
}

public final String getMessage() {
return this.message;
}

public final void setMessage( String message) {
this.message = message;
}

public final Object getData() {
return this.data;
}

public final void setData(Object data) {
this.data = data;
}

public ApiResult(int code, String message, Object data) {
super();
this.code = code;
this.message = message;
this.data = data;
}
}

定义错误码类ErrorCode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.karoy.springboot.common;

public enum ErrorCode {
SUCCESS(200,"成功"),
NO_PERMISSION(211,"权限不足"),
SERVER_ERROR(10000,"服务器异常"),
AUTH_ERROR(10001,"认证失败"),
PARAMS_ERROR(10002,"参数错误"),
JSON_PARSE_ERROR(10003,"Json解析错误"),
ILLEAGAL_STRING(15001,"非法字符串"),
UNKNOW_ERROR(16000,"未知错误");


private int code;
private String msg;

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

public int getCode() {
return code;
}

public String getMsg() {
return msg;
}
}

定义ApiResultHandler

当接口方法返回数据后,在序列化器对该结果进行序列化之前,我们可以使用ResponseBodyAdvice来对这个结果进行操作包装,然后再将包装后的结果返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.karoy.springboot.handler;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.karoy.springboot.common.ApiResult;
import com.karoy.springboot.common.ErrorCode;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.reflect.AnnotatedElement;
import java.util.Arrays;

@ControllerAdvice(annotations = RestController.class)
public class ApiResultHandler implements ResponseBodyAdvice<Object> {
private ThreadLocal<ObjectMapper> mapperThreadLocal = ThreadLocal.withInitial(ObjectMapper::new);

private static final Class[] annos = {
RequestMapping.class,
GetMapping.class,
PostMapping.class,
DeleteMapping.class,
PutMapping.class
};

public boolean supports(MethodParameter returnType, Class converterType) {
AnnotatedElement element = returnType.getAnnotatedElement();
return Arrays.stream(annos).anyMatch(anno -> anno.isAnnotation() && element.isAnnotationPresent(anno));
}

public Object beforeBodyWrite(@Nullable Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
Object out;
ObjectMapper mapper = mapperThreadLocal.get();

response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
if(body instanceof ApiResult){
out = body;
}
else if (body instanceof ErrorCode){
ErrorCode errorCode = (ErrorCode) body;
out = new ApiResult(errorCode.getCode(),errorCode.getMsg(),"");
}
else if (body instanceof String){
ApiResult result = new ApiResult(200,"",body);
try {
out = mapper.writeValueAsString(result);
} catch (JsonProcessingException e) {
out = new ApiResult(ErrorCode.JSON_PARSE_ERROR.getCode(),e.getMessage(),"");
}
}
else{
out = new ApiResult(200,"",body);
}
return out;
}
}

结果对别

接口方法定义
图片2

未处理前返回结果

图片1

处理后返回结果

图片3

结束

这个时候在接口方法直接返回对象,你会发现该对象已经自动包装成ApiResult了。