Kotlin Spring Boot Webflux中@Valid注解校验@RequestBody不生效问题
问题原因及解决方案
你遇到的校验不生效是4个常见的WebFlux+Kotlin参数校验组合问题,按顺序修改即可:
1. 校验注解使用错误
@Max是JSR-380规范中用于数值类型的校验注解,不能用来校验字符串长度,你需要替换为@Size注解来限制字符串长度。
2. Kotlin数据类注解作用域错误
Kotlin中直接写在数据类主构造参数上的校验注解,默认是标注在构造参数而非类字段上,校验框架无法读取,需要给注解加上field:前缀指定作用于字段。
3. WebFlux请求体验写规则错误
Spring WebFlux是响应式框架,请求体需要用Mono/Flux包裹,同时@Valid注解需要标注在泛型内部的实体类上,才能触发校验逻辑。
4. 缺失校验依赖
Spring Boot 2.3及以上版本中,spring-boot-starter-webflux不再默认集成校验组件,需要手动引入校验依赖:
<!-- Maven 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
// Gradle 依赖 implementation 'org.springframework.boot:spring-boot-starter-validation'
修改后的代码示例
修改后Recipe实体类
package com.example.reactive.models import org.springframework.data.annotation.Id import org.springframework.data.relational.core.mapping.Table import javax.validation.constraints.NotBlank import javax.validation.constraints.Size @Table("recipes") data class Recipe ( @Id val id: Long?, @field:NotBlank(message = "Title is required") val title: String, @field:Size(max = 10, message = "Description is too long") val description: String?, )
修改后Controller代码
package com.example.reactive.controllers import com.example.reactive.models.Recipe import com.example.reactive.services.RecipeService import org.springframework.http.HttpStatus import org.springframework.web.bind.annotation.* import reactor.core.publisher.Mono import javax.validation.Valid @RestController @RequestMapping("/recipes") class RecipeController(val recipeService : RecipeService) { @PostMapping @ResponseStatus(HttpStatus.CREATED) fun createRecipe(@RequestBody payload: Mono<@Valid Recipe>): Mono<Recipe> = payload.flatMap(recipeService::createRecipe) }
可选优化:统一异常返回
如果需要返回结构化的校验错误信息,可以新增全局异常处理器捕获WebFlux校验抛出的WebExchangeBindException:
@ControllerAdvice class GlobalExceptionHandler { @ExceptionHandler(WebExchangeBindException::class) fun handleValidException(e: WebExchangeBindException): ResponseEntity<Map<String, String?>> { val errors = e.bindingResult.fieldErrors.associate { it.field to it.defaultMessage } return ResponseEntity.badRequest().body(errors) } }
内容的提问来源于stack exchange,提问作者paswes
相关产品推荐
相关产品推荐

