張 冠楠 和 陳 志娴
2011 年 3 月 24 日釋出

2
Bean 是 Java Bean 的縮寫,在 Java 分層架構的實際應用中,從表示層到持久化層,每一層都需要對 Java Bean 進行業務符合性驗證,如圖 1 所示。然而對于同一個 Java Bean 的對象,在每一層都需要實作同樣的驗證邏輯時,這将是一項耗時且容易誘發錯誤的做法。Bean Validation 規範的目标就是避免多層驗證的重複性。事實上,開發者更傾向于将驗證規則直接放到 Java Bean 本身,使用注解的方式進行驗證規則的設計。
JSR303 規範(Bean Validation 規範)提供了對 Java EE 和 Java SE 中的 Java Bean 進行驗證的方式。該規範主要使用注解的方式來實作對 Java Bean 的驗證功能,并且這種方式會覆寫使用 XML 形式的驗證描述符,進而使驗證邏輯從業務代碼中分離出來,如圖 2 所示。
JSR303 規範提供的 API 是 Java Bean 對象模型的一般擴充,它并不局限于某一層或者某一程式設計模型,在伺服器端和用戶端都可使用,其最大的特點就是易用而且靈活。
Hibernate Validator 4.0 是 JSR303 規範的參考實作,本文所有示例代碼均使用該參考實作。
下面給出一個 Bean Validation 的簡單示例(清單 1):
1
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<code>public class Employee {</code>
<code>@NotNull(message = "The id of employee can not be null")</code>
<code>private Integer id;</code>
<code>@NotNull(message = "The name of employee can not be null")</code>
<code>@Size(min = 1,max = 10,message="The size of employee's name must between 1 and 10")</code>
<code>private String name;</code>
<code>public int getId() {</code>
<code>return id;</code>
<code>}</code>
<code>public void setId(int id) {</code>
<code>this.id = id;</code>
<code>public String getName() {</code>
<code>return name;</code>
<code>public void setName(String name) {</code>
<code>this.name = name;</code>
<code>public static void main(String[] args) {</code>
<code>Employee employee = new Employee();</code>
<code>employee.setName("Zhang Guan Nan");</code>
<code>ValidatorFactory vf = Validation.buildDefaultValidatorFactory();</code>
<code>Validator validator = vf.getValidator();</code>
<code>Set<</code><code>ConstraintViolation</code><code><Employee>> set = validator.validate(employee);</code>
<code>for (ConstraintViolation<</code><code>Employee</code><code>> constraintViolation : set) {</code>
<code>System.out.println(constraintViolation.getMessage());</code>
運作該示例的輸出結果為:
The size of employee's name must between 1 and 10
The id of employee can not be null
從示例中可以看出,Bean Validation 使用注解(@NotNull 和 @Size)的方式對字段 id 和 name 進行了限制聲明,當該 Java Bean 被實際使用時,相關的驗證器就會對該類的執行個體進行驗證確定其符合該限制聲明。完成 Java Bean 的驗證通常可分為如下四個步驟:
限制注解的定義
限制驗證規則(限制驗證器)
限制注解的聲明
限制驗證流程
本文第二大部分将詳細介紹限制注解的定義和限制驗證規則;第三大部分将詳細介紹限制注解的聲明和限制驗證流程;第四大部分将介紹 JSR303 規範提供的 API。
Bean Validation 規範對限制的定義包括兩部分,一是限制注解,清單 1 中的 @NotNull 就是限制注解;二是限制驗證器,每一個限制注解都存在對應的限制驗證器,限制驗證器用來驗證具體的 Java Bean 是否滿足該限制注解聲明的條件。
在 Java Bean 中,對某一方法、字段、屬性或其組合形式等進行限制的注解,即為限制注解,如清單 2 所示:
清單 2 的含義為:對于字段 id,在 Java Bean 的執行個體中值不能為空。對于每一個限制注解,在實際使用前必須有相關定義。JSR303 規範預設提供了幾種限制注解的定義(見表 1),我們也可以擴充規範提供的 API,實作符合自身業務需求的限制注解。
限制注解名稱
限制注解說明
@Null
驗證對象是否為空
@NotNull
驗證對象是否為非空
@AssertTrue
驗證 Boolean 對象是否為 true
@AssertFalse
驗證 Boolean 對象是否為 false
@Min
驗證 Number 和 String 對象是否大等于指定的值
@Max
驗證 Number 和 String 對象是否小等于指定的值
@DecimalMin
驗證 Number 和 String 對象是否大等于指定的值,小數存在精度
@DecimalMax
驗證 Number 和 String 對象是否小等于指定的值,小數存在精度
@Size
驗證對象(Array,Collection,Map,String)長度是否在給定的範圍之内
@Digits
驗證 Number 和 String 的構成是否合法
@Past
驗證 Date 和 Calendar 對象是否在目前時間之前
@Future
驗證 Date 和 Calendar 對象是否在目前時間之後
@Pattern
驗證 String 對象是否符合正規表達式的規則
限制注解和普通的注解一樣,一個典型的限制注解的定義應該至少包括如下内容(清單 3):
<code>@Target({ }) // 限制注解應用的目标元素類型</code>
<code>@Retention() // 限制注解應用的時機</code>
<code>@Constraint(validatedBy ={}) // 與限制注解關聯的驗證器</code>
<code>public @interface ConstraintName{</code>
<code>String message() default " "; // 限制注解驗證時的輸出消息</code>
<code>Class<?>[] groups() default { }; // 限制注解在驗證時所屬的組别</code>
<code>Class<?</code><code>extends</code> <code>Payload>[] payload() default { }; // 限制注解的有效負載</code>
限制注解應用的目标元素類型包括 METHOD, FIELD, TYPE, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER。METHOD 限制相關的 getter 方法;FIELD 限制相關的屬性;TYPE 限制具體的 Java Bean;ANNOTATION_TYPE 用在組合限制中;該規範同樣也支援對參數(PARAMETER)和構造器(CONSTRUCTOR)的限制。
驗證時的組别屬性将在本文第三大部分中組與組序列中詳細介紹。
有效負載通常用來将一些中繼資料資訊與該限制注解相關聯,常用的一種情況是用負載表示驗證結果的嚴重程度。
清單 4 給出一個驗證字元串非空的限制注解的定義:
<code>@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })</code>
<code>@Retention(RUNTIME)</code>
<code>@Documented</code>
<code>@Constraint(validatedBy = {NotEmptyValidator.class})</code>
<code>public @interface NotEmpty {</code>
<code>String message() default "this string may be empty";</code>
<code>Class<?>[] groups() default { };</code>
<code>Class<?</code><code>extends</code> <code>Payload>[] payload() default {};</code>
限制注解定義完成後,需要同時實作與該限制注解關聯的驗證器。限制驗證器的實作需要擴充 JSR303 規範提供的接口 javax.validation.ConstraintValidator。清單 5 給出該接口。
<code>public interface ConstraintValidator<</code><code>A</code> <code>extends Annotation, T> {</code>
<code>void initialize(A constraintAnnotation);</code>
<code>boolean isValid(T value, ConstraintValidatorContext context);</code>
該接口有兩個方法,方法 initialize 對驗證器進行執行個體化,它必須在驗證器的執行個體在使用之前被調用,并保證正确初始化驗證器,它的參數是限制注解;方法 isValid 是進行限制驗證的主體方法,其中 value 參數代表需要驗證的執行個體,context 參數代表限制執行的上下文環境。
對于清單 4 定義的限制注解,清單 6 給出了與該注解對應的驗證器的實作。
<code>public class NotEmptyValidator implements ConstraintValidator<</code><code>NotEmpty</code><code>, String>{</code>
<code>public void initialize(NotEmpty parameters) {</code>
<code>public boolean isValid(String string,</code>
<code> </code><code>ConstraintValidatorContext constraintValidatorContext) {</code>
<code>if (string == null) return false;</code>
<code>else if(string.length()<1) return false;</code>
<code>else return true;</code>
至此,一個可以聲明并使用的限制注解已經定義完畢,清單 7 将給出該限制注解在實際程式中的使用。為節省篇幅,這裡隻給出針對清單 1 的增加和修改内容,未給出全部的示例代碼,您可以在本文的附錄中獲得全部的代碼。
<code>首先在清單 1 中的類 Employee 中加入字段 company 和相應的 getter 和 setter 方法:</code>
<code> </code><code>@NotEmpty</code>
<code> </code><code>private String company;</code>
<code>然後在 main 函數中加入如下代碼清單:</code>
<code> </code><code>String company = new String();</code>
<code> </code><code>employee.setCompany(company);</code>
<code>再次運作該程式,輸出結果為:</code>
<code> </code><code>The id of employee can not be null</code>
<code> </code><code>this string may be empty</code>
<code> </code><code>The size of employee's name must between 1 and 10</code>
下面介紹 Bean Validation 規範的一個特性,多值限制(Multiple Constraints):對于同一個目标元素,在進行限制注解聲明時可以同時使用不同的屬性達到對該目标元素進行多值驗證的目的。如清單 8 所示:
<code>String message() default " ";</code>
<code>Class<?</code><code>extends</code> <code>Payload>[] payload() default { };</code>
<code>@interface List {</code>
<code>ConstraintName[] value();</code>
實作多值限制隻需要在定義限制注解的同時定義一個 List(@interface List{})。使用該限制注解時,Bean Validation 将 value 數組裡面的每一個元素都處理為一個普通的限制注解,并對其進行驗證,所有限制條件均符合時才會驗證通過。
清單 9 定義了一個限制注解,它用來驗證某一字元串是否包含指定的内容。
<code>@Constraint(validatedBy = PatternOfStringValidator.class)</code>
<code>public @interface PatternOfString {</code>
<code>String mustContainLetter();</code>
<code>String message() default "this pattern may not be right";</code>
<code>@Target({ METHOD, FIELD, ANNOTATION_TYPE})</code>
<code>PatternOfString[] value();</code>
該限制注解對應的驗證器如清單 10 所示:
<code>public class PatternOfStringValidator implements ConstraintValidator</code>
<code><</code><code>PatternOfString</code><code>, String> {</code>
<code>private String letterIn;</code>
<code>public void initialize(PatternOfString parameters) {</code>
<code>this.letterIn=parameters.mustContainLetter();</code>
<code>ConstraintValidatorContext constraintValidatorContext) {</code>
<code>if (string.contains(letterIn))</code>
<code>return true;</code>
<code>return false;</code>
如果想驗證某一字元串是否同時包含兩個子串,那麼多值限制就顯得比較重要了,清單 11 将詳細給出多值限制的使用。
<code>在清單 1 中的類 Employee 中增加如下字段 place 以及相應的 getter 和 setter 方法:</code>
<code> </code><code>@PatternOfString.List({</code>
<code> </code><code>@PatternOfString(mustContainLetter = "CH",</code>
<code> </code><code>message = "It does not belong to China"),</code>
<code> </code><code>@PatternOfString(mustContainLetter="MainLand",</code>
<code> </code><code>message="It does not belong to MainLand")})</code>
<code> </code><code>private String place;</code>
<code> </code><code>String place = "C";</code>
<code> </code><code>employee.setPlace(place);</code>
<code> </code><code>It does not belong to MainLand</code>
<code> </code><code>It does not belong to China</code>
<code>如果将 place 指派為 String place = "CHINA",則輸出結果為:</code>
可見,該限制會對聲明的兩個限制注解分别進行驗證,隻要存在不符合限制驗證規則的 Java Bean 執行個體,就将産生相應的驗證失敗資訊。限制注解聲明的時候可以根據不同的限制值使用 message 參數給出不同的輸出資訊。
下面介紹 Bean Validation 規範中另一個重要的特性:組合限制。Bean Validation 規範允許将不同的限制進行組合來建立級别較高且功能較多的限制,進而避免原子級别限制的重複使用。如清單 4 定義的限制注解 @NotEmpty,是用來判斷一個字元串在非空的基礎上長度至少為 1,其實際意義等同于 @NotNull 和 @Size(min=1)的組合形式,是以可以将 @NotEmpty 限制定義為組合限制 NotEmpty2,如清單 12 所示:
<code>@NotNull</code>
<code>@Size(min = 1)</code>
<code>@Constraint(validatedBy = {NotEmptyValidator2.class})</code>
<code>public @interface NotEmpty2 {</code>
<code>NotEmpty2[] value();</code>
實際使用中 @NotEmpty2 限制注解可以得到與 @NotEmpty 限制注解同樣的驗證結果。
本文第二大部分介紹了如何定義限制注解和驗證器,本章主要介紹如何在 Java Bean 中應用存在定義的限制注解,主要包括兩部分:一是限制的聲明;二是限制的驗證流程。
在需要進行限制的目标元素前面用注解的方式即可聲明限制,這意味着該目标元素必須滿足該限制的驗證條件。如清單 13 即在字段 id 上聲明了限制 @NotNull:
該目标元素在具體執行個體中被指派後,Bean Validation 就會調用相關的流程進行驗證。具體使用方式可以參見清單 14 所示,其中所涉及的接口将在本文第四大部分詳細介紹。
<code>Set<</code><code>ConstraintViolation</code><code><Employee>> set = validator.validate(JavaBeanInstance);</code>
Bean Validation 規範對 Java Bean 的驗證流程如下:在實際使用中調用 Validator.validate(JavaBeanInstance) 方法後,Bean Validation 會查找在 JavaBeanInstance上所有的限制聲明,對每一個限制調用對應的限制驗證器進行驗證,最後的結果由限制驗證器的 isValid 方法産生,如果該方法傳回 true,則限制驗證成功,否則驗證失敗。驗證失敗的限制将産生限制違規對象(ConstraintViolation 的執行個體)并放到限制違規清單中。驗證完成後所有的驗證失敗資訊均能在該清單中查找并輸出。
Bean Validation 規範規定在對 Java Bean 進行限制驗證前,目标元素必須滿足以下條件:
如果驗證的是屬性(getter 方法),那麼必須遵從 Java Bean 的命名習慣(JavaBeans 規範);
靜态的字段和方法不能進行限制驗證;
限制适用于接口和基類;
限制注解定義的目标元素可以是字段、屬性或者類型等;
可以在類或者接口上使用限制驗證,它将對該類或實作該接口的執行個體進行狀态驗證;
字段和屬性均可以使用限制驗證,但是不能将相同的限制重複聲明在字段和相關屬性(字段的 getter 方法)上。
除了支援 Java Bean 的執行個體驗證外,Bean Validation 規範同樣支援 Object Graph 的驗證。Object Graph 即為對象的拓撲結構,如對象之間的引用關系。如果類 A 引用類 B,則在對類 A 的執行個體進行限制驗證時也需要對類 B 的執行個體進行限制驗證,這就是驗證的級聯性。當對 Java 語言中的集合、數組等類型進行驗證時也需要對該類型的每一個元素進行驗證。
完成級聯驗證的方式就是使用 @Valid 注解,如清單 15 所示:
<code>public class Person {</code>
<code>@NotEmpty</code>
<code>public class Order {</code>
<code>@Valid</code>
<code>private Person person;</code>
<code>public Person getPerson() {</code>
<code>return person;</code>
<code>public void setPerson(Person person) {</code>
<code>this.person = person;</code>
在對 Order 的執行個體進行驗證時,隻有當在 Order 引用的對象 Person 前面聲明了注解 @Valid,才對 Person 中 name 字段的 @NotEmpty 注解進行驗證,否則将不予驗證。
Bean Validation 規範中一個重要的概念,就是組群組序列。組定義了限制的子集。對于一個給定的 Object Graph 結構,有了組的概念,則無需對該 Object Graph 中所有的限制進行驗證,隻需要對該組定義的一個子集進行驗證即可。完成組别驗證需要在限制聲明時進行組别的聲明,否則使用預設的組 Default.class.
組使用接口的方式進行定義,清單 16 給出了如何定義組并使用組進行限制驗證。
<code>public interface GroupA {}</code>
<code>public class User {</code>
<code>@NotEmpty (message = "firstname may be empty")</code>
<code>private String firstname;</code>
<code>@NotEmpty(message = "middlename may be empty", groups = Default.class)</code>
<code>private String middlename;</code>
<code>@NotEmpty(message = "lastname may be empty",groups = GroupA.class)</code>
<code>private String lastname;</code>
<code>public static void main(String[] args){</code>
<code>User user = new User();</code>
<code>Set<</code><code>ConstraintViolation</code><code><User>> set = validator.validate(user,GroupA.class);</code>
<code>for (ConstraintViolation<</code><code>User</code><code>> constraintViolation : set) {</code>
在類 User 中需要驗證的字段上聲明驗證時所屬的組别屬性,如(groups=GroupA.class), 然後在 main 函數中調用 validator.validate(user,GroupA.class)) 方法,在此必須指定需要驗證的組别。如果不顯示指明,則是預設的組别。
如清單 16,驗證器隻會驗證類 User 的 lastname 字段,如果使用 validator.validate(user)),則會使用 Default.class 組别,進而驗證 firstname 和 middlename 字段。
需要注意的是:組也有繼承的屬性。對某一組别進行限制驗證的時候,也會對其所繼承的基類進行驗證。
組可以進行隐式定義,其好處是可以不必在限制聲明的時候顯式聲明組别屬性,如清單 16 中的(groups=GroupA.class)。清單 17 給出了一個隐式定義的組接口(Animal),其中包含對相應屬性(getter 方法)的限制聲明。相應的 Java Bean(Dog)實作了該接口。
<code>public interface Animal {</code>
<code>@NotEmpty String getName();</code>
<code>@NotEmpty String getOwnerName();</code>
<code>public class Dog implements Animal {</code>
<code>private String ownername;</code>
<code>private String type;</code>
<code>public void setType(String type) {</code>
<code>this.type = type;</code>
<code>return null;</code>
<code>public String getOwnerName() {</code>
<code>@NotEmpty(message = "type of the dog may be empty")</code>
<code>public String getType() {</code>
<code>return type;</code>
這樣在對類 Dog 的執行個體進行驗證的時候,如果使用預設的組别(Default.class),則 name,ownername 和 type 都将進行驗證;如果使用 Animal 的組别,如清單 18 所示,則隻會對 name 和 ownername 屬性進行驗證。
<code>Dog dog = new Dog();</code>
<code>Set<</code><code>ConstraintViolation</code><code><Dog>> set = validator.validate(dog,Animal.class);</code>
<code>for (ConstraintViolation<</code><code>Dog</code><code>> constraintViolation : set) {</code>
輸出結果為:
this string may be empty
預設情況下,不同組别的限制驗證是無序的,然而在某些情況下,限制驗證的順序卻很重要,如下面兩個例子:(1)第二個組中的限制驗證依賴于一個穩定狀态來運作,而這個穩定狀态是由第一個組來進行驗證的。(2)某個組的驗證比較耗時,CPU 和記憶體的使用率相對比較大,最優的選擇是将其放在最後進行驗證。是以,在進行組驗證的時候尚需提供一種有序的驗證方式,這就提出了組序列的概念。
一個組可以定義為其他組的序列,使用它進行驗證的時候必須符合該序列規定的順序。在使用組序列驗證的時候,如果序列前邊的組驗證失敗,則後面的組将不再給予驗證。
清單 19 聲明了組 GroupA.class,GroupB.class 和 Group.class,其中 default,GroupA,GroupB 均為 Group 的序列。
<code>public interface GroupA {</code>
<code>public interface GroupB {</code>
<code>@GroupSequence({Default.class, GroupA.class, GroupB.class})</code>
<code>public interface Group {</code>
<code>@NotEmpty(message = "country may be empty",groups = GroupB.class)</code>
<code>private String country;</code>
<code>Set<</code><code>ConstraintViolation</code><code><User>> set = validator.validate(user,Group.class);</code>
清單 19 中 main 函數的輸出結果為:
middlename may be empty
firstname may be empty
從輸出結果可以看出,該驗證将不再為屬于 GroupA 和 GroupB 的限制進行驗證,因為屬于組序列(Group.class)中前面位置的 Default 組驗證失敗。隻有當在 main 函數加入如下代碼片段使屬于 Default 組别的驗證通過後,方可進行後續組别(GroupA,GroupB)的驗證。
<code>user.setFirstname("firstname");</code>
<code>user.setMiddlename("midlename");</code>
穿透驗證器主要适用于 JPA 規範,JPA 規範提供一種惰性連接配接屬性,允許實體對象的某些字段被延遲加載,這些被延遲加載的字段需要 JPA 從底層資料庫中擷取。Bean Validation 規範通過 TraversableResolver 接口來控制這類字段的存取性。在實際使用中需要先調用該接口中的 isReachable() 方法,如果傳回 true,則證明該屬性是可存取的,方可進行屬性的限制驗證。同樣,在進行級聯驗證時,也需要首先确定所引用的字段或者屬性的可存取性方可進行限制的級聯驗證。
本文前面的章節介紹了如何定義限制注解以及如何使用限制進行 Java Bean 驗證。對于第三部分中提到的限制驗證流程中的接口,本章将給予詳細的介紹。
Bean Validation 規範允許使用者定制個性化的限制驗證,并給出了 4 大類接口供擴充使用。本章将結合 Bean Validation 規範的參考實作 Hibernate Validator4.0 進行說明。圖 3 給出了 Bean
Validation 規範的 API 以及 Hibernate4.0 相關實作之間的關系示意圖。
Bootstrapping 相關接口
Bootstrapping 相關接口提供 ValidatorFactory 對象,該對象負責建立 Validator(驗證器)執行個體,該執行個體即是 Bean Validation 用戶端用來進行限制驗證的主體類。Bootstrapping 相關接口主要包括 5 類,如表 2 所示:
表 2. Bootstrapping 相關接口及其作用
接口
作用
javax.validation.validation
Bean Validation 規範的 API 預設提供該類,是整個 API 的入口,用來産生 Configuraton 對象執行個體,并啟動環境中 ValidationProvider 的具體實作。
javax.validation.ValidationProviderResolver
傳回執行上下文環境中所有的 BeanValidationProviders 的清單,并對每一個 BeanValidationProvider 産生一個對象執行個體。BeanValidation 規範提供一個預設的實作。
javax.validation.spi.ValidationProvider
具體的 BeanValidationProvider 實作需要實作該接口。該接口用來生成具體的 Congfiguration 接口的實作。
javax.validation.Configuration
收集上下文環境中的配置資訊,主要用來計算如何給定正确的 ValidationProvider,并将其委派給 ValidatorFactory 對象。
javax.validation.ValidatorFactory
從一個具體的 BeanValidationProvider 中建構 Validator 的執行個體。
Validator 接口
該接口(javax.validation.Validator)定義了驗證執行個體的方法,主要包括三種,如表 2 所示:
表 3. Validator 接口中的方法及其作用
方法名
<T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups)
該方法用于驗證一個給定的對象
<T>Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, Class<?>...groups)
該方法用于驗證給定對象中的字段或者屬性
<T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, Class<?>... groups)
該方法用于驗證給定對象中的屬性的具體值
上述兩類接口完成驗證器的初始化工作,下面使用清單 20 解釋上述接口,在本文的示例中均使用 Hibernat Validator4.0 作為參考實作,是以上述兩類接口的具體實作均是 Hibernat Validator4.0 包中的類。
清單 20 使用預設的方式建立驗證工廠(ValidatorFactory),類 Validation 會檢索類路徑下面所有的 jar 檔案,使用 ValidationProviderResolver 接口的預設實作 DefaultValidationProviderResolver(Bean Validation 規範提供該類)查找 META-INF/services/ 目錄中的 javax.validation.spi.ValidationProvider 檔案 , 在 Hibernate Validator4.0 中該檔案中聲明 org.hibernate.validator.HibernateValidator 類為 ValidationProvider 的具體實作,是以 Validation 調用 HibernateValidator 類建立 Configuration 接口的執行個體,在 Hibernate Validator4.0 中,該執行個體為 ConfigurationImpl。最後由 ConfigurationImpl 類産生 ValidatorFactory 的執行個體,在 HibernateValidator4.0 中為 ValidatorFactoryImpl 類。
如果類路徑中存在着多個該規範的實作,這就要用到 Configuration 接口去顯示指定要使用的具體實作,然後再産生 ValidatorFactory 的執行個體。如清單 21 所示:
<code>Configuration<</code><code>HibernateValidatorConfiguration</code><code>> config =</code>
<code>Validation.byProvider(HibernateValidator.class).configure();</code>
<code>ValidatorFactory vf = config.buildValidatorFactory();</code>
如果想實作符合自身業務邏輯的 BeanValidationProvider 檢索規則,隻需要實作接口 ValidationProviderResolver,而不是僅使用規範提供的預設實作。如清單 22 所示:
<code>Configuration<?> config=Validation.byDefaultProvider().providerResolver(</code>
<code>new MyValidationProviderResolver()).configure();</code>
清單 22 中 MyValidationProviderResolver 就是自定義的檢索規則,負責告訴 BeanValidation 如何在具體環境中進行 BeanValidationProvider 的查找。
ConstraintViolation 接口
該接口(javax.validation.ConstraintViolation)用來描述某一驗證的失敗資訊。對某一個實體對象進行驗證的時候,會傳回 ConstraintViolation 的集合,如清單 23 所示:
MessageInterpolator 接口
該接口(javax.validation.MessageInterpolator)用來将驗證過程中的失敗消息以可讀的方式傳遞給用戶端使用者。Bean Validation 規範提供一個預設的消息解析接口,使用者可自定義符合自身業務需求的消息解析機制,隻需實作該接口即可,如清單 24 所示。
<code>Configuration<?> config = Validation.byDefaultProvider().configure();</code>
<code>config.messageInterpolator(new MyMessageInterpolator(config</code>
<code>.getDefaultMessageInterpolator()));</code>
其中 MyMessageInterpolator 就是自定義的消息解析器,用來完成特定的邏輯。
Bean Validation 規範的輸出消息預設從類路徑下的 ValidationMessage.properties 檔案中讀取,使用者也可以在限制注解聲明的時候使用 message 屬性指定消息内容。
Bean Validation 規範使用注解的方式使 Java Bean 的驗證機制更加靈活而且高效。本文對該規範進行了簡單的介紹,旨在為 Java Bean 中業務邏輯驗證機制的程式開發提供一個有益的參考。
本文轉自二郎三郎部落格園部落格,原文連結:http://www.cnblogs.com/haore147/p/7205181.html,如需轉載請自行聯系原作者