“实现环境:SpringBoot 2.1.1,JDK 1.8
”
一、WebFlux 实现 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. RequestBodyArgumentResolver
官方解释:
“Resolves method arguments annotated with {@code @RequestBody} by reading the body of the request through a compatible {@code HttpMessageReader}.
”
源码中的继承关系
public class RequestBodyArgumentResolver extends AbstractMessageReaderArgumentResolver
public abstract class AbstractMessageReaderArgumentResolver extends HandlerMethodArgumentResolverSupport
RequestBodyArgumentResolver:使用 HttpMessageReader 解析 request body 参数的具体实现类
“Resolves method arguments annotated with {@code @RequestBody} by reading the body of the request through a compatible {@code HttpMessageReader}.
”
AbstractMessageReaderArgumentReaolver:使用 HttpMessageReder 解析 request body 参数的基类
“Abstract base class for argument resolvers that resolve method arguments by reading the request body with an {@link HttpMessageReader}.
”
RequestBodyArgumentResolver 对 @RequestBody 的绑定及参数解析源码
public class RequestBodyArgumentResolver extends AbstractMessageReaderArgumentResolver {
public RequestBodyArgumentResolver(List<HttpMessageReader<?>> readers,
ReactiveAdapterRegistry registry) {
super(readers, registry);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
@Override
public Mono<Object> resolveArgument(
MethodParameter param, BindingContext bindingContext, ServerWebExchange exchange) {
RequestBody ann = param.getParameterAnnotation(RequestBody.class);
Assert.state(ann != null, "No RequestBody annotation");
return readBody(param, ann.required(), bindingContext, exchange);
}
}
“supportsParameter 与 @RequestBody 注解绑定,resolveArgument 实现具体解析
”
二、自定义 RequestBody
1. 自定义注解
import java.lang.annotation.*;
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyBody {
boolean required() default true;
}
2. Resolver
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.Assert;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.annotation.AbstractMessageReaderArgumentResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
public class MyBodyResolver extends AbstractMessageReaderArgumentResolver {
public KIMBodyResolver(List<HttpMessageReader<?>> readers) {
super(readers);
}
protected KIMBodyResolver(List<HttpMessageReader<?>> messageReaders, ReactiveAdapterRegistry adapterRegistry) {
super(messageReaders, adapterRegistry);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(MyBody.class);//绑定注解
}
@Override
public Mono<Object> resolveArgument(MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) {
ServerHttpRequest request = exchange.getRequest();
String token = request.getHeaders().getFirst("token");//获取头部token
if (null == token||token.isEmpty()){
Assert.state(token==null,"token is null");
return Mono.error(new Exception("token is null"));//token不存在抛出异常
}
MyBody annotation = parameter.getParameterAnnotation(MyBody.class);
Assert.state(annotation != null, "No KIMBody annotation");
//调用AbstractMessageReaderArgumentResolver类中readBody方法
return readBody(parameter,annotation.required(),bindingContext,exchange);
}
}
3. 将 Resolver 添加入配置中
import com.example.webflux.request.MyBodyResolver;
import javafx.beans.property.ObjectProperty;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.codec.DecoderHttpMessageReader;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;
import java.util.ArrayList;
import java.util.List;
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
List<HttpMessageReader<?>> readers=new ArrayList<HttpMessageReader<?>>();
//添加Http消息编解码器
readers.add(new DecoderHttpMessageReader<>(new Jackson2JsonDecoder()));
//消息编解码器与Resolver绑定
configurer.addCustomResolver(new MyBodyResolver(readers));
}
}
可以查看官网(https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-config-message-codecs)说明
WebFlux 自定义 @RequestBody 与 MVC 自定义 @RequestBody 类似
如有谬误,欢迎各位大佬斧正!
作者:冲冠
来源链接:
https://blog.csdn.net/shenszy/article/details/85676415