Spring中@Valid和@Validated註解的差異
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
批註來觸發嵌套屬性的驗證。
與往常一樣,本文提供的代碼可從GitHub上獲得。