本文翻譯自 Java Bean Validation Basics
概述
在這個文章裡,我們簡單介紹一如何使用标準校驗架構來完成基本的Java Bean校驗,該架構即JSR380,也被稱為Bean Validation 2.0。
校驗使用者輸入,在大多是應用程式中是超級常見的需求,Java Bean校驗架構即是處理這部分邏輯的标準工具。
JSR308-Bean Validation 2.0
JSR 308是JavaBean校驗API規範,它是JavaEE和JavaSE的一部分。該規範使用@NotNull,@Min和@Max這樣的注解來確定一個Bean的屬性符合特定的條件。
這個版本要求使用Java8或更高版本,利用Java8提供的新特性例如類型注解,并且支援新的類型例如Optional和LocalDate。
要獲得更完整的資訊,可以進一步閱讀
JSR 308的文檔。
依賴
- JSR 308規範的的标準API包含在validation-api中:
<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency>
- Hibernate Validator是validation-api的參考實作:
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.2.Final</version> </dependency>
另外,Hibernate Validator還提供了一個注解處理器,利用Java編譯時注解處理機制,幫助開發人員發現校驗注解使用的錯誤。僅需要添加如下依賴即可:
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>6.0.2.Final</version>
<scop>provided</scop>
</dependency>
hibernate-validator與hibernate的持久化架構支援是完全分離的,引入hibnernate-validator依賴并不會間接引入hibernate持久化相關的依賴。
- 表達式語言依賴
JSR 308規範支援違約資訊的變量解析,并允許使用表達式。
為了解析表達式,我們必須添加表達式語言API和它的某個實作,GlassFish項目提供了表達式語言API的參考實作:
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.6</version>
</dependency>
如果沒有添加這些依賴到應用中,您會在運作時得到如下錯誤資訊:
HV000183: Unable to load ‘javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead
使用校驗注解
我們在這裡使用UserBean作為例子,為它添加一些簡單的校驗。
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.validation.constraints.Email;
public class User {
@NotNull(message = "Name cannot be null")
private String name;
@AssertTrue
private boolean working;
@Size(min = 10, max = 200, message
= "About Me must be between 10 and 200 characters")
private String aboutMe;
@Min(value = 18, message = "Age should not be less than 18")
@Max(value = 150, message = "Age should not be greater than 150")
private int age;
@Email(message = "Email should be valid")
private String email;
// standard setters and getters
}
該例子中使用的所有注解都是标準JSR注解:
- @NotNull-校驗被注解的屬性不能為null
- @AssertTrue-校驗被注解的屬性值必須為true
- @Size-校驗被注解的屬性的尺寸必須在min和max之間,該注解可以在String,Collection,Map和數組屬性上使用
- @Min,@Max-校驗備注解的屬性值必須大于或小于指定的值
- @Email-校驗備注接的屬性必須是有效的emal位址
JSR中還包含其他一些注解:
- @NotEmpty-校驗屬性不能為null或空;可以在String,Collection,Map或數組類型屬性上使用
- @NotBlank-隻能使用在文本類型的屬性上,校驗該屬性不能為null或空白
- @Positive,@PositiveOrZero-使用在數值屬性上,校驗該屬性必須為正數或0
- @Negative,@NegativeOrZero-使用在數值屬性上,校驗該屬性必須為負數或0
- @Past,@PastOrPresent-校驗日期類型值必須是過去的時間或現在;支援Java8中新增加的日期類型,例如LocalDateTime
- @Future,@FutureOrPresent-校驗日期類型值必須在未來或現在
所有注解都可以設定messge屬性,這個屬性的值在校驗失敗時被用來渲染違約消息。
Validation-API提供的标準注解的message屬性大都有預設值,使用者如無特别需求,無須設定該屬性。
校驗注解可以施加在集合的元素上
List<@NotBlank String> preferences;
在這個例子中,集合中的的所有元素都會被校驗不能為null或空白
規範也支援Java8中新增的Optional類型:
private LocalDate dateOfBirth;
public Optional<@Past LocalDate> getDateOfBirth() {
return Optional.of(dateOfBirth);
}
這個例子中,校驗架構會自動将LocalDate值取出并校驗。
程式設計校驗
- 一些架構,例如Spring,僅僅使用注解即可出發校驗過程。讓我們不必直接程式設計使用校驗API。但我們應當對其有所了解,以了解架構的運作原理。
下面讓我們來手動程式設計配置一個校驗環境:
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
我們必須首先建構一個校驗器(validator)對象,才能校驗一個Bean。
- 定義一個待校驗的Bean
User user = new User(); user.setWorking(true); user.setAboutMe("Its all about me!"); user.setAge(50);
- 對上面定義的Bean進行校驗
Set<ConstraintViolation<User>> violations = validator.validate(user);
将user對象作為validate方法的參數傳遞給校驗器對象,所有違背User對象定義的限制條件的資訊包裝為ConstraintViolation對象集合傳回。
周遊違約資訊,我們可以得到所有的違約消息
for (ConstraintViolation<User> violation : violations) {
log.error(violation.getMessage());
}
在我們的例子中,違約對象集合中隻會包含一個違約資訊,“Name cannot be null”。
這個違約消息可以通過校驗注解的message屬性進行定義。
總結
本教程聚焦于标準Java校驗API的基本内容,展示了使用基本javax.validation注解和API的使用方法。
所有的示例代碼可以在
GitHub上擷取。