SpringBoot WebFlux实现自定义RequestBody注解

实现环境: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.
	 * 

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> readers,
			ReactiveAdapterRegistry registry) {

		super(readers, registry);
	}


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

	@Override
	public Mono 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> readers) {
        super(readers);
    }

    protected KIMBodyResolver(List> messageReaders, ReactiveAdapterRegistry adapterRegistry) {
        super(messageReaders, adapterRegistry);
    }

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

    @Override
    public Mono 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> readers=new ArrayList>();
        //添加Http消息编解码器
        readers.add(new DecoderHttpMessageReader<>(new Jackson2JsonDecoder()));
        //消息编解码器与Resolver绑定
        configurer.addCustomResolver(new MyBodyResolver(readers));
    }

}

可以查看官网说明

WebFlux自定义@RequestBody与MVC自定义@RequestBody类似

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

你可能感兴趣的:(java)