SpringBoot如何实现统一响应体的详细解决方案?

2026-06-10 12:341阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1717个文字,预计阅读时间需要7分钟。

SpringBoot如何实现统一响应体的详细解决方案?

前言:最近在优化自己之前基于Spring AOP实现的统一响应体的实现方案。

什么是统一响应体呢?在目前的前后端分离架构下,后端主要是一组RESTful API的数据接口。但是HTTP的状态码数量有限,无法完全表达复杂的业务逻辑。

具体来说,我的方案是通过在Spring AOP中拦截所有的Controller方法,统一返回一个包含状态码、消息和数据的JSON对象。这样,无论后端业务逻辑如何变化,前端都能得到一致的响应格式,简化了前端处理逻辑。

前言

最近在优化自己之前基于Spring AOP的统一响应体的实现方案。

什么是统一响应体呢?在目前的前后端分离架构下,后端主要是一个RESTful API的数据接口。

但是HTTP的状态码数量有限,而随着业务的增长,HTTP状态码无法很好地表示业务中遇到的异常情况。

那么可以通过修改响应返回的JSON数据,让其带上一些固有的字段,例如以下这样的

{ "code": 10000, "msg": "success", "data": { "id": 2, "name": "test" } }

其中关键属性的用途如下:

  • code为返回结果的状态码
  • msg为返回结果的消息
  • data为返回的业务数据

这3个属性为固有属性,每次响应结果都会有带有它们。

需求

希望实现一个能够代替基于AOP的实现方案,需要满足以下几点:

  1. 原有的基于AOP的实现方案需要Controller的返回类型为Object,需要新方案不限制返回类型
  2. 原有的基于AOP的实现方案需要通过切面表达式+注解控制切点的Controller(注解的包名修改会导致切面表达式的修改,即需要修改两处地方),需要新方案能够基于注解,而不需要修改切面表达式

方案思路

基于上述的需求,选择使用Spring的Controller增强机制,其中关键的类为以下3个:

SpringBoot如何实现统一响应体的详细解决方案?

  • @ControllerAdvice:类注解,用于指定Controller增强处理器类。
  • ResponseBodyAdvice:接口,实现后beforeBodyWrite()方法后可以对响应的body进行修改,需要结合@ControllerAdvice使用。
  • @ExceptionHandler:方法注解,用于指定异常处理方法,需要结合@ControllerAdvice和@ResponseBody使用。

示例关键代码

本示例使用的Spring Boot版本为2.1.6.RELEASE,同时需要开发工具安装lombok插件

引入依赖

<dependencies> <!--web-starter--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!--test-starter--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>

统一响应体

Controller增强后统一响应体对应的对象

import lombok.AllArgsConstructor; import lombok.Data; import java.io.Serializable; /** * 统一的公共响应体 * @author NULL * @date 2019-07-16 */ @Data @AllArgsConstructor public class ResponseResult implements Serializable { /** * 返回状态码 */ private Integer code; /** * 返回信息 */ private String msg; /** * 数据 */ private Object data; }

统一响应注解

统一响应注解是一个标记是否开启统一响应增强的注解

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 统一响应注解<br/> * 添加注解后,统一响应体才能生效 * @author NULL * @date 2019-07-16 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface BaseResponse { }

状态码枚举

统一响应体中返回的状态码code和状态信息msg对应的枚举类

/** * 返回状态码 * * @author NULL * @date 2019-07-16 */ public enum ResponseCode { /** * 成功返回的状态码 */ SUCCESS(10000, "success"), /** * 资源不存在的状态码 */ RESOURCES_NOT_EXIST(10001, "资源不存在"), /** * 所有无法识别的异常默认的返回状态码 */ SERVICE_ERROR(50000, "服务器异常"); /** * 状态码 */ private int code; /** * 返回信息 */ private String msg; ResponseCode(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; } }

业务异常类

业务异常类是用于识别业务相关的异常,需要注意这个异常类强制需要以ResponseCode作为构造方法入参,这样可以通过捕获异常获得返回的状态码信息

import com.rjh.web.response.ResponseCode; import lombok.Data; import lombok.EqualsAndHashCode; /** * 业务异常类,继承运行时异常,确保事务正常回滚 * * @author NULL * @since 2019-07-16 */ @Data @EqualsAndHashCode(callSuper = false) public class BaseException extends RuntimeException{ private ResponseCode code; public BaseException(ResponseCode code) { this.code = code; } public BaseException(Throwable cause, ResponseCode code) { super(cause); this.code = code; } }

异常处理类

用于处理Controller运行时未捕获的异常的处理类。

