105

在下面的示例中,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();        
}    
4

9 回答 9

74

这是出于验证目的。

验证 在将用户输入绑定到模型后验证模型是很常见的。Spring 3 支持使用 JSR-303 进行声明式验证。如果您的类路径中存在 JSR-303 提供程序(例如 Hibernate Validator),则会自动启用此支持。启用后,您只需使用@Valid 注解注解Controller 方法参数即可触发验证:绑定传入的POST 参数后,AppointmentForm 将被验证;在这种情况下,要验证日期字段值不为空并且将来发生。


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

于 2010-08-29T14:51:59.060 回答
42

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

    @RequestMapping(value = "/appointments", method = RequestMethod.POST)
    public String add(@Valid AppointmentForm form, BindingResult result) {
        ....
    }

    static class AppointmentForm {

        @NotNull @Future
        private Date date;
    }
于 2015-10-07T00:31:30.167 回答
23

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

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

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

于 2017-11-09T12:56:00.413 回答
19

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

于 2010-08-29T14:56:00.550 回答
12

我想添加更多关于@Valid工作原理的细节,尤其是在春天。

https://reflectoring.io/bean-validation-with-spring-boot/中清楚详细地解释了您想了解的有关春季验证的所有内容,但我将复制@Valid链接的工作原理的答案下跌降落。

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

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

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

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

@RestController
class ValidateRequestBodyController {

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

}

所以这是一个包含请求主体的 POST 请求,我们将该请求主体映射到一个 class 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.

于 2020-12-08T15:45:22.123 回答
3
public String create(@Valid @NotNull ScriptFile scriptFile, BindingResult result, ModelMap modelMap) {    
    if (scriptFile == null) throw new IllegalArgumentException("A scriptFile is required");        

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

于 2015-11-08T04:50:29.310 回答
3

我想我知道你的问题在哪里。由于这个问题是谷歌搜索主要结果中弹出的问题,我可以对@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";
    }

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

所述错误的示例: 异常页面

场景 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在处理表单模型时触发的异常。检查这个看看如何处理映射和所有这些。

总结一下:@Valid 本身不做更多的事情来触发验证 JSR 303 注释字段的验证(@NotNull、@Email、@Size 等...),您仍然需要指定要做什么的策略与所述验证的结果。

希望我能够为可能会遇到这种情况的人清除一些东西。

于 2020-10-20T20:51:32.833 回答
2

只需添加到上面的答案,在 Web 应用程序 @valid中,要验证的 bean 也使用验证注释进行注释@NotNull,例如@Email(休眠注释),因此当从用户获取输入时,可以验证值并且绑定结果将具有验证结果。 bindingResult.hasErrors()将告诉是否有任何验证失败。

于 2015-06-23T07:00:03.063 回答
1

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

于 2019-01-12T16:00:53.653 回答