http://developer.51cto.com/art/201104/253257_1.htm
ava EE 6核心特征:Bean Validation特性概述(2)
數(shù)據(jù)驗(yàn)證在 Java 分層結(jié)構(gòu)的應(yīng)用開發(fā)中占據(jù)著重要位置。Java EE 6 提出了 Bean Validation 規(guī)范,使用注解的方式對 Java Bean 進(jìn)行約束驗(yàn)證,不局限于某一層次或者某一編程模型,靈活易用。本文將向您系統(tǒng)的介紹該規(guī)范的各種特性。
?
約束的定義約束注解
Bean Validation 規(guī)范對約束的定義包括兩部分,一是約束注解,清單 1 中的 @NotNull 就是約束注解;二是約束驗(yàn)證器,每一個(gè)約束注解都存在對應(yīng)的約束驗(yàn)證器,約束驗(yàn)證器用來驗(yàn)證具體的 Java Bean 是否滿足該約束注解聲明的條件。
在 Java Bean 中,對某一方法、字段、屬性或其組合形式等進(jìn)行約束的注解,即為約束注解,如清單 2 所示:
清單 2:
- @NotNull(message?=? "The?id?of?employee?can?not?be?null")? ?
- private?Integer?id;??
清單 2 的含義為:對于字段 id,在 Java Bean 的實(shí)例中值不能為空。對于每一個(gè)約束注解,在實(shí)際使用前必須有相關(guān)定義。JSR303 規(guī)范默認(rèn)提供了幾種約束注解的定義(見表 1),我們也可以擴(kuò)展規(guī)范提供的 API,實(shí)現(xiàn)符合自身業(yè)務(wù)需求的約束注解。
表 1. Bean Validation 規(guī)范內(nèi)嵌的約束注解定義
| 約束注解名稱 | 約束注解說明 |
| @Null | 驗(yàn)證對象是否為空 |
| @NotNull | 驗(yàn)證對象是否為非空 |
| @AssertTrue | 驗(yàn)證 Boolean 對象是否為 true |
| @AssertFalse | 驗(yàn)證 Boolean 對象是否為 false |
| @Min | 驗(yàn)證 Number 和 String 對象是否大等于指定的值 |
| @Max | 驗(yàn)證 Number 和 String 對象是否小等于指定的值 |
| @DecimalMin | 驗(yàn)證 Number 和 String 對象是否大等于指定的值,小數(shù)存在精度 |
| @DecimalMax | 驗(yàn)證 Number 和 String 對象是否小等于指定的值,小數(shù)存在精度 |
| @Size | 驗(yàn)證對象(Array,Collection,Map,String)長度是否在給定的范圍之內(nèi) |
| @Digits | 驗(yàn)證 Number 和 String 的構(gòu)成是否合法 |
| @Past | 驗(yàn)證 Date 和 Calendar 對象是否在當(dāng)前時(shí)間之前 |
| @Future | 驗(yàn)證 Date 和 Calendar 對象是否在當(dāng)前時(shí)間之后 |
| @Pattern | 驗(yàn)證 String 對象是否符合正則表達(dá)式的規(guī)則 |
?
約束注解和普通的注解一樣,一個(gè)典型的約束注解的定義應(yīng)該至少包括如下內(nèi)容(清單 3):
清單 3:
- @Target({?})??? //?約束注解應(yīng)用的目標(biāo)元素類型 ?
- @Retention()??? //?約束注解應(yīng)用的時(shí)機(jī) ?
- @Constraint(validatedBy?={})?? //?與約束注解關(guān)聯(lián)的驗(yàn)證器 ?
- public? @interface?ConstraintName{? ?
- String?message()? default? "?";??? //?約束注解驗(yàn)證時(shí)的輸出消息 ?
- Class[]?groups()? default?{?};?? //?約束注解在驗(yàn)證時(shí)所屬的組別 ?
- Class extends?Payload>[]?payload()? default?{?};? //?約束注解的有效負(fù)載 ?
- }??
約束注解應(yīng)用的目標(biāo)元素類型包括 METHOD, FIELD, TYPE, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER。METHOD 約束相關(guān)的 getter 方法;FIELD 約束相關(guān)的屬性;TYPE 約束具體的 Java Bean;ANNOTATION_TYPE 用在組合約束中;該規(guī)范同樣也支持對參數(shù)(PARAMETER)和構(gòu)造器(CONSTRUCTOR)的約束。
驗(yàn)證時(shí)的組別屬性將在本文第三大部分中組與組序列中詳細(xì)介紹。
有效負(fù)載通常用來將一些元數(shù)據(jù)信息與該約束注解相關(guān)聯(lián),常用的一種情況是用負(fù)載表示驗(yàn)證結(jié)果的嚴(yán)重程度。
清單 4 給出一個(gè)驗(yàn)證字符串非空的約束注解的定義:
清單 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?{};? ?
- }?
約束注解定義完成后,需要同時(shí)實(shí)現(xiàn)與該約束注解關(guān)聯(lián)的驗(yàn)證器。約束驗(yàn)證器的實(shí)現(xiàn)需要擴(kuò)展 JSR303 規(guī)范提供的接口 javax.validation.ConstraintValidator。清單 5 給出該接口。
清單 5:
- public? interface?ConstraintValidator<a?< span=""> extends?Annotation,?T>?{? ?
- void?initialize(A?constraintAnnotation);? ?
- boolean?isValid(T?value,?ConstraintValidatorContext?context);? ?
- }??
該接口有兩個(gè)方法,方法 initialize 對驗(yàn)證器進(jìn)行實(shí)例化,它必須在驗(yàn)證器的實(shí)例在使用之前被調(diào)用,并保證正確初始化驗(yàn)證器,它的參數(shù)是約束注解;方法 isValid 是進(jìn)行約束驗(yàn)證的主體方法,其中 value 參數(shù)代表需要驗(yàn)證的實(shí)例,context 參數(shù)代表約束執(zhí)行的上下文環(huán)境。
對于清單 4 定義的約束注解,清單 6 給出了與該注解對應(yīng)的驗(yàn)證器的實(shí)現(xiàn)。
清單 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;? ?
- }? ?
- }? ?
至此,一個(gè)可以聲明并使用的約束注解已經(jīng)定義完畢,清單 7 將給出該約束注解在實(shí)際程序中的使用。為節(jié)省篇幅,這里只給出針對清單 1 的增加和修改內(nèi)容,未給出全部的示例代碼,您可以在本文的附錄中獲得全部的代碼。
清單 7:
首先在清單 1 中的類 Employee 中加入字段 company 和相應(yīng)的 getter 和 setter 方法:
- @NotEmpty?
- private?String?company;?
然后在 main 函數(shù)中加入如下代碼清單:
- String?company?=? new?String(); ?
- employee.setCompany(company); ?
再次運(yùn)行該程序,輸出結(jié)果為:
- 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 規(guī)范的一個(gè)特性,多值約束(Multiple Constraints):對于同一個(gè)目標(biāo)元素,在進(jìn)行約束注解聲明時(shí)可以同時(shí)使用不同的屬性達(dá)到對該目標(biāo)元素進(jìn)行多值驗(yàn)證的目的。如清單 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();? ?
- }? ?
- }? ?
實(shí)現(xiàn)多值約束只需要在定義約束注解的同時(shí)定義一個(gè) List(@interface List{})。使用該約束注解時(shí),Bean Validation 將 value 數(shù)組里面的每一個(gè)元素都處理為一個(gè)普通的約束注解,并對其進(jìn)行驗(yàn)證,所有約束條件均符合時(shí)才會(huì)驗(yàn)證通過。
清單 9 定義了一個(gè)約束注解,它用來驗(yàn)證某一字符串是否包含指定的內(nèi)容。
清單 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();? ?
- }? ?
- }? ?
該約束注解對應(yīng)的驗(yàn)證器如清單 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;? ?
- }? ?
- }? ?
如果想驗(yàn)證某一字符串是否同時(shí)包含兩個(gè)子串,那么多值約束就顯得比較重要了,清單 11 將詳細(xì)給出多值約束的使用。
清單 11:
在清單 1 中的類 Employee 中增加如下字段 place 以及相應(yīng)的 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 函數(shù)中加入如下代碼清單:
- String?place?=? "C"; ??
- employee.setPlace(place); ? ?
再次運(yùn)行該程序,輸出結(jié)果為:
- 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",則輸出結(jié)果為:
- 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? ?
可見,該約束會(huì)對聲明的兩個(gè)約束注解分別進(jìn)行驗(yàn)證,只要存在不符合約束驗(yàn)證規(guī)則的 Java Bean 實(shí)例,就將產(chǎn)生相應(yīng)的驗(yàn)證失敗信息。約束注解聲明的時(shí)候可以根據(jù)不同的約束值使用 message 參數(shù)給出不同的輸出信息。
組合約束
下面介紹 Bean Validation 規(guī)范中另一個(gè)重要的特性:組合約束。Bean Validation 規(guī)范允許將不同的約束進(jìn)行組合來創(chuàng)建級(jí)別較高且功能較多的約束,從而避免原子級(jí)別約束的重復(fù)使用。如清單 4 定義的約束注解 @NotEmpty,是用來判斷一個(gè)字符串在非空的基礎(chǔ)上長度至少為 1,其實(shí)際意義等同于 @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();? ?
- }? ?
- }? ?
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