import com.rjh.web.exception.BaseException; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; /** * 异常处理器 * * @author NULL * @since 2019-07-16 */ @ControllerAdvice(annotations = BaseResponse.class) @ResponseBody @Slf4j public class ExceptionHandlerAdvice { /** * 处理未捕获的Exception * @param e 异常 * @return 统一响应体 */ @ExceptionHandler(Exception.class) public ResponseResult handleException(Exception e){ log.error(e.getMessage(),e); return new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(),ResponseCode.SERVICE_ERROR.getMsg(),null); } /** * 处理未捕获的RuntimeException * @param e 运行时异常 * @return 统一响应体 */ @ExceptionHandler(RuntimeException.class) public ResponseResult handleRuntimeException(RuntimeException e){ log.error(e.getMessage(),e); return new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(),ResponseCode.SERVICE_ERROR.getMsg(),null); } /** * 处理业务异常BaseException * @param e 业务异常 * @return 统一响应体 */ @ExceptionHandler(BaseException.class) public ResponseResult handleBaseException(BaseException e){ log.error(e.getMessage(),e); ResponseCode code=e.getCode(); return new ResponseResult(code.getCode(),code.getMsg(),null); } }

响应增强类

Conrtoller增强的统一响应体处理类,需要注意异常处理类已经进行了增强,所以需要判断一下返回的对象是否为统一响应体对象。

import lombok.extern.slf4j.Slf4j; import org.springframework.core.MethodParameter; import org.springframework.127.0.0.1:8080/users/0,则返回结果如下(结果经过格式化处理):

{ "code": 10001, "msg": "资源不存在", "data": null }

在浏览器直接访问127.0.0.1:8080/users/1,则返回结果如下(结果经过格式化处理):

{ "code": 50000, "msg": "服务器异常", "data": null }

在浏览器直接访问127.0.0.1:8080/users/2,则返回结果如下(结果经过格式化处理):

{ "code": 10000, "msg": "success", "data": { "id": 2, "name": "test" } }

由运行结果可以得知统一响应增强其实已经生效了,而且能够很好的处理异常。

示例代码地址

下面是这个示例的代码地址,如果觉得不错或者帮助到你,希望大家给个Star:

github.com/spring-based-solutions/spring-web-unified-response-demo

参考资料

docs.spring.io/spring/docs/5.1.8.RELEASE/spring-framework-reference/web.html#mvc-ann-controller-advice
docs.spring.io/spring/docs/5.1.8.RELEASE/spring-framework-reference/web.html#mvc-ann-exceptionhandler

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自由互联。

本文共计1717个文字,预计阅读时间需要7分钟。

SpringBoot如何实现统一响应体的详细解决方案?

前言:最近在优化自己之前基于Spring AOP实现的统一响应体的实现方案。

什么是统一响应体呢?在目前的前后端分离架构下,后端主要是一组RESTful API的数据接口。但是HTTP的状态码数量有限,无法完全表达复杂的业务逻辑。

具体来说,我的方案是通过在Spring AOP中拦截所有的Controller方法,统一返回一个包含状态码、消息和数据的JSON对象。这样,无论后端业务逻辑如何变化,前端都能得到一致的响应格式,简化了前端处理逻辑。

前言

最近在优化自己之前基于Spring AOP的统一响应体的实现方案。

什么是统一响应体呢?在目前的前后端分离架构下,后端主要是一个RESTful API的数据接口。

但是HTTP的状态码数量有限,而随着业务的增长,HTTP状态码无法很好地表示业务中遇到的异常情况。

那么可以通过修改响应返回的JSON数据,让其带上一些固有的字段,例如以下这样的

{ "code": 10000, "msg": "success", "data": { "id": 2, "name": "test" } }

其中关键属性的用途如下:

  • code为返回结果的状态码
  • msg为返回结果的消息
  • data为返回的业务数据

这3个属性为固有属性,每次响应结果都会有带有它们。

需求

希望实现一个能够代替基于AOP的实现方案,需要满足以下几点:

  1. 原有的基于AOP的实现方案需要Controller的返回类型为Object,需要新方案不限制返回类型
  2. 原有的基于AOP的实现方案需要通过切面表达式+注解控制切点的Controller(注解的包名修改会导致切面表达式的修改,即需要修改两处地方),需要新方案能够基于注解,而不需要修改切面表达式

方案思路

基于上述的需求,选择使用Spring的Controller增强机制,其中关键的类为以下3个:

SpringBoot如何实现统一响应体的详细解决方案?

  • @ControllerAdvice:类注解,用于指定Controller增强处理器类。
  • ResponseBodyAdvice:接口,实现后beforeBodyWrite()方法后可以对响应的body进行修改,需要结合@ControllerAdvice使用。
  • @ExceptionHandler:方法注解,用于指定异常处理方法,需要结合@ControllerAdvice和@ResponseBody使用。

示例关键代码

