SpringBoot MVC实现自定义RequestBody注解

实现环境:SpringBoot 2.1.1,JDK 1.8

一、MVC实现RequestBody注解源码解析

1. @RequestBody

源码:

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestBody {

	/**
	 * Whether body content is required.
	 * <p>Default is {@code true}, leading to an exception thrown in case
	 * there is no body content. Switch this to {@code false} if you prefer
	 * {@code null} to be passed when the body content is {@code null}.
	 * @since 3.2
	 */
	boolean required() default true;

}
  • @Target(ElementType.PARAMETER):Target定义注解的作用目标,ElementType.PARAMETER作用在方法参数上
  • @Retention(RetentionPolicy.RUNTIME):注解会在class字节码文件中存在,在运行时可以通过反射获取到
  • @Documented:说明该注解被包含在javadoc中

2. RequestResponseBodyMethodProcessor

  官方解释:

Resolves method arguments annotated with {@code @RequestBody} and handles return values from methods annotated with {@code @ResponseBody} by reading and writing to the body of the request or response with an {@link HttpMessageConverter}.

 源码中的继承关系

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor
public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver implements HandlerMethodReturnValueHandler 
  • AbstractMessageConverterMethodProcessor:使用HttpMessageConverters解析response body和request body的参数值
Extends {@link AbstractMessageConverterMethodArgumentResolver} with the ability to handle method return values by writing to the response with {@link HttpMessageConverter HttpMessageConverters}
  • AbstractMessageConverterMethodArgumentResolver:使用HttpMessageConverters解析request body参数值的基类
A base class for resolving method argument values by reading from the body of a request with {@link HttpMessageConverter HttpMessageConverters}.

 RequestResponseBodyMethodProcessor对@RequestBody的绑定及实现源码:

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
    
    ...


        @Override
	public boolean supportsParameter(MethodParameter parameter) {
		return parameter.hasParameterAnnotation(RequestBody.class);
	}

	/**
	 * Throws MethodArgumentNotValidException if validation fails.
	 * @throws HttpMessageNotReadableException if {@link RequestBody#required()}
	 * is {@code true} and there is no body content or if there is no suitable
	 * converter to read the content with.
	 */
	@Override
	public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

		parameter = parameter.nestedIfOptional();
		Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
		String name = Conventions.getVariableNameForParameter(parameter);

		if (binderFactory != null) {
			WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
			if (arg != null) {
				validateIfApplicable(binder, parameter);
				if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
					throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
				}
			}
			if (mavContainer != null) {
				mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
			}
		}

		return adaptArgumentIfNecessary(arg, parameter);
	}

    ...

}
supportsParameter方法实现与@RequestBody绑定,resolveArgument实现具体解析

 二、自定义RequestBody

1. 自定义注解

import java.lang.annotation.*;

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface KIMBody {
}

2. Resolver

package com.example.kimpay.request;

import org.springframework.core.MethodParameter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver;

import java.util.Iterator;
import java.util.List;

/**
 * Description: 继承AbstractMessageConverterMethodArgumentResolver实现RequestBody方式解析
 * 也可直接实现HandlerMethodArgumentResolver类自定义解析方式
 * 
 * 
 * 
 */

public class KIMBodyResolver extends AbstractMessageConverterMethodArgumentResolver {
    public KIMBodyResolver(List<HttpMessageConverter<?>> converters) {
        super(converters);
    }

    public KIMBodyResolver(List<HttpMessageConverter<?>> converters, List<Object> requestResponseBodyAdvice) {
        super(converters, requestResponseBodyAdvice);
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(KIMBody.class);//绑定注解
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        String token=webRequest.getHeader("token");
        //判断头部token是否存在
        if (null==token||token.isEmpty()){
            throw new Exception("token is null");
        }
        //打印头部信息
        Iterator<String> headerNames = webRequest.getHeaderNames();
        String headerParameter;
        while (headerNames.hasNext()) {
            headerParameter = headerNames.next();
            System.out.println(headerParameter + ":" + webRequest.getHeader(headerParameter));
        }
        //调用AbstractMessageConverterMethodArgumentResolver类中readWithMessageConverters方法
        Object args = readWithMessageConverters(webRequest, parameter, parameter.getParameterType());
        return args;
    }
}

3. 将Resolver添加入配置中

package com.example.kimpay.config;

import com.example.kimpay.request.KIMBodyResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableWebMvc
public class KIMConfig implements WebMvcConfigurer {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
        //添加消息转换器
        converters.add(new MappingJackson2HttpMessageConverter());
        //消息转换器与Resolver绑定
        resolvers.add(new KIMBodyResolver(converters));
    }

}

也可以官网上的方式添加配置。

三、HttpMessageConverter<>消息转换器

HttpMessageConverter主要是用来转换request的内容到一定的格式,转换输出的内容的到response。即:controller方法返回的类型,可以是字节数组、字符串、对象引用等,经过HttpMessageConverter处理后,将这些返回类型以一定内容格式(即response的content-type类型,同时还要考虑到客户端是否接受这个类型)存进response的body中返回给客户端。可参考https://lgbolgger.iteye.com/blog/2108885

如有谬误,欢迎各位大佬斧正!

猜你喜欢

转载自blog.csdn.net/shenszy/article/details/85597919