我们知道在开发,规范化的开发会节省很多时间,无论是代码规范还是接口规范,如果你们的开发模式是前后端分离的,那你要和前端开发工程师进行对接,不可能因为每个人的代码风格不统一来进行更改,统一的规范会让我们在开发过程事半功倍,下面就看看如何统一处理响应体。
一、定义响应实体类
定义了响应的实体类,code 代表响应状态码,msg代表响应信息,data 代表响应的具体数据 ,这里使用了泛型,为了可以更好的兼容不同类型的返回数据,在做使用swagger作为api工具的是唱吧,使用泛型可以很好的处理接口文档。
package com.dongl.utils.response;
import lombok.Data;
/**
* @author D-L
* @Version 1.0
* @Description 响应体实体类
* @Date 2020/8/26
*/
@Data
public class ResultVO<T> {
/**
* 状态码,比如200代表响应成功
*/
private int code;
/**
* 响应信息,用来说明响应情况
*/
private String msg;
/**
* 响应的具体数据
*/
private T data;
public ResultVO(T data) {
this(ResultCode.SUCCESS, data);
}
public ResultVO(ResultCode resultCode, T data) {
this.code = resultCode.getCode();
this.msg = resultCode.getMsg();
this.data = data;
}
}
二、定义响应状态码枚举类(统一响应状态)
这个响应状态码可以自己根据具体的业务自行定义:
package com.dongl.utils.response;
import lombok.Getter;
/**
* @author D-L
* @Version 1.0
* @Description 响应状态码枚举类
* @Date 2020/8/26
*/
@Getter
public enum ResultCode {
SUCCESS(200, "操作成功"),
FAILED(1001, "响应失败"),
VALIDATE_FAILED(1002, "参数校验失败"),
ERROR(5000, "未知错误");
private int code;
private String msg;
ResultCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
}
package com.dongl.utils.error;
import com.dongl.utils.response.ResultCode;
import com.dongl.utils.response.ResultVO;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @author D-L
* @Classname ExceptionControllerAdvice
* @Version 1.0
* @Description 全局处理参数校验异常返回提示
* @Date 2020/8/26
*/
@RestControllerAdvice
public class ExceptionControllerAdvice {
@ExceptionHandler(APIException.class)
public ResultVO<String> APIExceptionHandler(APIException e) {
// 注意哦,这里传递的响应码枚举
return new ResultVO<>(ResultCode.FAILED, e.getMsg());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResultVO<String> MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
// 注意哦,这里传递的响应码枚举
return new ResultVO<>(ResultCode.VALIDATE_FAILED, objectError.getDefaultMessage());
}
}
返回响应体:
{
"code": 1002,
"msg": "参数校验失败",
"data": "需要在20和99之间"
}
三、全局配置响应体(这里需要加上扫描的包)
这样定义完了响应体,就需要你在编写代码的同时,每一个接口都要添加对应的code msg data ,虽然勉强说的过去,但是总感觉差点意思,当然我们可以统一处理,先创建一个类加上注解使其成为全局处理类。然后继承ResponseBodyAdvice接口重写其中的方法,即可对我们的controller进行增强操作。
package com.dongl.utils.response;
import com.dongl.utils.error.APIException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* @author D-L
* @date 2020-08-27
* @Description 全局配置 响应体
* Version 1.0
*/
@RestControllerAdvice(basePackages = {"com.dongl.controller"}) // 注意哦,这里要加上需要扫描的包
public class ResponseControllerAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> aClass) {
// 如果接口返回的类型本身就是ResultVO那就没有必要进行额外的操作,返回false
return !returnType.getGenericParameterType().equals(ResultVO.class);
}
@Override
public Object beforeBodyWrite(Object data, MethodParameter returnType, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest request, ServerHttpResponse response) {
// String类型不能直接包装,所以要进行些特别的处理
if (returnType.getGenericParameterType().equals(String.class)) {
ObjectMapper objectMapper = new ObjectMapper();
try {
// 将数据包装在ResultVO里后,再转换为json字符串响应给前端
return objectMapper.writeValueAsString(new ResultVO<>(data));
} catch (JsonProcessingException e) {
throw new APIException("返回String类型错误");
}
}
// 将原本的数据包装在ResultVO里
return new ResultVO<>(data);
}
}
【总结】响应体的定义,以及状态码的定义,都可以自己根据自己的需要和业务的需要自行编写。