Java 驗證列表註釋
1. 概述
在下面的教程中,我們將學習[jakarta.validations.constraints .](https://jakarta.ee/specifications/bean-validation/3.0/apidocs/jakarta/validation/constraints/package-summary)
包下提供的註釋的List
變體的實用程序。此註釋有助於在字段上應用類似類型的驗證。這也使我們能夠在同一字段上顯示不同的驗證消息。
讓我們通過一個用例及其實現來詳細了解這一點。
2. 用例詳細信息
在此用例中,我們將開發一個 Java 程序,用於驗證作為職位申請表的一部分捕獲的字段。有志於工作的人可以通過輸入姓名、工作經驗年限、護照到期日期等個人詳細信息來申請不同的工作級別。該計劃必須驗證以下字段:
字段名稱 | 驗證 | 註解 |
姓名 |
| |
經驗 |
| |
協議 |
| |
護照有效期 |
|
通常, jakarta.validation.constraints
包的@Size
、 @Pattern
、 @Max
、 @Min
、 @AssertTrue
和@Future
註釋在顯示驗證失敗的通用消息時效果很好。但這些註釋的List
變體必須用於滿足最後的驗證要求,如上面每個字段的表中突出顯示的那樣。
不用再等待,讓我們開始實施吧。
3. 用例實現
3.1.概述
為了實現第 2 節中討論的場景,我們創建一個JobAspirant
bean。這個 bean 完成了 90% 的繁重工作。所有字段都使用支持其驗證的註釋進行定義和修飾。在下面使用的註釋中還有一個更重要的屬性,稱為groups
。它在需要驗證的特定環境中應用驗證方面發揮著至關重要的作用。
在這裡,我們不打算介紹如何使用驗證框架的先決條件。此外,本文給出的解釋應該為讀者探索更多類似性質的其他註釋提供良好的開端。
因此,在後續部分中,我們將完成對 JobAspirant bean 的每個字段應用驗證的步驟。
3.2.標記接口
標記接口Senior.class
、 MidSenior.class
和Junior.class
在根據工作級別應用正確的驗證方面發揮了重要作用。還有一個更重要的標記接口AllLevel.class
,它就像一個通用信號說“嘿,無論工作級別如何,都必須應用此驗證!” 。它們被分配給註釋的groups
屬性,以使驗證正常工作。讓我們看看它們:
public interface AllLevels {}
public interface Junior {}
public interface MidSenior {}
public interface Senior {}
3.3.使用@Size.List
和@Pattern.List
驗證名稱
為了在name
字段上應用不同的驗證,我們在 Pattern.List 中廣泛使用了正則表達式和@Pattern
註釋Pattern.List.
此外,通過在Size.List
中使用@Size
註釋,我們對name
應用了最小和最大限制。為了理解這一點,讓我們看一下應用於name
字段的註釋:
@Size.List({
@Size(min = 5, message = "Name should have at least 5 characters", groups = AllLevels.class),
@Size(max = 20, message = "Name should have at most 20 characters", groups = AllLevels.class)
})
@Pattern.List({
@Pattern(regexp = "^[\\p{Alpha} ]*$", message = "Name should contain only alphabets and space", groups = AllLevels.class),
@Pattern(regexp = "^[^\\s].*$", message = "Name should not start with space", groups = AllLevels.class),
@Pattern(regexp = "^.*[^\\s]$", message = "Name should not end with space", groups = AllLevels.class),
@Pattern(regexp = "^((?! ).)*$", message = "Name should not contain consecutive spaces", groups = AllLevels.class),
@Pattern(regexp = "^[^az].*$", message = "Name should not start with a lower case character", groups = AllLevels.class)
})
private String name;
以下是我們對名稱字段應用驗證的方法:
@Test
public void whenInvalidName_thenExpectErrors() throws ParseException {
JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam", "2025-12-31", 17, true);
Set<ConstraintViolation<JobAspirant>> violations = validator.validate(jobAspirant, Senior.class, AllLevels.class);
assertThat(violations.size()).isEqualTo(1);
violations.forEach(action -> {
assertThat(action.getPropertyPath().toString()).isEqualTo("name");
assertThat(action.getMessage()).isEqualTo("Name should not contain consecutive spaces");
});
}
3.4.使用@Min.List
和@Max.List
驗證經驗
**我們可以使用@Min.List
和@Max.List.
**因此,以下是JobAspirant
bean 中的註釋:
@Min.List({
@Min(value = 15, message = "Years of experience cannot be less than 15 Years", groups = Senior.class),
@Min(value = 10, message = "Years of experience cannot be less than 10 Years", groups = MidSenior.class),
@Min(value = 5, message = "Years of experience cannot be less than 5 Years", groups = Junior.class)
})
@Max.List({
@Max(value = 20, message = "Years of experience cannot be more than 20 Years", groups = Senior.class),
@Max(value = 15, message = "Years of experience cannot be more than 15 Years", groups = MidSenior.class),
@Max(value = 10, message = "Years of experience cannot be more than 10 Years", groups = Junior.class)
})
private Integer experience;
讓我們看看@Min
註釋的實際效果:
@Test
public void givenJobLevelJunior_whenInValidMinExperience_thenExpectErrors() throws ParseException {
JobAspirant jobAspirant = getJobAspirant("Junior", "John Adam", "2025-12-31", 3, true);
Set<ConstraintViolation<JobAspirant>> violations = validator.validate(jobAspirant, Junior.class);
assertThat(violations.size()).isEqualTo(1);
violations.forEach(action -> {
assertThat(action.getPropertyPath().toString()).isEqualTo("experience");
assertThat(action.getMessage()).isEqualTo("Years of experience cannot be less than 5 Years");
});
}
現在,我們在這裡檢查@Max
註釋在JobAspirant
bean 中的作用:
@Test
public void givenJobLevelJunior_whenInValidMaxExperience_thenExpectErrors() throws ParseException {
JobAspirant jobAspirant = getJobAspirant("Junior", "John Adam", "2025-12-31", 11, true);
Set<ConstraintViolation<JobAspirant>> violations = validator.validate(jobAspirant, Junior.class);
assertThat(violations.size()).isEqualTo(1);
violations.forEach(action -> {
assertThat(action.getPropertyPath().toString()).isEqualTo("experience");
assertThat(action.getMessage()).isEqualTo("Years of experience cannot be more than 10 Years");
});
}
3.5.使用@AssertTrue.List
驗證協議
我們看一下字段agreement,
它是一個布爾值。通常,布爾值可以是 true 或 false,那麼這個驗證有什麼特別之處呢?如果我們想為不同的工作級別顯示單獨的消息怎麼辦?這就是我們使用@AssertTrue.List
處理此問題的方式:
@AssertTrue.List({
@AssertTrue(message = "Terms and Conditions consent missing for Senior Level Job Application", groups = Senior.class),
@AssertTrue(message = "Terms and Conditions consent missing for Mid-Senior Level Job Application", groups = MidSenior.class),
@AssertTrue(message = "Terms and Conditions consent missing for Junior Level Job Application", groups = Junior.class)
})
private Boolean agreement;
讓我們檢查一下正在執行的高級工作的agreement
字段的驗證:
@Test
public void givenSeniorLevel_whenInvalidAgreement_thenExpectErrors() throws ParseException {
JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam", "2025-12-31", 17, false);
Set<ConstraintViolation<JobAspirant>> violations = validator.validate(jobAspirant, Senior.class);
assertThat(violations.size()).isEqualTo(1);
violations.forEach(action -> {
assertThat(action.getPropertyPath().toString()).isEqualTo("agreement");
assertThat(action.getMessage()).isEqualTo("Terms and Conditions consent missing for Senior Level Job");
});
}
3.6.使用@Future.List
驗證護照到期日期
同樣,這種驗證也可以擴展到其他類型的字段,例如passportExpiryDate,
其類型為 Date 。為了確保我們針對不同職位級別的過期護照顯示單獨的消息,我們使用@Future.List
:
@Future.List({
@Future(message = "Active passport is mandatory for Senior Level Job Application", groups = Senior.class),
@Future(message = "Active passport is mandatory for Mid-Senior Level Job Application", groups = MidSenior.class),
@Future(message = "Active passport is mandatory for Junior Level Job Application", groups = Junior.class)
})
private Date passportExpiryDate;
這是正在運行的註釋:
@Test
public void givenJobLevelMidSenior_whenInvalidPassport_thenExpectErrors() throws ParseException {
JobAspirant jobAspirant = getJobAspirant("MidSenior", "John Adam", "2021-12-31", 12, true);
Set<ConstraintViolation<JobAspirant>> violations = validator.validate(jobAspirant, MidSenior.class);
assertThat(violations.size()).isEqualTo(1);
violations.forEach(action -> {
assertThat(action.getPropertyPath().toString()).isEqualTo("passportExpiryDate");
assertThat(action.getMessage()).isEqualTo("Active passport is mandatory for Mid-Senior Level Job");
});
}
4。結論
在本教程中,我們學習瞭如何使用驗證註釋的 List 變體以及 groups 屬性來在不同上下文中的同一字段上有效地應用不同的驗證。此外,這裡給出的示例足以讓讀者自己探索更多其他 List 註釋。
與往常一樣,本文中顯示的所有示例都可以在 GitHub 上找到。