本示例使用的Spring Boot版本为2.1.6.RELEASE,同时需要开发工具安装lombok插件

引入依赖

<dependencies> <!--web-starter--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!--test-starter--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>

统一响应体

Controller增强后统一响应体对应的对象

import lombok.AllArgsConstructor; import lombok.Data; import java.io.Serializable; /** * 统一的公共响应体 * @author NULL * @date 2019-07-16 */ @Data @AllArgsConstructor public class ResponseResult implements Serializable { /** * 返回状态码 */ private Integer code; /** * 返回信息 */ private String msg; /** * 数据 */ private Object data; }

统一响应注解

统一响应注解是一个标记是否开启统一响应增强的注解

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 统一响应注解<br/> * 添加注解后,统一响应体才能生效 * @author NULL * @date 2019-07-16 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface BaseResponse { }

状态码枚举

统一响应体中返回的状态码code和状态信息msg对应的枚举类

/** * 返回状态码 * * @author NULL * @date 2019-07-16 */ public enum ResponseCode { /** * 成功返回的状态码 */ SUCCESS(10000, "success"), /** * 资源不存在的状态码 */ RESOURCES_NOT_EXIST(10001, "资源不存在"), /** * 所有无法识别的异常默认的返回状态码 */ SERVICE_ERROR(50000, "服务器异常"); /** * 状态码 */ private int code; /** * 返回信息 */ private String msg; ResponseCode(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; } }

业务异常类

业务异常类是用于识别业务相关的异常,需要注意这个异常类强制需要以ResponseCode作为构造方法入参,这样可以通过捕获异常获得返回的状态码信息

import com.rjh.web.response.ResponseCode; import lombok.Data; import lombok.EqualsAndHashCode; /** * 业务异常类,继承运行时异常,确保事务正常回滚 * * @author NULL * @since 2019-07-16 */ @Data @EqualsAndHashCode(callSuper = false) public class BaseException extends RuntimeException{ private ResponseCode code; public BaseException(ResponseCode code) { this.code = code; } public BaseException(Throwable cause, ResponseCode code) { super(cause); this.code = code; } }

异常处理类

用于处理Controller运行时未捕获的异常的处理类。

import com.rjh.web.exception.BaseException; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; /** * 异常处理器 * * @author NULL * @since 2019-07-16 */ @ControllerAdvice(annotations = BaseResponse.class) @ResponseBody @Slf4j public class ExceptionHandlerAdvice { /** * 处理未捕获的Exception * @param e 异常 * @return 统一响应体 */ @ExceptionHandler(Exception.class) public ResponseResult handleException(Exception e){ log.error(e.getMessage(),e); return new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(),ResponseCode.SERVICE_ERROR.getMsg(),null); } /** * 处理未捕获的RuntimeException * @param e 运行时异常 * @return 统一响应体 */ @ExceptionHandler(RuntimeException.class) public ResponseResult handleRuntimeException(RuntimeException e){ log.error(e.getMessage(),e); return new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(),ResponseCode.SERVICE_ERROR.getMsg(),null); } /** * 处理业务异常BaseException * @param e 业务异常 * @return 统一响应体 */ @ExceptionHandler(BaseException.class) public ResponseResult handleBaseException(BaseException e){ log.error(e.getMessage(),e); ResponseCode code=e.getCode(); return new ResponseResult(code.getCode(),code.getMsg(),null); } }

响应增强类

Conrtoller增强的统一响应体处理类,需要注意异常处理类已经进行了增强,所以需要判断一下返回的对象是否为统一响应体对象。

import lombok.extern.slf4j.Slf4j; import org.springframework.core.MethodParameter; import org.springframework.127.0.0.1:8080/users/0,则返回结果如下(结果经过格式化处理):

{ "code": 10001, "msg": "资源不存在", "data": null }

在浏览器直接访问127.0.0.1:8080/users/1,则返回结果如下(结果经过格式化处理):

{ "code": 50000, "msg": "服务器异常", "data": null }

在浏览器直接访问127.0.0.1:8080/users/2,则返回结果如下(结果经过格式化处理):

{ "code": 10000, "msg": "success", "data": { "id": 2, "name": "test" } }

由运行结果可以得知统一响应增强其实已经生效了,而且能够很好的处理异常。

示例代码地址

下面是这个示例的代码地址,如果觉得不错或者帮助到你,希望大家给个Star:

github.com/spring-based-solutions/spring-web-unified-response-demo

参考资料

docs.spring.io/spring/docs/5.1.8.RELEASE/spring-framework-reference/web.html#mvc-ann-controller-advice
docs.spring.io/spring/docs/5.1.8.RELEASE/spring-framework-reference/web.html#mvc-ann-exceptionhandler

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自由互联。