实现环境: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
如有谬误,欢迎各位大佬斧正!