控制器方法中 requestBody 上的 Spring Boot @Valid 不起作用
Posted
技术标签:
【中文标题】控制器方法中 requestBody 上的 Spring Boot @Valid 不起作用【英文标题】:Spring boot @Valid on requestBody in controller method not working 【发布时间】:2020-09-11 12:17:27 【问题描述】:我正在尝试在由@Validated 注释的@RestController 中验证由@Valid 注释注释的简单请求正文。验证在请求中的原始变量上正常工作(在下面的例子中年龄),但在 pojo 请求正文上没有工作。 @Valid 注解对请求主体 Person 类没有影响(即控制器接受空白名称和 18 岁以下的年龄)。
人物类:
import javax.validation.constraints.Min
import javax.validation.constraints.NotBlank
class Person (
@NotBlank
val name : String,
@Min(18)
val age : Int
)
控制器类:
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
import javax.validation.Valid
@RestController
@Validated
class HomeController
@GetMapping("/age")
fun verifyAge(@PathVariable("age") @Min(18) age:Int): String
return "Eligible age."
@PostMapping
fun personValidation(@Valid @RequestBody person : Person) : String
return "No validation error"
@NotBlank、@Min 和 @Valid 注释来自以下依赖:
implementation("org.springframework.boot:spring-boot-starter-validation:2.3.0.RELEASE")
如何让@Valid 在 @Validated 控制器中处理 Person 请求正文?
【问题讨论】:
您应该将 BindingResult 声明为方法参数。之后,您将像这样进行验证: if(bindingResult.hasErrors()) ... 我只想使用注释和标准验证器提供程序(如 springframework 或 hibernate)进行验证,而无需任何编程方式,例如:spring.io/guides/gs/validating-form-input。我还可以使用配置类或依赖项配置我的项目,但希望保持验证干净。此外,我的期望是仅验证 pojo 类中的原始/原始值。 此示例使用 BindingResult。在他们的 github 存储库中查看:github.com/spring-guides/gs-validating-form-input/blob/… 【参考方案1】:不要将 Person 标记为 Spring @Component。
实现字段验证的正确方法是将@field 添加到您的属性中。 示例代码:
class SomeRequest(
@field:NotBlank val name: String
)
发生这种情况是因为 Spring Boot 需要将此注释应用于字段。 Kotlin 默认将它们应用于构造函数参数。请参阅 Kotlin 文档中的 Annotation use-site targets。
【讨论】:
谢谢您,先生!我搜索了大量的答案,只有你的答案真的很有帮助! 很高兴我的回答对您有所帮助! :)【参考方案2】:在我的例子中,为了让 @Valid @RequestBody 在 springboot 应用程序中工作,必须同时使用这两个依赖项
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
【讨论】:
【参考方案3】:[已编辑] 正如其中一位用户回答的那样,这也对我有用(在构造函数参数上添加字段注释):
import javax.validation.constraints.Min
import javax.validation.constraints.NotBlank
class Person (
@field:NotBlank
val name : String,
@field:Min(18)
val age : Int
)
尽管将 Person 的“kotlin”类定义更改如下(将构造函数参数更改为无参数)(注意括号 (...) 到花括号...)也可以在不添加 @field 注释的情况下工作:
import javax.validation.constraints.Min
import javax.validation.constraints.NotBlank
class Person
@NotBlank
lateinit var name: String
@Min(18)
var age: Int = 0
【讨论】:
【参考方案4】:你可以试试这个选项。
请使用@PostMapping("/validateBody") 之类的URL 映射@PostMapping,并尝试使用它的URL。正如https://reflectoring.io/bean-validation-with-spring-boot/所做的那样
【讨论】:
这只是验证示例中的路径。根据项目,该路径可以是“/users”、“/products”之类的任何路径。我共享的帖子映射工作正常,即我成功获得了返回的响应“无验证错误”,只是 @Valid 注释没有任何效果。【参考方案5】:以防万一有人使用@BasePathAwareController
或@RepositoryRestController
注释。 @Valid
目前在 @RepositoryRestController
或 @BasePathAwareController
上不受支持。
Spring Data REST 中有一个未解决的问题:https://github.com/spring-projects/spring-data-rest/issues/967
【讨论】:
【参考方案6】:Piotr Solarski 是正确的(上图),将组件添加到请求主体是不正确的,因为主体会发生变化,并且稍后为它创建单个对象可能会变得很棘手(即使它解决了 OP 的问题)。
在 MVC 应用程序中,这就是我的问题所在。
我添加了你通常做的东西(pom 中的库、RequestBody 上的@Valid 等)
Spring 文档(以及许多博客)留下的微妙之处在于 Spring 寻找一个退出点来抛出错误,但如果该退出不存在,它将回复 404。在阅读了很多之后,尤其是这个 @ 987654321@,添加这个类让Spring识别@Valid并找到退出点抛出错误
@RestControllerAdvice
@Order(1)
public class RestControllerExceptionHandler
@RequestMapping(value = "error/404" , method = RequestMethod.GET)
@ExceptionHandler(Exception.class)
public String handleUnexpectedException(Exception e)
return "views/base/rest-error";
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public String handlemethodArgumentNotValid(MethodArgumentNotValidException exception) //
// TODO you can choose to return your custom object here, which will then get transformed to json/xml etc.
return "Sorry, that was not quite right: " + exception.getMessage();
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(ConstraintViolationException.class)
public String handleConstraintViolation(ConstraintViolationException exception) //
// TODO you can choose to return your custom object here, which will then get transformed to json/xml etc.
return "Sorry, that was not quite right: " + exception.getMessage();
【讨论】:
以上是关于控制器方法中 requestBody 上的 Spring Boot @Valid 不起作用的主要内容,如果未能解决你的问题,请参考以下文章
WEB之ResponseBody RequestBody RequestParam