Spring Boot中,一致回来前端格局能够进步代码复用性和维护性。本文将介绍如何在Spring Boot项目中封装一致的呼应格局。

呼应格局的设计

在设计呼应格局时,能够参考RESTful API的设计标准,一般一个合理的呼应格局应该包含以下几个字段:

  • code:呼应状况码,用于表明恳求的处理成果。一般情况下,2xx表明成功(个人习惯用0代表成功),4xx表明客户端错误,5xx表明服务端错误。
  • message:呼应音讯,用于描述呼应状况码的详细含义。
  • data:呼应数据,用于寄存恳求处理成功后的数据。假如恳求失利,则该字段能够为空或许不存在。

在详细的完成中,data字段能够是一个对象,也能够是一个集合。别的,为了便利前端的解析,呼应格局一般选用JSON格局。

基于上述标准,咱们能够界说一个通用的呼应实体类:

@Data
public class DataResult <T>{
  @ApiModelProperty(value = "呼应状况码 code=0代表成功,其它失利")
  private int code;
  @ApiModelProperty(value = "呼应的事务数据")
  private T data;
  @ApiModelProperty(value = "呼应状提示语")
  private String message;
​
  /**
   * 呼应成功的办法
   * @param data
   * @param <T>
   * @return
   */
  public static <T> DataResult<T> success(T data){
    DataResult<T> result=new DataResult<>();
    result.data=data;
    result.code= ResponseCode.SUCCESS.getCode();
    result.message=ResponseCode.SUCCESS.getMessage();
    return result;
   }
​
  /**
   * 呼应失利东西办法
   * @param code
   * @param message
   * @param <T>
   * @return
   */
  public static <T> DataResult<T> fail(int code ,String message){
    DataResult<T> result=new DataResult<>();
    result.code= code;
    result.message=message;
    return result;
   }
}

界说一个一致呼应状况码枚举:

public enum ResponseCode {
  SUCCESS(0,"呼应成功"),
  //后端服务反常以500最初
  SYSTEM_ERROR(500000,"服务反常,请稍后再试"),
  OPERATION_ERROR(500001,"操作失利,请稍后再试"),
  //后端服务反常以400最初
  DATA_PARAM_ERROR(400000,"传入参数错误"),
  ACCOUNT_ALREADY_EXISTS(400001,"账号已存在,请登录"),
  ACCOUNT_NOT_FOUND(400002,"账号不存在"),
  ACCOUNT_LOCK(400003,"账号已锁定,请联络管理员解锁"),
  ACCOUNT_ERROR(400004,"账户密码不匹配"),
  TOKEN_ERROR(401000,"token 已失效,请重新登录")
   ;
  private final int code;
  private final String message;
​
  ResponseCode(int code, String message) {
    this.code = code;
    this.message = message;
   }
​
  public int getCode() {
    return code;
   }
​
  public String getMessage() {
    return message;
   }
}

一致呼应格局的封装

咱们能够使用Spring供给的ResponseBodyAdvice来完成一致呼应格局的封装。详细来说,ResponseBodyAdvice是一个接口,能够在Controller办法履行完成后,对回来的成果进行修改和增强。

首先,咱们需求界说一个通用的呼应格局类:

@RestControllerAdvice
@Slf4j
public class RestResponseBodyAdviceHandler implements ResponseBodyAdvice<Object> {
  @Resource
  private ObjectMapper objectMapper;
  private final String stringConverter="org.springframework.http.converter.StringHttpMessageConverter";
  /**
   * true:代表支撑咱们在呼应前端的时分做一些处理(调用beforeBodyWrite办法)
   * false:不支撑
   * @param returnType
   * @param converterType
   * @return
   */
  @Override
  public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    log.info("supports:{}",returnType.getDeclaringClass().getName());
    /**
     * 排除swagger-ui恳求回来数据增强
     */
    return !returnType.getDeclaringClass().getName().contains("springfox");
   }
​
  @SneakyThrows
  @Override
  public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
    /**
     * 当接口回来到类型音讯转化器是StringHttpMessageConverter
     * 咱们才需求把它转化成string
     */
    if(stringConverter.equalsIgnoreCase(selectedConverterType.getName())){
      HttpHeaders headers= response.getHeaders();
      headers.setContentType(MediaType.APPLICATION_JSON);
      return objectMapper.writeValueAsString(DataResult.success(body));
     }
    /**
     * 
     * 假如呼应成果现已是DataResult类型,则直接回来
     */
    if(body instanceof DataResult){
      return body;
     }
    return DataResult.success(body);
   }
}

在上述代码中,咱们完成了ResponseBodyAdvice接口,偏重写了其间的supportsbeforeBodyWrite办法。其间,supports办法用于判断当时回来类型是否需求进行处理,beforeBodyWrite办法则用于对回来成果进行封装

在Spring Boot中,StringHttpMessageConverter音讯转化器现已默许添加到了音讯转化器列表中,它会将恳求和呼应中的字符串类型数据转化成Java中的String类型,当接口回来类型是字符串类型,则StringHttpMessageConverter会处理该恳求,并将恳求中的数据转化成Java中的String类型,假如咱们直接回来到是DataResult 类型就会出现类型转化反常:xxxxx.DataResult cannot be cast to java.lang.String

SpringBoot 项目中统一返回前端格式老手是这样封装的

当接口回来类型为DataResult时现已是 DataResult 类型了所以咱们不需求处理,反之需求使用 DataResult 包装处理一致回来DataResult类型。

使用ResponseBodyAdvice的好处是,它能够更加精细地控制呼应成果的格局,能够对所有的回来值进行一致的封装,也能够针对某些回来值进行特别处理,灵活性更高。

测验

@RestController
@Api(tags = "测验模块")
public class TestController {
  @GetMapping("/hello")
  @ApiOperation(value = "经典hello接口")
  public String hello(){
    return "Hello World";
   }
}

成果:

{
 "code": 0,
 "data": "Hello World",
 "message": "呼应成功"
}