提问者:小点点

为什么验证Spring控制器请求参数需要@验证?


使用带注释的MVC控制器中的以下验证设置:

@RestController
@RequestMapping("/users")
@Validated  // <-- without this, the @Size annotation in setPassword() has no effect
public class UserController {

    @PutMapping("/{id}/password")
    public void setPassword(@PathVariable long id, @RequestBody @Size(min = 8) String password) {
        /* ... */
    }

    @PutMapping("/{id}/other")
    public void setOther(@PathVariable long id, @RequestBody @Valid MyFormObject form) {
        /* ... */
    }
}

方法参数需要在控制器上的@Valid,因为它不是一个“复杂”对象。相比之下,set其他方法上的@Valid注解在没有@Valed注解的情况下也可以工作。

为什么需要@验证?为什么不默认启用它?使用它有成本吗?

请注意,在Spring中@Valid和@Val的区别是相关的(我在问这个问题之前阅读了它),但它并没有解决我问题中的原因。


共1个答案

匿名用户

对象的验证由Hibernate Validator使用Jakarta Bean Validation2.0的注释完成。需要一些东西来触发hibernate validator才能运行。

SpringMVC在看到带有@Valid的参数时调用控制器方法,它会将该对象传递给Hibernate验证器。Hibernate验证器将

  1. 检查对象的类以找出类字段上放置了哪些验证规则
  2. 针对用验证注释标记的字段执行验证规则。

所以在这种情况下

@PutMapping("/{id}/other")
public void setOther(@PathVariable long id, @RequestBody @Valid MyFormObject form) {
        /* ... */
} 

MyFormObject上面有注释,Hibernate验证器可以找到这些注释来验证对象。

在这种情况下

@PutMapping("/{id}/password")
public void setPassword(@PathVariable long id, @RequestBody @Size(min = 8) String password) {
        /* ... */
}

java. lang.String上没有定义任何注释供Hibernate验证器发现。

@Valid来自Bean验证包javax. valid.Valid,而@Valided来自Springorg.springframe.validation.annotation.Valided

@验证注解激活Spring验证AOP拦截器,它将检查方法参数以查看它们是否有任何验证注解,如果它们有,那么Spring将使用每个特定的注解调用hibernate验证器,例如@Size(min=8)字符串密码意味着调用hibernate大小验证器并传递参数密码的值,在这种情况下,hibernate验证器不需要扫描java. lang.String以查看它是否有验证注解。@验证适用于任何Spring@Component,例如您可以在@Service类上使用它。

与使用@Transactional类似,使用@Valid会有额外的开销,因此您必须选择使用它。在javax. valid.Valid的情况下,SpringMVC需要检查控制器方法参数的注释,因此当它看到@Valid时,它很容易将该对象发送到Hibernate Validator,而无需添加AOP拦截器。