前言
如今web项目的接口大都是 RESTful 的,响应体中包含了一些接口执行的信息,比如返回的数据(data)、响应码(code)、是否成功(success)和响应描述(message)。每个接口都需要封装成这种格式,这样每次都需要留意。
下面来介绍一种方法,是 Spring 的 web 模块提供的功能。
统一响应体
pom依赖了web模块和lombok
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.61</version>
</dependency>
首先创建枚举类ResultMessage,定义一些响应码
public enum ResultMessage {
/** 成功 */
SUCCESS(200, "Success"),
/** 请求错误 */
BAD_REQUEST(400, "Bad request"),
/** 未经授权 */
UNAUTHORIZED(401, "Unauthorized"),
/** 目标不存在 */
NOT_FOUND(404, "Not found"),
/** 服务内部错误 */
SERVER_ERROR(500, "Server Error");
private int code;
private String message;
ResultMessage(int code, String message) {
this.code = code;
this.message = message;
}
public int code() {
return code;
}
public String message() {
return message;
}
}
创建 Result 类,代表接口的响应体
@Getter
public class Result<T> {
/**
* 状态码
*/
private int code = -1;
/**
* 提示信息
*/
private String message;
/**
* 响应数据
*/
private T data;
private Result(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
public static <T> Result<T> data(T data) {
return new Result<>(ResultMessage.SUCCESS.code(), ResultMessage.SUCCESS.message(), data);
}
public static <T> Result<T> err() {
return new Result<>(ResultMessage.SERVER_ERROR.code(), ResultMessage.SERVER_ERROR.message(), null);
}
public static <T> Result<T> err(String message) {
return new Result<>(ResultMessage.SERVER_ERROR.code(), message, null);
}
}
接着创建,HelloController类
@RestController
public class HelloController {
@GetMapping("/hello")
public Result<String> hello() {
return Result.data("hello");
}
}
使用postman访问 http://localhost:8080/hello
{
"code": 200,
"message": "Success",
"data": "hello"
}
创建注解 OriginalBody,代表原始响应头。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OriginalBody {
}
创建 ResultBodyAdvice 类,实现 ResponseBodyAdvice 接口,重写两个方法:
@ControllerAdvice
public class ResultBodyAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
Annotation[] methodAnnotations = methodParameter.getMethodAnnotations();
for (Annotation methodAnnotation : methodAnnotations) {
if (methodAnnotation instanceof OriginalBody) {
return false;
}
}
Annotation[] classAnnotations = methodParameter.getMethod().getDeclaringClass().getAnnotations();
for (Annotation classAnnotation : classAnnotations) {
if (classAnnotation instanceof OriginalBody) {
return false;
}
}
return true;
}
@Override
public Object beforeBodyWrite(Object result, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse response) {
if (result instanceof Result) {
return result;
}
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
String type = mediaType.getType();
if ("text".equals(type)) {
return JSON.toJSONString(Result.data(result), SerializerFeature.PrettyFormat);
}
return Result.data(result);
}
}
在 HelloController 新增两个方法,用来测试
@GetMapping("/hello2")
public String hello2() {
return "hello2";
}
@OriginalBody
@GetMapping("/hello3")
public String hello3() {
return "hello3";
}
使用Postman分别调用 hello2:
{
"code": 200,
"data": "hello2",
"message": "Success"
}
调用 hello3 :
hello3
统一异常响应体
新增一个方法,如果接口出现异常,则响应成了酱紫:
@GetMapping("/hello4")
public String hello4(@RequestParam Integer code) {
if (code != null && code.equals(1)) {
throw new RuntimeException();
}
return "hello4";
}
{
"code": 200,
"message": "Success",
"data": {
"timestamp": "2020-04-10T11:06:45.299+0000",
"status": 500,
"error": "Internal Server Error",
"message": "No message available",
"path": "/hello4"
}
}
这种方法使用 @ExceptionHandler 注解来解决。
创建
@ControllerAdvice
@Slf4j
@ResponseBody
public class ExceptionHandlerAdvice {
@ExceptionHandler(Exception.class)
public Result<Object> handleException(Exception e){
log.error(e.getMessage(), e);
return Result.err();
}
}
请求结果:
{
"code": 500,
"message": "Server Error",
"data": null
}