子物件上的@Valid註釋
一、簡介
在本教程中,我們將了解如何使用@Valid註解來驗證物件及其巢狀子物件。
當傳入資料是基本資料類型(例如整數或字串)時,驗證傳入資料可能很簡單。但是,當傳入資訊是物件(特別是物件圖)時,這可能會更加困難。幸運的是, @Valid註解簡化了巢狀子物件的驗證。
2.什麼是@Valid註解?
@Valid註釋來自Jakarta Bean Validation規範,標記用於驗證的特定參數。
使用此註解可確保傳遞至方法或儲存在欄位中的資料符合指定的驗證規則。這有助於我們促進資料完整性和一致性。
當用於JavaBean的欄位或方法時,它會觸發所有定義的約束檢查。 Bean Validation API 中最常使用的一些約束是@NotNull, @NotBlank, @NotEmpty, @Size, @Email, @Pattern, etc 。
3. 如何在子物件上使用@Valid註解
首先,我們必須確定驗證規則並將前面提到的驗證約束應用於欄位。
接下來,我們定義一個代表項目的類,它包含一個嵌套的User對象,我們將使用@Valid註釋來裝飾該對象:
public class User {
@NotBlank(message = "User name must be present")
@Size(min = 3, max = 50, message = "User name size not valid")
private String name;
@NotBlank(message = "User email must be present")
@Email(message = "User email format is incorrect")
private String email;
// omitted constructors, getters and setters
}
public class Project {
@NotBlank(message = "Project title must be present")
@Size(min = 3, max = 20, message = "Project title size not valid")
private String title;
@Valid
private User owner;
// omitted constructors, getters and setters
}
之後,我們將透過簡單地使用Validator實例上的validate()方法來執行驗證。讓我們確保子物件通過測試進行驗證:
@Test
public void whenInvalidProjectAndUser_thenAssertConstraintViolations() {
Project project = new Project(null);
project.setOwner(new User(null, "invalid-email"));
List<String> messages = validate(project);
assertEquals(3, messages.size());
assertTrue(messages.contains("Project title must be present"));
assertTrue(messages.contains("User name must be present"));
assertTrue(messages.contains("User email format is incorrect"));
}
private List<String> validate(Project project) {
return validator.validate(project)
.stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.toList());
}
此外,使用@Valid註釋的 Bean 驗證可以與 Spring 和 Jakarta EE 等框架完美配合。透過在控制器類別的方法參數上使用註釋,我們可以在進入控制器方法之前執行驗證,這非常適合保持資料一致。
4.了解對象圖驗證
現在我們已經了解瞭如何使用@Valid ,讓我們更好地理解它為什麼這樣工作。在物件具有其他嵌套物件的情況下,我們必須應用一種稱為物件圖驗證的機制。
此機制驗證物件圖中相關物件的完整結構。當父物件為 時,所有以@Valid註解的子物件(及其子物件)都會被驗證。換句話說,驗證是在整個圖中遞歸應用的。
此圖遍歷的結果,我們得到ConstraintViolations作為一個集合,其中包含來自嵌套物件的所有組合驗證違規。
因為我們遞歸地驗證圖中的每個對象,所以我們可能會遇到循環引用的問題,其中對像在循環中相互引用。這可能會讓我們陷入無限循環,不斷重複驗證相同的物件。
幸運的是,Jakarta Bean Validation 包含定義驗證路徑的概念,該路徑被描述為從根物件開始的@Valid關聯序列。此實作從根物件開始追蹤當前路徑中已驗證的每個實例。如果相同實例在給定的導航路徑中出現多次,驗證例程將忽略它,從而防止無限循環。
5. 子對象的註解用法
現在我們知道如何使用@Valid註釋以及它在表面下如何工作,讓我們檢查一下可以使用它的所有地方。我們將研究在容器物件中的嵌套實例、集合和類型參數上使用@Valid 。
5.1.使用@Valid驗證嵌套實例
驗證巢狀實例的一種方法是使用欄位存取策略,這與我們在上一個範例中驗證Project內的巢User物件的方法相同。簡單地說,我們使用@Valid註釋來裝飾該字段,並將該實例添加到導航路徑中:
@Valid
private User owner;
類似地,驗證嵌套實例的另一種方法是使用屬性存取策略,這意味著我們可以將@Valid放在存取屬性狀態的 getter 方法上:
@Valid
public User getOwner() {
return owner;
}
5.2.使用@Valid驗證可迭代對象
集合、陣列或java.lang.Iterebale介面的任何其他實作都符合@Valid註解的條件。如果我們在這種情況下進行註釋,我們將遵循相同的規則對Iterable的每個元素應用驗證。
重要的是要知道,如果集合是java.util.Map介面的實現,則只會驗證值。我們必須專門註釋鍵來觸發它們的驗證。
例如,讓我們檢查一個驗證鍵和值的Map :
private Map<@Valid User, @Valid Task> assignedTasks;
5.3.在容器物件和類型參數上使用註釋
在容器物件和類型參數上應用註解非常相似,讓我們先看看如何操作:
@Valid
private List<Task> tasks;
private List<@Valid Task> tasks;
第一個範例向我們展示了在容器上使用註釋,而第二個範例則直接在類型參數上使用。在這種情況下,沒有什麼區別,它們都按照我們的預期工作。通常,我們應該避免在這兩個地方使用它,因為這可能會導致容器元素被驗證兩次。
正如我們所看到的,在這些情況下使用註釋很靈活,但它們並不總是按照我們希望的方式工作。如果我們有嵌套的通用容器,為了驗證容器的內容,我們必須在內部容器的類型參考上套用註釋。
讓我們來看一個List嵌套在Map中的範例:
private Map<String, List<@Valid Task>> taskByType;
六,結論
在本文中,我們了解了@Valid註解是什麼、如何使用它對子物件執行驗證以及物件圖驗證的工作原理。
@Valid註釋是一個強大的工具,我們可以在不同的地方使用它來確保事物按預期進行驗證。這很棒,因為它會自動檢查圖中每個經過驗證的對象,使我們的工作變得更輕鬆。
與往常一樣,範例程式碼可在 GitHub 上取得。