实现环境: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));
}
}
可以查看官网说明
WebFlux自定义@RequestBody与MVC自定义@RequestBody类似
如有谬误,欢迎各位大佬斧正!