http://developer.51cto.com/art/201104/253257_1.htm
ava EE 6核心特征:Bean Validation特性概述(2)
數據驗證在 Java 分層結構的應用開發中占據著重要位置。Java EE 6 提出了 Bean Validation 規范,使用注解的方式對 Java Bean 進行約束驗證,不局限于某一層次或者某一編程模型,靈活易用。本文將向您系統的介紹該規范的各種特性。
?
約束的定義約束注解
Bean Validation 規范對約束的定義包括兩部分,一是約束注解,清單 1 中的 @NotNull 就是約束注解;二是約束驗證器,每一個約束注解都存在對應的約束驗證器,約束驗證器用來驗證具體的 Java Bean 是否滿足該約束注解聲明的條件。
在 Java Bean 中,對某一方法、字段、屬性或其組合形式等進行約束的注解,即為約束注解,如清單 2 所示:
清單 2:
- @NotNull(message?=? "The?id?of?employee?can?not?be?null")? ?
- private?Integer?id;??
清單 2 的含義為:對于字段 id,在 Java Bean 的實例中值不能為空。對于每一個約束注解,在實際使用前必須有相關定義。JSR303 規范默認提供了幾種約束注解的定義(見表 1),我們也可以擴展規范提供的 API,實現符合自身業務需求的約束注解。
表 1. Bean Validation 規范內嵌的約束注解定義
約束注解名稱 | 約束注解說明 |
@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):
清單 3:
- @Target({?})??? //?約束注解應用的目標元素類型 ?
- @Retention()??? //?約束注解應用的時機 ?
- @Constraint(validatedBy?={})?? //?與約束注解關聯的驗證器 ?
- public? @interface?ConstraintName{? ?
- String?message()? default? "?";??? //?約束注解驗證時的輸出消息 ?
- Class[]?groups()? default?{?};?? //?約束注解在驗證時所屬的組別 ?
- Class extends?Payload>[]?payload()? default?{?};? //?約束注解的有效負載 ?
- }??
約束注解應用的目標元素類型包括 METHOD, FIELD, TYPE, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER。METHOD 約束相關的 getter 方法;FIELD 約束相關的屬性;TYPE 約束具體的 Java Bean;ANNOTATION_TYPE 用在組合約束中;該規范同樣也支持對參數(PARAMETER)和構造器(CONSTRUCTOR)的約束。
驗證時的組別屬性將在本文第三大部分中組與組序列中詳細介紹。
有效負載通常用來將一些元數據信息與該約束注解相關聯,常用的一種情況是用負載表示驗證結果的嚴重程度。
清單 4 給出一個驗證字符串非空的約束注解的定義:
清單 4:
- @Target({?METHOD,?FIELD,?ANNOTATION_TYPE,?CONSTRUCTOR,?PARAMETER?})? ?
- @Retention(RUNTIME)? ?
- @Documented? ?
- @Constraint(validatedBy?=?{NotEmptyValidator. class})? ?
- public? @interface?NotEmpty?{? ?
- String?message()? default? "this?string?may?be?empty";? ?
- Class[]?groups()? default?{?};? ?
- Class extends?Payload>[]?payload()? default?{};? ?
- }?
約束注解定義完成后,需要同時實現與該約束注解關聯的驗證器。約束驗證器的實現需要擴展 JSR303 規范提供的接口 javax.validation.ConstraintValidator。清單 5 給出該接口。
清單 5:
- public? interface?ConstraintValidator<a?< span=""> extends?Annotation,?T>?{? ?
- void?initialize(A?constraintAnnotation);? ?
- boolean?isValid(T?value,?ConstraintValidatorContext?context);? ?
- }??
該接口有兩個方法,方法 initialize 對驗證器進行實例化,它必須在驗證器的實例在使用之前被調用,并保證正確初始化驗證器,它的參數是約束注解;方法 isValid 是進行約束驗證的主體方法,其中 value 參數代表需要驗證的實例,context 參數代表約束執行的上下文環境。
對于清單 4 定義的約束注解,清單 6 給出了與該注解對應的驗證器的實現。
清單 6:
- public? class?NotEmptyValidator? implements?ConstraintValidator<notempty,?string>{? ?
- public? void?initialize(NotEmpty?parameters)?{? ?
- }? ?
- public? boolean?isValid(String?string,? ?
- ???ConstraintValidatorContext?constraintValidatorContext)?{? ?
- if?(string?==? null)? return? false;? ?
- else? if(string.length()< 1)? return? false;? ?
- else? return? true;? ?
- }? ?
- }? ?
至此,一個可以聲明并使用的約束注解已經定義完畢,清單 7 將給出該約束注解在實際程序中的使用。為節省篇幅,這里只給出針對清單 1 的增加和修改內容,未給出全部的示例代碼,您可以在本文的附錄中獲得全部的代碼。
清單 7:
首先在清單 1 中的類 Employee 中加入字段 company 和相應的 getter 和 setter 方法:
- @NotEmpty?
- private?String?company;?
然后在 main 函數中加入如下代碼清單:
- String?company?=? new?String(); ?
- employee.setCompany(company); ?
再次運行該程序,輸出結果為:
- The?id?of?employee?can?not?be? null??
- this?string?may?be?empty ?
- The?size?of?employee's?name?must?between? 1?and? 10? ?
多值約束
下面介紹 Bean Validation 規范的一個特性,多值約束(Multiple Constraints):對于同一個目標元素,在進行約束注解聲明時可以同時使用不同的屬性達到對該目標元素進行多值驗證的目的。如清單 8 所示:
清單 8:
- public? @interface?ConstraintName{? ?
- String?message()? default? "?";? ?
- Class[]?groups()? default?{?};? ?
- Class extends?Payload>[]?payload()? default?{?};? ?
- @Target({?METHOD,?FIELD,?ANNOTATION_TYPE,?CONSTRUCTOR,?PARAMETER?})? ?
- @Retention(RUNTIME)? ?
- @Documented? ?
- @interface?List?{? ?
- ConstraintName[]?value();? ?
- }? ?
- }? ?
實現多值約束只需要在定義約束注解的同時定義一個 List(@interface List{})。使用該約束注解時,Bean Validation 將 value 數組里面的每一個元素都處理為一個普通的約束注解,并對其進行驗證,所有約束條件均符合時才會驗證通過。
清單 9 定義了一個約束注解,它用來驗證某一字符串是否包含指定的內容。
清單 9:
- @Target({?METHOD,?FIELD,?ANNOTATION_TYPE,?CONSTRUCTOR,?PARAMETER?})? ?
- @Retention(RUNTIME)? ?
- @Documented? ?
- @Constraint(validatedBy?=?PatternOfStringValidator. class)? ?
- public? @interface?PatternOfString?{? ?
- String?mustContainLetter();? ?
- String?message()? default? "this?pattern?may?not?be?right";? ?
- Class[]?groups()? default?{?};? ?
- Class extends?Payload>[]?payload()? default?{};? ?
- ?
- @Target({?METHOD,?FIELD,?ANNOTATION_TYPE})? ?
- @Retention(RUNTIME)? ?
- @interface?List?{? ?
- PatternOfString[]?value();? ?
- }? ?
- }? ?
該約束注解對應的驗證器如清單 10 所示:
清單 10:
- public? class?PatternOfStringValidator? implements?ConstraintValidator ?
- ?{? ?
- private?String?letterIn;? ?
- public? void?initialize(PatternOfString?parameters)?{? ?
- this.letterIn=parameters.mustContainLetter();? ?
- }? ?
- public? boolean?isValid(String?string,? ?
- ConstraintValidatorContext?constraintValidatorContext)?{? ?
- if?(string.contains(letterIn))? ?
- return? true;? ?
- return? false;? ?
- }? ?
- }? ?
如果想驗證某一字符串是否同時包含兩個子串,那么多值約束就顯得比較重要了,清單 11 將詳細給出多值約束的使用。
清單 11:
在清單 1 中的類 Employee 中增加如下字段 place 以及相應的 getter 和 setter 方法:
- @PatternOfString.List({ ??
- @PatternOfString(mustContainLetter?=? "CH", ??
- message?=? "It?does?not?belong?to?China"), ?
- @PatternOfString(mustContainLetter= "MainLand", ?
- message= "It?does?not?belong?to?MainLand")}) ?
- private?String?place;?
然后在 main 函數中加入如下代碼清單:
- String?place?=? "C"; ??
- employee.setPlace(place); ? ?
再次運行該程序,輸出結果為:
- It?does?not?belong?to?MainLand ??
- It?does?not?belong?to?China ?
- this?string?may?be?empty ?
- The?id?of?employee?can?not?be? null?
- The?size?of?employee's?name?must?between? 1?and? 10? ?
如果將 place 賦值為 String place = "CHINA",則輸出結果為:
- this?string?may?be?empty ??
- The?id?of?employee?can?not?be? null?
- It?does?not?belong?to?MainLand ?
- The?size?of?employee's?name?must?between? 1?and? 10? ?
可見,該約束會對聲明的兩個約束注解分別進行驗證,只要存在不符合約束驗證規則的 Java Bean 實例,就將產生相應的驗證失敗信息。約束注解聲明的時候可以根據不同的約束值使用 message 參數給出不同的輸出信息。
組合約束
下面介紹 Bean Validation 規范中另一個重要的特性:組合約束。Bean Validation 規范允許將不同的約束進行組合來創建級別較高且功能較多的約束,從而避免原子級別約束的重復使用。如清單 4 定義的約束注解 @NotEmpty,是用來判斷一個字符串在非空的基礎上長度至少為 1,其實際意義等同于 @NotNull 和 @Size(min=1)的組合形式,因此可以將 @NotEmpty 約束定義為組合約束 NotEmpty2,如清單 12 所示:
清單 12:
- @NotNull? ?
- @Size(min?=? 1)? ?
- @Target({?METHOD,?FIELD,?ANNOTATION_TYPE,?CONSTRUCTOR,?PARAMETER?})? ?
- @Retention(RUNTIME)? ?
- @Documented? ?
- @Constraint(validatedBy?=?{NotEmptyValidator2. class})? ?
- public? @interface?NotEmpty2?{? ?
- String?message()? default? "this?string?may?be?empty";? ?
- Class[]?groups()? default?{?};? ?
- Class extends?Payload>[]?payload()? default?{};? ?
- ?
- @Target({?METHOD,?FIELD,?ANNOTATION_TYPE})? ?
- @Retention(RUNTIME)? ?
- @interface?List?{? ?
- NotEmpty2[]?value();? ?
- }? ?
- }? ?
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
