SpringBoot MVC實現自定義RequestBody註解
阿新 • • 發佈:2019-01-02
實現環境: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
如有謬誤,歡迎各位大佬斧正!