【问题标题】:What does the @Valid annotation indicate in Spring?Spring中的@Valid注解表示什么?
【发布时间】:2011-04-05 10:35:24
【问题描述】:

在以下示例中,ScriptFile 参数标有 @Valid 注释。

@Valid注解有什么作用?

@RequestMapping(value = "/scriptfile", method = RequestMethod.POST)    
public String create(@Valid ScriptFile scriptFile, BindingResult result, ModelMap modelMap) {    
    if (scriptFile == null) throw new IllegalArgumentException("A scriptFile is required");        
    if (result.hasErrors()) {        
        modelMap.addAttribute("scriptFile", scriptFile);            
        modelMap.addAttribute("showcases", ShowCase.findAllShowCases());            
        return "scriptfile/create";            
    }        
    scriptFile.persist();        
    return "redirect:/scriptfile/" + scriptFile.getId();        
}    

【问题讨论】:

    标签: java spring spring-mvc spring-annotations


    【解决方案1】:

    用于验证目的。

    验证 通常验证一个 将用户输入绑定到它之后的模型。 Spring 3 支持 使用 JSR-303 进行声明式验证。 自动启用此支持 如果是 JSR-303 提供程序,例如 Hibernate Validator,存在于 你的类路径。启用后,您可以 只需通过触发验证 注释控制器方法 带有@Valid 注释的参数: 绑定传入 POST 后 参数,AppointmentForm 将 得到验证;在这种情况下,要验证 日期字段值不为空并且 将来会发生。


    在这里查看更多信息:
    http://blog.springsource.com/2009/11/17/spring-3-type-conversion-and-validation/

    【讨论】:

    • 长话短说,在您的特定示例代码中,ScriptFile 类为@NotNull@NotEmpty 等类数据成员定义了一些约束,而@Valid 指示当有人调用您的方法时,框架(在我们的例子中是 spring)根据提供的参数检查这些约束。在这种情况下,如果验证失败,服务器会返回一个HTTP 400 Bad Request 状态码。
    【解决方案2】:

    除了上面的答案,看看下面的。 AppointmentFormdate 列带有几个注释。通过使用@Valid 注释触发AppointmentForm(在本例中为@NotNull@Future)上的验证。这些注释可能来自不同的 JSR-303 提供者(例如,Hibernate、Spring..等)。

        @RequestMapping(value = "/appointments", method = RequestMethod.POST)
        public String add(@Valid AppointmentForm form, BindingResult result) {
            ....
        }
    
        static class AppointmentForm {
    
            @NotNull @Future
            private Date date;
        }
    

    【讨论】:

    • 我有类似的代码。我已经删除了ApplicationForm 参数上的@Valid,但是仍然在date(设置为null)字段上触发了验证。请解释一下。
    【解决方案3】:

    @Valid 本身与 Spring 无关。它是 Bean Validation 规范的一部分(其中有几个,截至 2017 年下半年,最新的是 JSR 380),但 @Valid 非常古老,并且一直从 JSR 303 派生而来。

    众所周知,Spring 非常擅长提供与所有不同 JSR 和一般 Java 库的集成(想想 JPA、JTA、缓存等),当然这些人也负责验证。促成这一点的关键组件之一是MethodValidationPostProcessor

    尝试回答您的问题 - @Valid 在您想要验证复杂图形而不仅仅是对象的顶级元素时,对于所谓的验证级联非常方便。每次想要更深入,都必须使用@Valid。这就是 JSR 规定的。 Spring 将遵守这一点,但会有一些细微的偏差(例如,我尝试在 RestController 方法上放置 @Validated 而不是 @Valid 并且验证有效,但同样不适用于常规的“服务”bean)。

    【讨论】:

    • 但是,验证什么?
    • 请详细说明,@nephewtom。你想澄清什么?
    • 我阅读了 JSR 303: Bean Validation, beanvalidation.org/1.0/spec 但我仍然不知道将在 ScriptFile scriptFile 上执行什么验证。
    • ScriptFile 里面可能有一堆字段,这些字段上也有注释。这是验证开始的地方。根据原始问题,尚不清楚 ScriptFile 类中到底是什么。
    • 好的,谢谢。你能举一个例子来验证它的字段是否是字符串、整数和 Bean?
    【解决方案4】:

    IIRC @Valid 不是 Spring 注释,而是 JSR-303 注释(这是 Bean 验证标准)。它的作用基本上是检查您发送给该方法的数据是否有效(它将为您验证 scriptFile)。

    【讨论】:

    • “它将为您验证 scriptFile”是什么意思?检查它不为空,它有一些语法,还是一些内容?换句话说,它验证了什么以及如何验证?用户应该实现一些东西吗?我在哪里可以获得有关它的信息?谢谢!
    • 请回答@nephewtom 的问题,没有足够的答案来验证缺少的“反对什么”要点?
    【解决方案5】:

    我想添加更多关于@Valid 工作原理的详细信息,尤其是在春季。

    https://reflectoring.io/bean-validation-with-spring-boot/ 清楚详细地解释了您想了解的有关春季验证的所有信息,但如果链接断开,我将复制@Valid 如何工作的答案。

    @Valid 注释可以添加到 rest 控制器方法中的变量以验证它们。可以验证的变量有 3 种类型:

    • 请求正文,
    • 路径中的变量(例如 /foos/{id} 中的 id)和,
    • 查询参数。

    那么现在...... spring 如何“验证”?您可以通过使用某些注释来注释类的字段来定义对它们的约束。然后,将该类的一个对象传递给一个验证器,该验证器检查是否满足约束条件。

    例如,假设我有这样的控制器方法:

    @RestController
    class ValidateRequestBodyController {
    
      @PostMapping("/validateBody")
      ResponseEntity<String> validateBody(@Valid @RequestBody Input input) {
        return ResponseEntity.ok("valid");
      }
    
    }
    

    所以这是一个包含请求正文的 POST 请求,我们将该请求正文映射到 Input 类。

    这是Input的课程:

    class Input {
    
      @Min(1)
      @Max(10)
      private int numberBetweenOneAndTen;
    
      @Pattern(regexp = "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$")
      private String ipAddress;
      
      // ...
    }
    

    @Valid 注释将告诉 spring 去验证传递到控制器的数据,方法是检查整数 numberBetweenOneAndTen 是否在 1 和 10 之间,因为这些 min 和 max 注释。它还会检查以确保传入的 ip 地址与注解中的正则表达式匹配。

    旁注:正则表达式并不完美。您可以传入大于 255 的 3 位数字,它仍然会匹配正则表达式。


    以下是验证查询变量和路径变量的示例:

    @RestController
    @Validated
    class ValidateParametersController {
    
      @GetMapping("/validatePathVariable/{id}")
      ResponseEntity<String> validatePathVariable(
          @PathVariable("id") @Min(5) int id) {
        return ResponseEntity.ok("valid");
      }
      
      @GetMapping("/validateRequestParameter")
      ResponseEntity<String> validateRequestParameter(
          @RequestParam("param") @Min(5) int param) { 
        return ResponseEntity.ok("valid");
      }
    }
    

    在这种情况下,由于查询变量和路径变量只是整数,而不仅仅是复杂的类,所以我们将约束注解@Min(5)放在参数上,而不是使用@Valid

    【讨论】:

    • > 所以这是一个 POST 请求,它接受一个响应体,我们将该响应体映射到一个类 Input..... 不应该是接受一个“请求正文”?
    • @sss:是的,那是个错误。现已更正
    【解决方案6】:
    public String create(@Valid @NotNull ScriptFile scriptFile, BindingResult result, ModelMap modelMap) {    
        if (scriptFile == null) throw new IllegalArgumentException("A scriptFile is required");        
    

    我猜这个@NotNull 注释是有效的,因此如果不需要条件。

    【讨论】:

      【解决方案7】:

      我想我知道你的问题在哪里。由于这个问题是在 google 的主要搜索结果中弹出的问题,所以我可以对 @Valid 注释的作用给出一个简单的答案。

      我将介绍我如何使用@Valid 的 3 个场景

      型号:

      public class Employee{
      private String name;
      @NotNull(message="cannot be null")
      @Size(min=1, message="cannot be blank")
      private String lastName;
       //Getters and Setters for both fields.
       //...
      }
      

      JSP:

      ...
      <form:form action="processForm" modelAttribute="employee">
       <form:input type="text" path="name"/>
       <br>
       <form:input type="text" path="lastName"/>
      <form:errors path="lastName"/>
      <input type="submit" value="Submit"/>
      </form:form>
      ...
      

      场景 1 的控制器:

           @RequestMapping("processForm")
              public String processFormData(@Valid @ModelAttribute("employee") Employee employee){
              return "employee-confirmation-page";
          }
      

      在这种情况下,在提交您的带有空姓氏字段的表单后,您将收到一个错误页面,因为您正在应用验证规则,但您并没有对其进行任何处理。

      上述错误示例: Exception page

      场景 2 的控制器:

       @RequestMapping("processForm")
          public String processFormData(@Valid @ModelAttribute("employee") Employee employee,
      BindingResult bindingResult){
                      return bindingResult.hasErrors() ? "employee-form" : "employee-confirmation-page";
                  }
      

      在这种情况下,您将该验证的所有结果传递给 bindingResult,因此由您决定如何处理该表单的验证结果。

      场景 3 的控制器:

      @RequestMapping("processForm")
          public String processFormData(@Valid @ModelAttribute("employee") Employee employee){
                      return "employee-confirmation-page";
                  }
      @ExceptionHandler(MethodArgumentNotValidException.class)
      @ResponseStatus(HttpStatus.BAD_REQUEST)
      public Map<String, String> invalidFormProcessor(MethodArgumentNotValidException ex){
        //Your mapping of the errors...etc
      }
      

      在这种情况下,您仍然没有像第一种情况那样处理错误,而是将其传递给另一个方法,该方法将处理 @Valid 在处理表单模型时触发的异常.检查this 看看如何处理映射等等。

      总结:@Valid 本身不会触发验证 JSR 303 注释字段的验证(@NotNull、@Email、@Size 等... ),您仍然需要指定如何处理上述验证结果的策略。

      希望我能够为可能遇到此问题的人澄清一些问题。

      【讨论】:

        【解决方案8】:

        只是添加到上面的答案,在网络应用程序中 @valid 用于要验证的 bean 也使用验证注释进行注释的情况,例如@NotNull, @Email(hibernate annotation) 所以当从用户获取输入时,可以验证值,绑定结果将具有验证结果。 bindingResult.hasErrors() 将告知是否有任何验证失败。

        【讨论】:

          【解决方案9】:

          上面没有提到的@Valid 的另一个方便的方面是(即:使用 Postman 测试端点)@Valid 会将不正确的 REST 调用的输出格式化为格式化的 JSON,而不是一团几乎不可读的文本。如果您正在为用户创建可商用的 API,这将非常有用。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-05-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-12-31
            • 1970-01-01
            • 2015-01-04
            相关资源
            最近更新 更多