SpringBoot实现统一返回接口(除AOP)

起因

关于使用AOP去实现统一返回接口在之前的博客中我们已经实现了,但我突然突发奇想,SpringBoot中异常类的统一返回好像是通过@RestControllerAdvice 这个注解去完成的,那我是否也可以通过这个注解去实现统一返回接口。

正文

这个方法主要是通过@ControllerAdvice + ResponseBodyAdvice实现统一返回结果。其实本质来说和aop实现是相通的明白一个另一个就非常好理解了。
(Result 的代码我就不在这边重复贴了,读者可以去我直接用AOP实现的博客中拿)

自定义注解

import com.study.project.common.BaseResponse;
import com.study.project.common.ResultCode;

import java.lang.annotation.*;

import static com.study.project.common.ResultCode.SUCCESS;

/**
 * @date 2023/2/18
 */
@Documented
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface FunctionResult {
    String value() default "";
    
	//默认code为成功
    ResultCode code() default SUCCESS;
}

自定义一个响应拦截

import com.study.project.annotation.FunctionResult;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
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;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;


/**
 * @author Chengming.Zhang
 * @date 2023/2/18
 * ResponseBodyAdvice主要是对加了@RestController(也就是@Controller+@ResponseBody)注解的处理器将要返回的值进行增强处理。
 *其实也就是采用了AOP的思想,对返回值进行一次修改。
 */
@RestControllerAdvice
public class FunctionResponseBodyAdvice implements ResponseBodyAdvice  {
    //判断当前类上是否有@FunctionResult
    protected boolean isFunctionResult(MethodParameter returnType) {
        /**
         * getContainingClass() 获取当前类的信息
         * isAnnotationPresent 判断当前类上是否存在某个注解
         */
        Class<?> containingClass = returnType.getContainingClass();
        boolean annotationPresent = containingClass.isAnnotationPresent(FunctionResult.class);
        Annotation[] annotations = containingClass.getAnnotations();
        return returnType.getContainingClass().isAnnotationPresent(FunctionResult.class);
    }

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return isFunctionResult(returnType);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {

        Method method = returnType.getMethod();
        Class<?> methodReturnType = method.getReturnType();
        //判断是否为void的方法
        if (methodReturnType.equals(void.class)) {
            return body;
        }
        //判断当前方法是否有@FunctionResult注解,如果没有则全部按照成功返回,如果有则根据具体指定的返回码以及返回内容返回
        FunctionResult result = returnType.getMethod().getAnnotation(FunctionResult.class);
        if (result == null) {
            return new BaseResponse(ResultCode.SUCCESS, body);
        }
        ResultCode code = result.code();
        return new BaseResponse(result.code(), body);
    }
}

controller类

import com.study.project.annotation.FunctionResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @date 2023/2/4
 */
@FunctionResult
@RestController
public class TestController {

    @RequestMapping("/test5")
    public int test5(){
        return 1;
    }

    @RequestMapping("/test6")
    public void test6(){
        System.err.println("test6");
    }
}

测试
SpringBoot实现统一返回接口(除AOP)_第1张图片
SpringBoot实现统一返回接口(除AOP)_第2张图片

你是不是以为代码已经结束?
其实这个代码是有问题hhhhh,当接口的返回类型是String的时候就会提示报错
SpringBoot实现统一返回接口(除AOP)_第3张图片
看控制台的报错信息发现是接口的返回参数转换的时候报错了,于是我们根据控制台上的报错信息进行断点排查

首先我们找到控制台中的第一行的报错类StringHttpMessageConverter.java中的addDefaultHeaders方法,发这个方法其实是重新了他父类的AbstractHttpMessageConverter的方法

在这里插入图片描述
SpringBoot实现统一返回接口(除AOP)_第4张图片
AbstractHttpMessageConverter中的方法Result的参数是T,但是StringHttpMessageConverter在重写的时候将其转为了String,因此当ResponseBodyAdvice返回Result格式的时候就会报错,所以我们就需要在ResponseBodyAdvice中需要单独处理一下String类型。

完整代码

import cn.hutool.json.JSONUtil;
import com.study.project.annotation.FunctionResult;
import jdk.nashorn.internal.objects.annotations.Function;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;


/**
 * @author Chengming.Zhang
 * @date 2023/2/18
 * ResponseBodyAdvice主要是对加了@RestController(也就是@Controller+@ResponseBody)注解的处理器将要返回的值进行增强处理。
 *其实也就是采用了AOP的思想,对返回值进行一次修改。
 */
@RestControllerAdvice
public class FunctionResponseBodyAdvice implements ResponseBodyAdvice  {
    //判断当前类上是否有@FunctionResult
    protected boolean isFunctionResult(MethodParameter returnType) {
        /**
         * getContainingClass() 获取当前类的信息
         * isAnnotationPresent 判断当前类上是否存在某个注解
         */
        Class<?> containingClass = returnType.getContainingClass();
        boolean annotationPresent = containingClass.isAnnotationPresent(FunctionResult.class);
        Annotation[] annotations = containingClass.getAnnotations();
        return returnType.getContainingClass().isAnnotationPresent(FunctionResult.class);
    }

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return isFunctionResult(returnType);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {

        Method method = returnType.getMethod();
        Class<?> methodReturnType = method.getReturnType();
        if (methodReturnType.equals(void.class)) {
            return body;
        }
        //判断当前方法是否有@FunctionResult注解,如果没有则全部按照成功返回,如果有则根据具体指定的返回码以及返回内容返回
        FunctionResult result = returnType.getMethod().getAnnotation(FunctionResult.class);
        if (result == null) {
            if (body instanceof String) {
                return JSONUtil.toJsonStr(new BaseResponse(ResultCode.SUCCESS, body));
            }
            return new BaseResponse(ResultCode.SUCCESS, body);
        }
        if (body instanceof String) {
            return JSONUtil.toJsonStr(new BaseResponse(result.code(), body));
        }
        return new BaseResponse(result.code(), body);
    }
}

你可能感兴趣的:(spring,boot,spring,java)