1.概述
在本快速教程中,我们将重点介绍Spring中@Valid和@Validated注解之间的区别。
验证用户输入是我们大多数应用程序中的常见功能。在Java生态系统中,我们专门使用Java标准Bean验证API来支持此功能。而且,从4.0版本开始,它也与Spring很好地集成在一起。 @Valid和@Validated注解源自此Standard Bean API 。
在下一节中,我们将详细介绍它们。
2. @Valid
和@Validated
注解
在Spring中,我们使用JSR-303的**@Valid批注进行方法级别验证。此外,我们还使用它来标记成员属性以进行验证**。但是,此注释不支持组验证。
组有助于限制验证期间应用的约束。 UI向导是一种特殊的用例。在这里,第一步,我们可能有一个特定的字段子组。在后续步骤中,可能存在另一个属于同一bean的组。因此,我们需要在每个步骤中对这些有限的字段应用约束,但是@Valid不支持此约束。
在这种情况下,**对于组级别,我们必须使用Spring的@Validated,**这是此JSR-303的@Valid的变体。在方法级别使用。为了标记成员属性,我们继续使用@Valid批注。
现在,让我们深入研究一下,并通过示例查看这些注释的用法。
3.例子
让我们考虑一个使用Spring Boot开发的简单用户注册表单。首先,我们只有name和password属性:
public class UserAccount { @NotNull @Size(min = 4, max = 15) private String password; @NotBlank private String name; // standard constructors / setters / getters / toString }
接下来,让我们看一下控制器。在这里,我们将使用带有@Valid批注的saveBasicInfo方法来验证用户输入:
@RequestMapping(value = "/saveBasicInfo", method = RequestMethod.POST) public String saveBasicInfo( @Valid @ModelAttribute("useraccount") UserAccount useraccount, BindingResult result, ModelMap model) { if (result.hasErrors()) { return "error"; } return "success"; }
现在让我们测试一下这个方法:
@Test public void givenSaveBasicInfo_whenCorrectInput_thenSuccess() throws Exception { this.mockMvc.perform(MockMvcRequestBuilders.post("/saveBasicInfo") .accept(MediaType.TEXT_HTML) .param("name", "test123") .param("password", "pass")) .andExpect(view().name("success")) .andExpect(status().isOk()) .andDo(print()); }
在确认测试成功运行之后,现在让我们扩展功能。下一步的逻辑步骤是将其转换为多步骤注册表格,就像大多数向导一样。第一步, name和password保持不变。在第二步中,我们将获取其他信息,例如age和phone 。因此,我们将使用以下其他字段更新域对象:
public class UserAccount { @NotNull @Size(min = 4, max = 15) private String password; @NotBlank private String name; @Min(value = 18, message = "Age should not be less than 18") private int age; @NotBlank private String phone; // standard constructors / setters / getters / toString }
但是,这一次,我们将注意到先前的测试失败。这是因为我们没有传递age和phone字段,这些字段仍然不在UI的图片中.为了支持此行为,我们将需要组验证和@Validated批注。
为此,我们需要对字段进行分组以创建两个不同的组。首先,我们需要创建两个标记接口。每个组或每个步骤都有一个单独的名称。我们可以参考我们关于组验证的文章来实现此目的。在这里,让我们关注注释中的差异。
第一步将具有BasicInfo接口,第二步将具有AdvanceInfo 。此外,我们将更新UserAccount类以使用这些标记接口,如下所示:
public class UserAccount { @NotNull(groups = BasicInfo.class) @Size(min = 4, max = 15, groups = BasicInfo.class) private String password; @NotBlank(groups = BasicInfo.class) private String name; @Min(value = 18, message = "Age should not be less than 18", groups = AdvanceInfo.class) private int age; @NotBlank(groups = AdvanceInfo.class) private String phone; // standard constructors / setters / getters / toString }
另外,我们现在将更新控制器以使用@Validated注释而不是@Valid :
@RequestMapping(value = "/saveBasicInfoStep1", method = RequestMethod.POST) public String saveBasicInfoStep1( @Validated(BasicInfo.class) @ModelAttribute("useraccount") UserAccount useraccount, BindingResult result, ModelMap model) { if (result.hasErrors()) { return "error"; } return "success"; }
作为此更新的结果,我们的测试现在可以成功运行。现在,我们还要测试这个新方法:
@Test public void givenSaveBasicInfoStep1_whenCorrectInput_thenSuccess() throws Exception { this.mockMvc.perform(MockMvcRequestBuilders.post("/saveBasicInfoStep1") .accept(MediaType.TEXT_HTML) .param("name", "test123") .param("password", "pass")) .andExpect(view().name("success")) .andExpect(status().isOk()) .andDo(print()); }
这也成功运行。因此,我们可以看到**@Validated的用法对于组验证至关重要。 **
接下来,让我们看看@Valid对于触发嵌套属性验证是必不可少的。
4.使用@Valid
批注标记嵌套对象
批注标记嵌套对象@Valid批注特别用于标记嵌套属性。这触发了嵌套对象的验证。例如,在我们当前的场景中,让我们创建一个UserAddress对象:
public class UserAddress { @NotBlank private String countryCode; // standard constructors / setters / getters / toString }
为了确保验证此嵌套对象,我们将使用@Valid批注装饰属性:
public class UserAccount { //... @Valid @NotNull(groups = AdvanceInfo.class) private UserAddress useraddress; // standard constructors / setters / getters / toString }
5.利与弊
让我们看看在Spring中使用@Valid和@Validated批注的一些优缺点。
@Valid批注确保整个对象的验证。重要的是,它执行整个对像图的验证。但是,这为仅需要部分验证的方案带来了问题。
另一方面,我们可以使用@Validated进行组验证,包括上面的部分验证。但是,在这种情况下,经过验证的实体必须知道其使用的所有组或用例的验证规则。在这里,我们混合了各种顾虑,因此这可能会导致产生反模式。
六,结论
在本快速教程中,我们探讨了@Valid和@Validated批注之间的主要区别。
总之,对于任何基本验证,我们将在方法调用中使用JSR @Valid批注。另一方面,对于包括组序列在内的任何组验证,我们都需要在方法调用中使用Spring的@Validated批注。还需要@Valid批注来触发嵌套属性的验证。
0 评论