Spring Boot WebFlux实现@JsonBody注解自定义参数解析器方案咨询
WebFlux自定义@JsonBody参数解析器实现方案
1. 定义@JsonBody自定义注解
和Spring MVC环境的注解定义一致,仅用于标记需要从请求体JSON解析的参数:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface JsonBody { }
2. 实现HandlerMethodArgumentResolver
WebFlux环境需要实现org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver接口,核心逻辑复用Spring内置的JSON解码器处理请求体,避免自行读取请求体导致的资源泄露、重复读取问题:
import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; import org.springframework.http.MediaType; import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.web.reactive.BindingContext; import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.util.List; public class JsonBodyArgumentResolver implements HandlerMethodArgumentResolver { private final List<HttpMessageReader<?>> messageReaders; public JsonBodyArgumentResolver(ServerCodecConfigurer codecConfigurer) { this.messageReaders = codecConfigurer.getReaders(); } @Override public boolean supportsParameter(MethodParameter parameter) { // 判断参数是否标注了@JsonBody注解 return parameter.hasParameterAnnotation(JsonBody.class); } @Override public Mono<Object> resolveArgument(MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) { ServerHttpRequest request = exchange.getRequest(); ResolvableType targetType = ResolvableType.forMethodParameter(parameter); // 遍历所有内置的消息阅读器,找到匹配JSON的阅读器解析请求体 for (HttpMessageReader<?> reader : messageReaders) { if (reader.canRead(targetType, MediaType.APPLICATION_JSON)) { return reader.readMono(targetType, parameter, request, exchange, bindingContext.getModel()) .cast(Object.class); } } // 没有匹配的阅读器时返回空 return Mono.empty(); } }
以上实现同时支持普通POJO参数和Mono<T>/Flux<T>包装的响应式参数,Spring会自动处理返回的响应式结果完成参数绑定
3. 注册自定义解析器
在WebFlux配置类中注册解析器,使其生效:
import org.springframework.context.annotation.Configuration; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.web.reactive.config.WebFluxConfigurer; import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer; @Configuration public class WebFluxConfig implements WebFluxConfigurer { private final ServerCodecConfigurer codecConfigurer; public WebFluxConfig(ServerCodecConfigurer codecConfigurer) { this.codecConfigurer = codecConfigurer; } @Override public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) { configurer.addCustomResolver(new JsonBodyArgumentResolver(codecConfigurer)); } }
4. 控制器使用示例
和Spring MVC的使用方式完全一致:
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; @RestController @RequestMapping("/student") public class StudentController { // 普通POJO参数 @PostMapping public Mono<Student> addStudent(@JsonBody Student student) { // 业务逻辑处理 return Mono.just(student); } // 响应式包装参数 @PostMapping("/async") public Mono<Student> addStudentAsync(@JsonBody Mono<Student> studentMono) { return studentMono.doOnNext(student -> { // 业务逻辑处理 }); } }
注意事项
- 无需自行通过
exchange.getRequest().getBody()读取请求体转字符串后用ObjectMapper解析,Spring内置的解码器已经处理了编码适配、类型转换、空请求体等边界场景,性能和稳定性更高 - 如果需要自定义JSON序列化/反序列化规则,直接配置Spring默认的
Jackson2ObjectMapperBuilder即可,解析器会自动复用该配置的ObjectMapper - 若接收JSON数组参数,直接声明
@JsonBody List<Student> list或者@JsonBody Flux<Student> flux即可,解码器会自动适配
内容的提问来源于stack exchange,提问作者tweetysat
相关产品推荐
相关产品推荐

