拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 Spring中@Valid和@Validated注解的差异

Spring中@Valid和@Validated注解的差异

白鹭 - 2021-11-14 2213 0 2

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 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *