问题: 发现每个接口请求返回的内容都不一样,前端处理起来麻烦;后端处理的话每个接口都要通过类似Result的对象返回
实现自定义注解: 优点:只要在接口类或者接口方法上携带该注解,接口都可以自动通过类似Result返回,不需要自己手动规整统一返回
展示:
步骤:
① 准备工作
创建标识注解类 UnifiedReturn (注解名字自定义)
import java.lang.annotation.*;
/**
* @author hjh
* 统一返回结果
* Target是作用的范围
*/
@Target(value = {ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UnifiedReturn {
}
创建统一返回结果类
import java.io.Serializable;
/**
* @author root
*/
public class ResultData<T> implements Serializable {
private static final long serialVersionUID = 2260434901667977303L;
/**
* code:状态码
* msg:消息
* exception:原始的异常信息,方便从页面排查问题.
* total:分页时,表示所有页加起来的数据总数
* pageNum:分页时,表示当前的页码
* pageSize:分页时,表示每页显示的数据条数
* pages:分页时,表示总页数
*/
private int code;
private String msg;
private Long ts;
private T data;
public ResultData() {
}
public ResultData(ResultCode resultCode, T data) {
this.code = resultCode.getCode();
this.msg = resultCode.getMessage();
this.data = data;
}
public ResultData(ResultCode resultCode, T data, String exception) {
this.code = resultCode.getCode();
this.msg = resultCode.getMessage();
this.data = data;
}
public ResultData(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public Long getTs() {
return System.currentTimeMillis();
}
public String getMessage() {
return msg;
}
public void setMessage(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public static <T> ResultData<T> success() {
return success(null);
}
public static <T> ResultData<T> success(T data) {
return success(ResultCode.SUCCESS, data);
}
public static <T> ResultData<T> success(ResultCode resultCode, T data) {
return success(resultCode, data, resultCode.getMessage());
}
public static <T> ResultData<T> success(ResultCode resultCode, T data, String msg) {
ResultData<T> resultData = new ResultData<>(resultCode, data);
resultData.setMessage(msg);
return resultData;
}
public static <T> ResultData<T> error() {
return error(ResultCode.FAIL);
}
public static <T> ResultData<T> error(String msg) {
return error(ResultCode.FAIL, msg);
}
public static <T> ResultData<T> error(Integer code,String msg) {
return new ResultData<>(code,msg);
}
public static <T> ResultData<T> error(ResultCode resultCode) {
return error(resultCode, resultCode.getMessage());
}
public static <T> ResultData<T> error(ResultCode resultCode, String msg) {
return error(resultCode, msg, null);
}
public static <T> ResultData<T> error(ResultCode resultCode, Exception e) {
return error(resultCode, resultCode.getMessage(), e.toString());
}
public static <T> ResultData<T> error(ResultCode resultCode, String msg, String exception) {
ResultData<T> resultData = new ResultData<>(resultCode, null, exception);
resultData.setMessage(msg);
return resultData;
}
定义code编码 ResultCode
public enum ResultCode {
SUCCESS(200, "操作成功"),
SUCCESS_LOAD(200, "查询成功"),
EXP_SUCCESS(200,"导出成功"),
IMP_SUCCESS(200,"导入成功"),
FAIL(500, "操作失败"),
/**
* 参数错误:1000-1999
*/
PARAM_IS_FAIL(1000, "参数校验未通过"),
PARAM_IS_INVALID(1001, "参数无效"),
PARAM_IS_BLANK(1002, "参数为空"),
PARAM_TYP_EBIND_ERROR(1003, "参数类型错误"),
PARAM_NOT_C0MPLETE(1004, "参数缺失"),
/**
* 用户错误:2000-2999
*/
USER_NOT_L0GGED_IN(2001, "用户未登录,访问的路径需要验证,请登录"),
USER_L0GIN_ERROR(2002, "账号不存在或密码错误"),
USER_ACCOUNT_F0_RBIDDEN(2003, "账号已被禁用"),
USER_VERIFI_CODE_ERROR(2004, "验证码错误");
private Integer code;
private String message;
ResultCode(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return this.code;
}
public String getMessage() {
return this.message;
}
② 创建UnifiedReturnAdvice,用于拦截处理
主要的目的是判断是否使用了@UnifiedReturn注解标注;定义返回的格式
其中的"com.tool.controller"为自己controller对应的包路径
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.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* @author
*/
@ControllerAdvice(basePackages = "com.tool.controller") // controller对应的包位置
public class UnifiedReturnAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return returnType.getDeclaringClass().getName().contains("com.tool.controller");
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
Class<?> containingClass = returnType.getContainingClass();
//判断进入的方法对应的接口上的注解,主要是判断当前接口对应的类上是否标注了我们定义的@UnifiedReturn注解,如果标注才统一返回
boolean isContainUnifiedReturn = containingClass.isAnnotationPresent(UnifiedReturn.class);
// 判断的是进入的方法: returnType.hasMethodAnnotation(UnifiedReturn.class);
if (!isContainUnifiedReturn) {
return body;
}
//必须对String类型进行单独处理,否则会报转换类型异常
if (body instanceof String){
return body;
}
return body instanceof ResultData ? body : ResultData.success(body);
}
③ 在接口类上增加@UnifiedReturn注解,编写代码测试