[SpringBoot]使用ResponseBodyAdvice统一包装RestController返回结果
仓库
仓库案例:springboot_apiresult
为什么要统一格式
在我们使用SpringBoot编写接口的时候,最好是返回一个统一格式的JSON,该格式包含错误码,附带信息,以及携带的数据。这样前端在解析的时候就能统一解析,同时携带错误码可以更加容易的排查错误。
定义包装类ApiResult
1 | package com.karoy.springboot.common; |
定义错误码类ErrorCode
1 | package com.karoy.springboot.common; |
定义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
60package 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;
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( { 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;
}
}
结果对别
接口方法定义
未处理前返回结果
处理后返回结果
结束
这个时候在接口方法直接返回对象,你会发现该对象已经自动包装成ApiResult了。