Ryan's Java world!

          something about Java and opensource!

          BlogJava 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
            51 Posts :: 25 Stories :: 59 Comments :: 0 Trackbacks

          Hibernate Validator 簡(jiǎn)介

          在項(xiàng)目的業(yè)務(wù)屬性中,你是不是要經(jīng)常驗(yàn)證屬性的取值范圍呢. 想要了解比較優(yōu)美的解決方案嗎???????????

          看看Hibernate Validator 是怎么做的吧.一見(jiàn)到她,相信你就會(huì)說(shuō): Oh God, 這就是我需要的.

          任何獲得Matrix授權(quán)的網(wǎng)站,轉(zhuǎn)載請(qǐng)保留以下作者信息和鏈接:
          作者:icess(作者的blog:http://blog.matrix.org.cn/page/icess)
          關(guān)鍵字:Hibernate Validator

          用Annotations 給類或者類的屬性加上約束(constraint),在運(yùn)行期檢查屬性值是很優(yōu)雅的.Hibernate Validator就是這樣的一個(gè)框架.該框架是十分容易的(就像參考文檔中宣稱的那樣),幾乎沒(méi)有什么學(xué)習(xí)曲線,Validator 是一個(gè)驗(yàn)證框架 不需要和Hibernate的其他部分綁定就可以使用,只要在你的項(xiàng)目中添加Hibernate-annotations.jar庫(kù)就可以了.那么下面就讓我們看看怎么使用吧.

          Person.java 類

          /*
          ? *?Created?on?2006-1-12 Person.java
          ? *?@author?
          ? */
          package? test.annotation.validator;

          import? org.hibernate.validator.Length;
          import? org.hibernate.validator.Min;
          import? org.hibernate.validator.Valid;
           

          //@Serializability? //測(cè)試自定義約束
          public?class? Person?{

          ?? private? String?name;
          ?? private?int? age;
          ?? private? Address?address;
          ??
          ?? public? Person()?{}
          ??
          ?? @Valid //注意此處
          ?? public? Address?getAddress()?{
          ???? return? address;
          ?? }
          ?? public?void? setAddress(Address?address)?{
          ???? this .address?=?address;
          ?? }
          ??
          ?? @Min(value?=? 1 )
          ?? public?int? getAge()?{
          ???? return? age;
          ?? }
          ?? public?void? setAge( int? age)?{
          ???? this .age?=?age;
          ?? }
          ??
          ?? @Length(min?=? 4 )
          ?? public? String?getName()?{
          ???? return? name;
          ?? }
          ?? public?void? setName(String?name)?{
          ???? this .name?=?name;
          ?? }
          }

           

          Address.java 類

          /*
          ? *?Created?on?2006-1-12 Address.java
          ? *?@author?
          ? */
          package? test.annotation.validator;

          import? org.hibernate.validator.Length;
          import? org.hibernate.validator.Max;
          import? org.hibernate.validator.Min;

          public?class? Address?{

          ?? private? String?street;
          ?? private?int? num;
          ??
          ?? public? Address()?{}
          ??
          ?? @Min(value?=? 1 )
          ?? @Max(value?=? 100 )
          ?? public?int? getNum()?{
          ???? return? num;
          ?? }
          ?? public?void? setNum( int? num)?{
          ???? this .num?=?num;
          ?? }
          ??
          ?? @Length(min?=? 3 ,max?=? 8 )
          ?? public? String?getStreet()?{
          ???? return? street;
          ?? }
          ?? public?void? setStreet(String?street)?{
          ???? this .street?=?street;
          ?? }
          }

          上面是兩個(gè)用 Validator Annotations 注釋的 類. 每個(gè)屬性都用 約束限制了.? 下面看看測(cè)試的類吧:

          TestValidator.java 類

          /*
          ? *?Created?on?2006-1-12
          ? *?@author?icerain
          ? */
          package? test.annotation.validator;

          import? org.hibernate.validator.ClassValidator;
          import? org.hibernate.validator.InvalidValue;


          public?class? TestValidator?{
          ?? public?void? test()?{
          ???? Address?add?=? new? Address();
          ???? add.setNum( 0 );
          ???? add.setStreet( "1" );
          ????
          ???? Person?p?=? new? Person();
          ???? p.setAddress(add);
          ???? p.setAge( 0 );
          ???? p.setName( "ice" );
          ????
          ???? /******************Test?validator?********/

          ??? // 注意該處只驗(yàn)證了Person 為了說(shuō)明 @Valid 注釋的使用
          ???? ClassValidator<Person>?classValidator?=? new? ClassValidator<Person>?(Person. class );
          ???? InvalidValue[]?validMessages?=?classValidator.getInvalidValues(p);
          ???? for? (InvalidValue?value?:?validMessages)?{
          ??????
          ???? System.out.println( "InvalidValue?的長(zhǎng)度是:"? +?validMessages.length
          ???????? + "?.?驗(yàn)證消息是:?"? +?value.getMessage()?
          ???????? +? "?.?PropertyPath?是:"? +?value.getPropertyPath()
          ???????? + "?.\n\t?PropertyName?是:?"? +value.getPropertyName()
          ???????? +? "Value?是:?"? +?value.getValue()
          ???????? + "?Bean?是:?" +?value.getBean()
          ???????? + "\n\t?BeanClass?是:"? +?value.getBeanClass());
          ???? }
          ?? }
          ??
          ?? public?static?void? main(String[]?args)?{
          ???? new? TestValidator().test();
          ?? }
          }

           

          程序的輸出如下

          InvalidValue 的長(zhǎng)度是:4 . 驗(yàn)證消息是: 必須大于等于 1 . PropertyPath 是:age .

          PropertyName 是: age. Value 是: 0 Bean 是: test.annotation.validator.Person@dd87b2

          BeanClass 是:class test.annotation.validator.Person

          InvalidValue 的長(zhǎng)度是:4 . 驗(yàn)證消息是: 長(zhǎng)度必須介于 4 與 2147483647 之間 . PropertyPath 是:name .

          PropertyName 是: name. Value 是: ice Bean 是: test.annotation.validator.Person@dd87b2

          BeanClass 是:class test.annotation.validator.Person

          InvalidValue 的長(zhǎng)度是:4 . 驗(yàn)證消息是: 必須大于等于 1 . PropertyPath 是:address.num .

          PropertyName 是: num. Value 是: 0 Bean 是: test.annotation.validator.Address@197d257

          BeanClass 是:class test.annotation.validator.Address

          InvalidValue 的長(zhǎng)度是:4 . 驗(yàn)證消息是: 長(zhǎng)度必須介于 3 與 8 之間 . PropertyPath 是:address.street .

          PropertyName 是: street. Value 是: 1 Bean 是: test.annotation.validator.Address@197d257

          BeanClass 是:class test.annotation.validator.Address

          可以看出不滿足約束的值都被指出了.

          同時(shí)該句: ClassValidator<Person>?classValidator?=?new?ClassValidator<Person>?(Person.class);

          我們只驗(yàn)證了 Person. 在Person里面的Address的屬性 由于有@Valid Annotations 所以 Address的相關(guān)屬性也被機(jī)聯(lián)驗(yàn)證了 .

          如果 把 @Valid Annotations 去掉,結(jié)果如下:

          InvalidValue 的長(zhǎng)度是:2 . 驗(yàn)證消息是: 必須大于等于 1 . PropertyPath 是:age .

          PropertyName 是: age. Value 是: 0 Bean 是: test.annotation.validator.Person@18fef3d

          BeanClass 是:class test.annotation.validator.Person

          InvalidValue 的長(zhǎng)度是:2 . 驗(yàn)證消息是: 長(zhǎng)度必須介于 4 與 2147483647 之間 . PropertyPath 是:name .

          PropertyName 是: name. Value 是: ice Bean 是: test.annotation.validator.Person@18fef3d

          BeanClass 是:class test.annotation.validator.Person

          可以看出 沒(méi)有驗(yàn)證 Address.

          當(dāng)然了 ,你還可以只驗(yàn)證一個(gè)屬性 , 沒(méi)有必要驗(yàn)證整個(gè)類.只需要在調(diào)用 classValidator.getInvalidValues(p,"age")方法時(shí) 加上你要驗(yàn)證的屬性就可以了.如我們只想驗(yàn)證age 屬性 把代碼改為如下所示:

          InvalidValue[] validMessages = classValidator.getInvalidValues(p,"age"); / /只驗(yàn)證age 屬性

          運(yùn)行結(jié)果如下:

          InvalidValue 的長(zhǎng)度是:1 . 驗(yàn)證消息是: 必須大于等于 1 . PropertyPath 是:age .

          PropertyName 是: age. Value 是: 0 Bean 是: test.annotation.validator.Person@1457cb

          BeanClass 是:class test.annotation.validator.Person

          只是驗(yàn)證了 age 屬性.

          怎么樣 ,很簡(jiǎn)單吧. 關(guān)于 Hibernate Validator 內(nèi)建的驗(yàn)證Annotations 大家可以看看 API 或者 參考文檔(中文版我正在翻譯中 請(qǐng)?jiān)L問(wèn)我的 Blog 獲得最新信息).

          如果你要寫(xiě)自己的約束呢 , 你不用擔(dān)心 ,這也是很容易的. 任何約束有兩部分組成: [約束描述符 即注釋]the constraint descriptor (the annotation) 和[約束validator 即 實(shí)現(xiàn)類] the constraint validator (the implementation class).下面我們擴(kuò)展Hibernate Test suit 中的一個(gè)Test 來(lái)講解一下.

          首先: 要聲明一個(gè) constraint descriptor .如下:

          package? test.annotation.validator;

          import? java.lang.annotation.Documented;
          import?static? java.lang.annotation.ElementType.TYPE;
          import?static? java.lang.annotation.ElementType.FIELD;
          import?static? java.lang.annotation.ElementType.METHOD;
          import? java.lang.annotation.Retention;
          import?static? java.lang.annotation.RetentionPolicy.RUNTIME;
          import? java.lang.annotation.Target;

          import? org.hibernate.validator.ValidatorClass;

          /**
          ? *?Dummy?sample?of?a?bean-level?validation?annotation
          ? *
          ? *? @author? Emmanuel?Bernard
          ? */
          @ValidatorClass(SerializabilityValidator. class )
          @Target({METHOD,FIELD,TYPE})
          @Retention(RUNTIME)
          @Documented
          public? @interface?Serializability?{
          ?? int? num()? default? 11 ;
          ?? String?message()? default? "bean?must?be?serialiable" ;
          }

          @ValidatorClass(SerializabilityValidator. class ) 指出了 constraint validator 類.

          @Target({METHOD,FIELD,TYPE})
          @Retention(RUNTIME)
          @Documented????????????????

          這幾個(gè)我就不用解釋了吧.

          Serializability?里面聲明了一個(gè) message 顯示約束的提示信息. num 只是為了說(shuō)明一個(gè)方面 在這里面沒(méi)有實(shí)際用途用 .

          然后就是 實(shí)現(xiàn)一個(gè) constraint validator 類 該類要實(shí)現(xiàn)Validator<ConstraintAnnotation>.這里是SerializabilityValidator.java 如下:

          //$Id:?SerializabilityValidator.java,v?1.3?2005/11/17?18:12:11?epbernard?Exp?$
          package? test.annotation.validator;

          import? java.io.Serializable;

          import? org.hibernate.validator.Validator;

          /**
          ? *?Sample?of?a?bean-level?validator
          ? *
          ? *? @author? Emmanuel?Bernard
          ? */
          public?class? SerializabilityValidator? implements? Validator<Serializability>,?Serializable?{
          ?? public?boolean? isValid(Object?value)?{
          ??? //這里只是Validator 里面的 實(shí)現(xiàn)驗(yàn)證規(guī)則的 方法. value 是要驗(yàn)證的值.
          ???? System.out.println( "IN?SerializabilityValidator?isValid:" +value.getClass()+ ":?"? +value.toString());
          ???? return? value?instanceof?Serializable;
          ??}

          ??public?void?initialize(Serializability?parameters)?{
          ????//?在這里可以 取得
          constraint descriptor 里面的屬性 如上面我們聲明的 num
          ???? System.out.println( "IN?SerializabilityValidator:?parameters:" +?parameters.num()?);
          ?? }
          }

          然后在你的類中應(yīng)用@Serializability? 就可以約束一個(gè)類實(shí)現(xiàn)Serializable 接口了. 如下:

          在我們的Person.java類 添加@Serializability? Annotations ,把Person.java 中的 //@Serializability //測(cè)試自定義約束 注釋去掉就ok了.

          運(yùn)行結(jié)果如下:

          InvalidValue 的長(zhǎng)度是:3 . 驗(yàn)證消息是: bean must be serialiable . PropertyPath 是:null .

          PropertyName 是: null. Value 是: test.annotation.validator.Person@1a73d3c Bean 是: test.annotation.validator.Person@1a73d3c

          BeanClass 是:class test.annotation.validator.Person

          現(xiàn)在把Person類實(shí)現(xiàn) java.io.Serializable 接口 則沒(méi)有出現(xiàn) 驗(yàn)證錯(cuò)誤消息.

          消息的國(guó)際化也是很簡(jiǎn)單的,把 Serializability? 中的message 改為以{}擴(kuò)住的 屬性文件的Key就可以了

          public? @interface?Serializability?{
          ?? int? num()? default? 11 ;
          ?? String?message()? default? "{Serializable}"; //"bean?must?be?serialiable"; //消息的國(guó)際化
          }

          然后編輯資料文件. 注意 該資源文件中要包括 Hibernate Validator 內(nèi)建的資源. 可以在該org\hibernate\validator\resources 包里面的資源文件基礎(chǔ)上修改 ,在打包里面 這樣就可以了. 自己打包可能不太方便.你可以把該包里面的文件復(fù)制出來(lái).然后放到你自己的項(xiàng)目包下在自己編輯, 該測(cè)試中 我是放在 test\resources 包下的.

          然后在 資源文件中添加 Serializable = '''''' 這么一行, 樣例如下:

          #DefaultValidatorMessages.properties (DefaultValidatorMessages_zh.properties 不再列出^_^)

           

          #下面是 Hibernate Validator 內(nèi)建的國(guó)際化消息

          validator.assertFalse= assertion failed

          validator.assertTrue= assertion failed

          validator.future= must be a future date

          validator.length= length must be between {min} and {max}

          validator.max= must be less than or equal to {value}

          validator.min= must be greater than or equal to {value}

          validator.notNull= may not be null

          validator.past= must be a past date

          validator.pattern= must match "{regex}"

          validator.range= must be between {min} and {max}

          validator.size= size must be between {min} and {max}

          #下面是自定義的消息

          Serializable= Bean not Serializable? //加上自己定義的國(guó)際化消息.

          在構(gòu)造 ClassValidator 時(shí)要添上 資源文件 如下:(在測(cè)試類中)

          ClassValidator<Person> classValidator = new ClassValidator<Person> (Person.class,ResourceBundle.getBundle("test.resources.DefaultValidatorMessages"));//加載資源

          這樣就可以了 .? 當(dāng)然 你還可以 更改 Hibernate Validator 的消息(不是在上面的資源文件中直接修改 validator.length = ... 等等 ) , 還記得 Validator 注釋中有個(gè) message 元素嗎? 你以前用的都是默認(rèn)值,現(xiàn)在你可以該為你自己定義的了. 如:validator.length 我把他改為 "該字符串的長(zhǎng)度不符合規(guī)定范圍范圍". 在資源文件中添加一行鍵值屬性對(duì)(key定義為 "myMsg")如下:

          myMsg=該字符串的長(zhǎng)度不符合規(guī)定范圍范圍

          并且還要在 @Length 注釋中提供message的引用的key 如下 @Length(min = 4,message = "{ myMsg }")

          再一次運(yùn)行測(cè)試 ,我們就可以看到上面兩條自定義綁定的消息了 .如下:

          InvalidValue 的長(zhǎng)度是:3 . 驗(yàn)證消息是: Bean 不是 可 Serializable . PropertyPath 是:null .
          PropertyName 是: null. Value 是: test.annotation.validator.Person@1bd4722 Bean 是: test.annotation.validator.Person@1bd4722
          BeanClass 是:class test.annotation.validator.Person


          InvalidValue 的長(zhǎng)度是:3 . 驗(yàn)證消息是: 該字符串的長(zhǎng)度不符合規(guī)定范圍范圍 . PropertyPath 是:name .
          PropertyName 是: name. Value 是: ice Bean 是: test.annotation.validator.Person@1bd4722
          BeanClass 是:class test.annotation.validator.Person

          怎么樣,比你想象的簡(jiǎn)單吧.

          OK 上面我們討論了 Hibernate Validator 的主要用法: 但是 該框架有什么用呢? ^_^

          看到這里其實(shí)不用我在多說(shuō)了 大家都知道怎么用,什么時(shí)候用. 作為一篇介紹性文章我還是在此給出一個(gè)最常用的例子吧,更好的使用方式大家慢慢挖掘吧.

          比如 : 你現(xiàn)在在開(kāi)發(fā)一個(gè)人力資源(HR)系統(tǒng) (其實(shí)是我們ERP課程的一個(gè)作業(yè) ^_^), 里面要處理大量的數(shù)據(jù),尤其是在輸入各種資料時(shí) 如 登記員工信息. 如果你公司的員工的年齡要求是18 -- 60 那么你所輸入的年齡就不能超出這個(gè)范圍. 你可能會(huì)說(shuō)這很容易啊 , 不用Validator就可以解決啊.這保持?jǐn)?shù)據(jù)前驗(yàn)證就可以啦 如if ( e.getAge() > 60 || e.getAge() < 18 ) ........ 給出錯(cuò)誤信息 然后提示重新輸入不就OK啦 用得著 興師動(dòng)眾的來(lái)個(gè)第三方框架嗎?

          是啊 當(dāng)就驗(yàn)證這一個(gè)屬性時(shí), 沒(méi)有必要啊 ! 但是一個(gè)真正的HR 系統(tǒng),會(huì)只有一個(gè)屬性要驗(yàn)證嗎? 恐怕要有N多吧

          你要是每一個(gè)都那樣 寫(xiě)一段驗(yàn)證代碼 是不是很煩啊 ,況且也不方便代碼重用. 現(xiàn)在考慮一些 Validator 是不是更高效啊,攔截到 約束違例的 屬性 就可以直接得到 國(guó)際化的消息 可以把該消息顯示到一個(gè)彈出對(duì)話框上 提示更正? !

          Validator的用處不只這一種 ,你可以想到如何用呢 ! 歡迎發(fā)表你的高見(jiàn)!!

          OK 到此 我們的 Hibernate Validator 之旅就要先告一段落了 . 希望這是令你心曠神怡的一次寒冬之旅,

          把你學(xué)到的應(yīng)用到你的項(xiàng)目中吧,一定會(huì)提高你的生產(chǎn)率的. 相信我 ,沒(méi)錯(cuò)的? ^_^ !

          posted on 2006-05-17 10:35 冰雨 閱讀(1928) 評(píng)論(3)  編輯  收藏 所屬分類: Opensource

          Feedback

          # re: Hibernate Validator 簡(jiǎn)介 2006-05-17 10:58 popoer
          不錯(cuò)哦!  回復(fù)  更多評(píng)論
            

          # re: Hibernate Validator 簡(jiǎn)介 2006-05-17 15:44 鳥(niǎo)不生蛋蛋的地方
          是個(gè)很好用東西哪  回復(fù)  更多評(píng)論
            

          # re: Hibernate Validator 簡(jiǎn)介 2006-05-17 16:21 冰雨
          在有些驗(yàn)證上面用起來(lái)還是很不錯(cuò)的, apache 也有一個(gè)類似的框架, 我 沒(méi)有用過(guò), 有用過(guò)的路過(guò)的話, 給點(diǎn)比較,看看每一個(gè)在那個(gè)方面跟能發(fā)揮長(zhǎng)處.  回復(fù)  更多評(píng)論
            


          JSF中文技術(shù)文摘
          主站蜘蛛池模板: 兴海县| 柞水县| 阳春市| 九寨沟县| 无为县| 扎兰屯市| 六枝特区| 彰化县| 庆安县| 柳江县| 昆明市| 高台县| 攀枝花市| 宁南县| 济阳县| 富蕴县| 神农架林区| 平泉县| 武胜县| 丹东市| 丹巴县| 龙游县| 蒲江县| 棋牌| 桐城市| 安多县| 关岭| 福州市| 西充县| 交口县| 蚌埠市| 桂阳县| 固阳县| 鸡西市| 定远县| 鄂尔多斯市| 常宁市| 滨州市| 齐齐哈尔市| 如皋市| 湟中县|