在以下示例中,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();
}
这是出于验证目的。
验证 在将用户输入绑定到模型后验证模型是很常见的。 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/
添加到上述答案,看看以下。 AppointmentForm
的 date
列带有几个注释。通过在 AppointmentForm
(在本例中为 @NotNull
和 @Future
)上触发验证的 @Valid
注释。这些注释可能来自不同的 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
)字段上触发了验证。请解释。
@Valid
本身与 Spring 无关。它是 Bean Validation 规范的一部分(其中有几个,截至 2017 年下半年,最新的是 JSR 380),但 @Valid
非常古老,并且一直从 JSR 303 派生而来。
众所周知,Spring 非常擅长提供与所有不同 JSR 和一般 Java 库的集成(想想 JPA、JTA、缓存等),当然这些人也负责验证。促成这一点的关键组件之一是 MethodValidationPostProcessor。
尝试回答您的问题 - 当您想要验证复杂图形而不仅仅是对象的顶级元素时,@Valid
对于所谓的验证级联非常方便。每次想要更深入时,都必须使用 @Valid
。这就是 JSR 所规定的。 Spring 将遵守这一点,但会有一些细微的偏差(例如,我尝试将 @Validated
而不是 @Valid
放在 RestController 方法和验证工作上,但同样不适用于常规的“服务”bean)。
ScriptFile scriptFile
上执行什么验证。
IIRC @Valid 不是 Spring 注释,而是 JSR-303 注释(这是 Bean 验证标准)。它的作用是基本上检查您发送给该方法的数据是否有效(它将为您验证 scriptFile)。
我想添加有关 @Valid
工作原理的更多详细信息,尤其是在春季。
您想了解的有关春季验证的所有信息都在 https://reflectoring.io/bean-validation-with-spring-boot/ 中进行了清楚而详细的解释,但如果链接断开,我将复制 @Valid
如何工作的答案。
可以将 @Valid
注释添加到 rest 控制器方法中的变量以验证它们。可以验证的变量有 3 种类型:
请求正文,
路径中的变量(例如 /foos/{id} 中的 id)和,
查询参数。
那么现在......弹簧如何“验证”?您可以通过使用某些注释来注释类的字段来定义对它们的约束。然后,将该类的一个对象传递给一个验证器,该验证器检查是否满足约束。
例如,假设我有这样的控制器方法:
@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
。
public String create(@Valid @NotNull ScriptFile scriptFile, BindingResult result, ModelMap modelMap) {
if (scriptFile == null) throw new IllegalArgumentException("A scriptFile is required");
我猜这个 @NotNull
注释是有效的,因此如果不需要条件。
我想我知道你的问题在哪里。由于这个问题是谷歌搜索主要结果中弹出的问题,我可以对@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 等)的验证,您仍然需要指定要做什么的策略与所述验证的结果。
希望我能够为可能会遇到这种情况的人清除一些东西。
只是添加到上面的答案中,在 Web 应用程序中使用 @valid
,其中要验证的 bean 也使用验证注释进行注释,例如 @NotNull
、@Email
(休眠注释),因此当从用户获取输入时,值可以被验证并且绑定结果将具有验证结果。 bindingResult.hasErrors()
将告知是否有任何验证失败。
上面没有提到的@Valid 的另一个方便方面是(即:使用 Postman 测试端点)@Valid 会将不正确的 REST 调用的输出格式化为格式化的 JSON,而不是一团几乎不可读的文本。如果您正在为您的用户创建可商用的 API,这将非常有用。
不定期副业成功案例分享
ScriptFile
类为类数据成员(如@NotNull
、@NotEmpty
等)定义了一些约束,并且@Valid
指示框架(在我们的例子中是 spring)在有人调用您的方法时根据提供的参数检查这些约束。在这种情况下,如果验证失败,服务器会以HTTP 400 Bad Request
状态代码进行响应。