使用 ResponseBodyAdvice 对 controller 进行二次封装

概述

一般情况下 controller 的返回值为了规范我们都会进行二次封装,而之前的项目里我一般都是重新去 new 一个某个返回信息的类,反正一般都是要将其写在方法中。而这个代码又不属于业务代码,所以这时候浏览学习到了 看看别人后端API接口写得,那叫一个优雅! 这样一篇文章。

得到以下思路:我们可以通过注解来表名当前的方法返回什么类型的,然后通过某个切面进行修改。

代码

首先,为了方便,将返回码和返回信息都集成在一个枚举类之中。

@AllArgsConstructor
public enum ResultCode {

    SUCCESS(1,"成功"),
    PARAM_IS_INVALID(1001,"参数无效"),
    PARAM_IS_BLANK(1002,"参数为空"),
    PARAM_TYPE_BIND_ERROR(1003,"参数类型错误"),
    PARAM_NOT_COMPLETE(1004,"参数缺失"),
    USER_NOT_LOGGED_IN(2001,"用户未登录或无权限"),
    USER_LOGIN_ERROR(2002,"账号不存在或密码错误"),
    USER_NOT_EXIST(2003,"用户不存在"),
    USER_HAS_EXISTED(2004,"用户已存在");

    private Integer code;
    private String message;

然后再创建一个「返回类」,其中包含返回码、返回信息、具体数据,之后创建一个以上面枚举类为参数的构造函数。


@Data
public class Result implements Serializable {
    private Integer code;
    private String message;
    private Object data;

    public Result(ResultCode resultCode, Object data) {
        setResultCode(resultCode);
        this.data = data;
    }

为了区分当前类,我们还需要编写一个注解来声明当前类需要对返回值进行封装。并且加入属性 type 进行区分信息类型。当然,上方枚举类在当前注解中使用是有歧义的,所以请忽视。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ResponseResult {
    ResultCode type() default ResultCode.SUCCESS;
}

在之后再创建一个Handler 并且将其实现 ResponseBodyAdvice<Object> 接口,以及 @ControllerAdvice 注解,实现接口的两个方法。其中在 supports() 方法之中用于判断目标对象是否包含相对应的注解,而 beforeBodyWrite() 方法就是用于封装当前数据并将其返回的方法。

@Slf4j
@ControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
       return AnnotationUtils.findAnnotation(methodParameter.getAnnotatedElement(), ResponseResult.class) != null;
    }

    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        ResponseResult responseResult = AnnotationUtils.findAnnotation(methodParameter.getAnnotatedElement(), ResponseResult.class);
        return new Result(responseResult.type(),o).toString();
    }
}
# JavaSpring