SpringBoot implements unified return interface (except AOP)

origin

Regarding the use of AOP to implement the unified return interface, we have already implemented it in the previous blog, but I suddenly thought that the unified return of exception classes in SpringBoot seems to be done through this annotation, so can I also use this annotation to @RestControllerAdvicego Implement a unified return interface.

text

This method mainly uses @ ControllerAdvice+ ResponseBodyAdviceto achieve unified return results. In fact, it is essentially the same as the aop implementation. It is very easy to understand one if you understand the other.
(I won’t repost the Result code here. Readers can get it from my blog where I implemented it directly using AOP)

Custom annotations

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;
}

Customize a response interception

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 class

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");
    }
}

test
Insert image description here
Insert image description here

Did you think the code was finished?
In fact, there is a problem with this code hhhhh, when the return type of the interface is String, an
Insert image description here
error message will be prompted to see the error message on the console, and it is found that an error was reported when the return parameter of the interface was converted, so we interrupted according to the error message on the console Click to troubleshoot

StringHttpMessageConverter.javaFirst, we find the method in the error reporting class in the first line of the console . This method is actually a new method of addDefaultHeadersits parent class.AbstractHttpMessageConverter

Insert image description here
Insert image description here
AbstractHttpMessageConverterThe parameter of the method Result in is T, but it StringHttpMessageConverteris converted to a String when it is rewritten, so when ResponseBodyAdvicethe Result format is returned, an error will be reported, so we need to ResponseBodyAdvicedeal with the String type separately in the method.

Complete code

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);
    }
}

Guess you like

Origin blog.csdn.net/qq_43649799/article/details/129106439