spring mvc统一API返回格式

对于前后端分离的项目,采用统一的返回格式可以有效减少前后端开发人员的交流成本,对于Spring MVC可以利用切面无侵入地、优雅地实现这一点。

Spring MVC提供了AbstractMappingJacksonResponseBodyAdvice抽象类对返回的JSON做二次处理

首先定义返回结构

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
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResponse {

private Integer status;
@JsonInclude(JsonInclude.Include.NON_NULL)
private String error;
private String message;
@JsonInclude(JsonInclude.Include.NON_NULL)
private Object data;

public static CommonResponse success(Integer status, Object data) {
return new CommonResponse(status, null, "success", data);
}

public static CommonResponse success(Integer status, String message, Object data) {
return new CommonResponse(status, null, message, data);
}

public static CommonResponse fail(Integer status, String error, String message, Object data) {
return new CommonResponse(status, error, message, data);
}

}

编写切面继承AbstractMappingJacksonResponseBodyAdvice并注入容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RestControllerAdvice
public class GlobalResponseAdvice extends AbstractMappingJacksonResponseBodyAdvice {

@Override
protected void beforeBodyWriteInternal(MappingJacksonValue bodyContainer, MediaType contentType, MethodParameter returnType, ServerHttpRequest request, ServerHttpResponse response) {
HttpStatus code = HttpStatus.OK; //默认状态码为200
final ResponseStatus responseStatus = returnType.getMethodAnnotation(ResponseStatus.class); //这里反射获取Controller方法的ResponseStatus注解,如果存在注解,则使用该注解的值作为状态码。作为Restful API 201状态码也是很常用的
if (responseStatus != null) {
code = responseStatus.code();
}

Object body = bodyContainer.getValue();
if (!CommonResponse.class.isAssignableFrom(body.getClass())) { //对于已经包装为CommonResponse的结果不处理,以防二次包装
bodyContainer.setValue(CommonResponse.success(code.value(), body));
}
}

}

效果

1
2
3
4
5
6
7
8
9
{
"status": 200,
"message": "success",
"data": {
"id": 1,
"username": "user1",
"role": "ADMIN"
}
}
作者

udp_bbr

发布于

2021-10-31

更新于

2022-09-08

许可协议