熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java開源技術 >> 正文

框架Hibernate Validator 簡介

2013-11-23 20:29:44  來源: Java開源技術 

  用Annotations 給類或者類的屬性加上約束(constraint)在運行期檢查屬性值是很優雅的Hibernate Validator就是這樣的一個框架該框架是十分容易的(就像參考文檔中宣稱的那樣)幾乎沒有什麼學習曲線Validator 是一個驗證框架 不需要和Hibernate的其他部分綁定就可以使用只要在你的項目中添加Hibernateannotationsjar庫就可以了那麼下面就讓我們看看怎麼使用吧

Personjava 類
/*
* Created on Personjava
* @author
*/
package testannotationvalidator;

import orghibernatevalidatorLength;
import orghibernatevalidatorMin;
import orghibernatevalidatorValid;
 

//@Serializability  //測試自定義約束
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) {
    thisaddress = address;
  }
  
  @Min(value = )
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    thisage = age;
  }
  
  @Length(min = )
  public String getName() {
    return name;
  }
  public void setName(String name) {
    thisname = name;
  }
}

  Addressjava 類

  /*
* Created on Addressjava
* @author
*/
package testannotationvalidator;

import orghibernatevalidatorLength;
import orghibernatevalidatorMax;
import orghibernatevalidatorMin;

public class Address {

  private String street;
  private int num;
  
  public Address() {}
  
  @Min(value = )
  @Max(value = )
  public int getNum() {
    return num;
  }
  public void setNum(int num) {
    thisnum = num;
  }
  
  @Length(min = max = )
  public String getStreet() {
    return street;
  }
  public void setStreet(String street) {
    thisstreet = street;
  }
}

  上面是兩個用 Validator Annotations 注釋的 類 每個屬性都用 約束限制了  下面看看測試的類吧:

TestValidatorjava 類
/*
* Created on
* @author icerain
*/
package testannotationvalidator;

import orghibernatevalidatorClassValidator;
import orghibernatevalidatorInvalidValue;


public class TestValidator {
  public void test() {
    Address add = new Address();
    addsetNum();
    addsetStreet();
    
    Person p = new Person();
    psetAddress(add);
    psetAge();
    psetName(ice);
    
    /******************Test validator ********/
    // 注意該處只驗證了Person 為了說明 @Valid 注釋的使用
    ClassValidator<Person> classValidator = new ClassValidator<Person> (Personclass);
    InvalidValue[] validMessages = classValidatorgetInvalidValues(p);
    for (InvalidValue value : validMessages) {
      
    Systemoutprintln(InvalidValue 的長度是: + validMessageslength
        + 驗證消息是: + valuegetMessage()
        + PropertyPath 是: + valuegetPropertyPath()
        + \n\t PropertyName 是: +valuegetPropertyName()
        + Value 是: + valuegetValue()
        + Bean 是: + valuegetBean()
        +\n\t BeanClass 是: + valuegetBeanClass());
    }
  }
  
  public static void main(String[] args) {
    new TestValidator()test();
  }
}

  程序的輸出如下

InvalidValue 的長度是: 驗證消息是: 必須大於等於 PropertyPath 是:age

PropertyName 是: age Value 是: Bean 是: testannotationvalidatorPerson@ddb

BeanClass 是:class testannotationvalidatorPerson

InvalidValue 的長度是: 驗證消息是: 長度必須介於 之間 PropertyPath 是:name

PropertyName 是: name Value 是: ice Bean 是: testannotationvalidatorPerson@ddb

BeanClass 是:class testannotationvalidatorPerson

InvalidValue 的長度是: 驗證消息是: 必須大於等於 PropertyPath 是:addressnum

PropertyName 是: num Value 是: Bean 是: testannotationvalidatorAddress@d

BeanClass 是:class testannotationvalidatorAddress

InvalidValue 的長度是: 驗證消息是: 長度必須介於 之間 PropertyPath 是:addressstreet

PropertyName 是: street Value 是: Bean 是: testannotationvalidatorAddress@d

BeanClass 是:class testannotationvalidatorAddress

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

同時該句: ClassValidator<Person> classValidator = new ClassValidator<Person> (Personclass);

我們只驗證了 Person 在Person裡面的Address的屬性 由於有@Valid Annotations 所以 Address的相關屬性也被機聯驗證了



如果 把@Valid Annotations 去掉結果如下:

InvalidValue 的長度是: 驗證消息是: 必須大於等於 PropertyPath 是:age

PropertyName 是: age Value 是: Bean 是: testannotationvalidatorPerson@fefd

BeanClass 是:class testannotationvalidatorPerson

InvalidValue 的長度是: 驗證消息是: 長度必須介於 之間 PropertyPath 是:name

PropertyName 是: name Value 是: ice Bean 是: testannotationvalidatorPerson@fefd

BeanClass 是:class testannotationvalidatorPerson

可以看出 沒有驗證 Address



當然了 你還可以只驗證一個屬性 沒有必要驗證整個類只需要在調用classValidatorgetInvalidValues(page)方法時 加上你要驗證的屬性就可以了如我們只想驗證age 屬性 把代碼改為如下所示:

InvalidValue[] validMessages = classValidatorgetInvalidValues(page); //只驗證age 屬性

運行結果如下:

InvalidValue 的長度是: 驗證消息是: 必須大於等於 PropertyPath 是:age

PropertyName 是: age Value 是: Bean 是: testannotationvalidatorPerson@cb

BeanClass 是:class testannotationvalidatorPerson

只是驗證了 age 屬性



怎麼樣 很簡單吧 關於 Hibernate Validator 內建的驗證Annotations 大家可以看看 API 或者 參考文檔(中文版我正在翻譯中 請訪問我的 Blog 獲得最新信息)

如果你要寫自己的約束呢 你不用擔心 這也是很容易的 任何約束有兩部分組成: [約束描述符 即注釋]the constraint descriptor (the annotation) 和[約束validator 即 實現類] the constraint validator (the implementation class)下面我們擴展Hibernate Test suit 中的一個Test 來講解一下

首先: 要聲明一個constraint descriptor 如下:
package testannotationvalidator;

import javalangannotationDocumented;
import static javalangannotationElementTypeTYPE;
import static javalangannotationElementTypeFIELD;
import static javalangannotationElementTypeMETHOD;
import javalangannotationRetention;
import static javalangannotationRetentionPolicyRUNTIME;
import javalangannotationTarget;

import orghibernatevalidatorValidatorClass;

/**
* Dummy sample of a beanlevel validation annotation
*
* @author Emmanuel Bernard
*/
@ValidatorClass(SerializabilityValidatorclass)
@Target({METHODFIELDTYPE})
@Retention(RUNTIME)
@Documented
public @interface Serializability {
  int num() default ;
  String message() default bean must be serialiable;
}

@ValidatorClass(SerializabilityValidatorclass) 指出了 constraint validator 類

@Target({METHODFIELDTYPE})
@Retention(RUNTIME)
@Documented

  這幾個我就不用解釋了吧

Serializability 裡面聲明了一個 message 顯示約束的提示信息 num 只是為了說明一個方面 在這裡面沒有實際用途用

然後就是 實現一個constraint validator 類 該類要實現Validator<ConstraintAnnotation>這裡是SerializabilityValidatorjava 如下:

  //$Id: SerializabilityValidatorjavav // :: epbernard Exp $
package testannotationvalidator;

import javaioSerializable;

import orghibernatevalidatorValidator;

/**
* Sample of a beanlevel validator
*
* @author Emmanuel Bernard
*/
public class SerializabilityValidator implements Validator<Serializability> Serializable {
  public boolean isValid(Object value) {
   //這裡只是Validator 裡面的 實現驗證規則的 方法 value 是要驗證的值
    Systemoutprintln(IN SerializabilityValidator isValid:+valuegetClass()+: +valuetoString());
    return value instanceof Serializable;
  }

  public void initialize(Serializability parameters) {
    // 在這裡可以 取得 constraint descriptor 裡面的屬性 如上面我們聲明的 num
    Systemoutprintln(IN SerializabilityValidator: parameters:+ parametersnum() );
  }
}

  然後在你的類中應用@Serializability  就可以約束一個類實現Serializable 接口了 如下:

在我們的Personjava類 添加@Serializability  Annotations 把Personjava 中的 //@Serializability //測試自定義約束 注釋去掉就ok了

運行結果如下:

InvalidValue 的長度是: 驗證消息是: bean must be serialiable PropertyPath 是:null

PropertyName 是: null Value 是: testannotationvalidatorPerson@adc Bean 是: testannotationvalidatorPerson@adc

BeanClass 是:class testannotationvalidatorPerson

現在把Person類實現 javaioSerializable 接口 則沒有出現 驗證錯誤消息

消息的國際化也是很簡單的把Serializability  中的message 改為以{}擴住的 屬性文件的Key就可以了

public @interface Serializability {
  int num() default ;
  String message() default {Serializable}; //bean must be serialiable; //消息的國際化
}
然後編輯資料文件 注意 該資源文件中要包括 Hibernate Validator 內建的資源 可以在該org\hibernate\validator\resources 包裡面的資源文件基礎上修改 在打包裡面 這樣就可以了 自己打包可能不太方便你可以把該包裡面的文件復制出來然後放到你自己的項目包下在自己編輯 該測試中 我是放在 test\resources 包下的

然後在 資源文件中添加 Serializable = 這麼一行 樣例如下:

#DefaultValidatorMessagesproperties (DefaultValidatorMessages_zhproperties 不再列出^_^)

 

#下面是 Hibernate Validator 內建的國際化消息

validatorassertFalse=assertion failed

validatorassertTrue=assertion failed

validatorfuture=must be a future date

validatorlength=length must be between {min} and {max}

validatormax=must be less than or equal to {value}

validatormin=must be greater than or equal to {value}

validatornotNull=may not be null

validatorpast=must be a past date

validatorpattern=must match {regex}

validatorrange=must be between {min} and {max}

validatorsize=size must be between {min} and {max}

#下面是自定義的消息

Serializable=Bean not Serializable  //加上自己定義的國際化消息

在構造ClassValidator 時要添上 資源文件 如下:(在測試類中)

ClassValidator<Person> classValidator = new ClassValidator<Person> (PersonclassResourceBundlegetBundle(testresourcesDefaultValidatorMessages));//加載資源

  這樣就可以了   當然 你還可以 更改 Hibernate Validator 的消息(不是在上面的資源文件中直接修改validatorlength = 等等 ) 還記得 Validator 注釋中有個 message 元素嗎? 你以前用的都是默認值現在你可以該為你自己定義的了如:validatorlength 我把他改為 該字符串的長度不符合規定范圍范圍 在資源文件中添加一行鍵值屬性對(key定義為 myMsg)如下:

myMsg=該字符串的長度不符合規定范圍范圍

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

再一次運行測試 我們就可以看到上面兩條自定義綁定的消息了 如下:

InvalidValue 的長度是: 驗證消息是: Bean 不是 可 Serializable PropertyPath 是:null
PropertyName 是: null Value 是: testannotationvalidatorPerson@bd Bean 是: testannotationvalidatorPerson@bd
BeanClass 是:class testannotationvalidatorPerson


InvalidValue 的長度是: 驗證消息是: 該字符串的長度不符合規定范圍范圍 PropertyPath 是:name
PropertyName 是: name Value 是: ice Bean 是: testannotationvalidatorPerson@bd
BeanClass 是:class testannotationvalidatorPerson

  怎麼樣比你想象的簡單吧

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

  看到這裡其實不用我在多說了 大家都知道怎麼用什麼時候用 作為一篇介紹性文章我還是在此給出一個最常用的例子吧更好的使用方式大家慢慢挖掘吧

  比如 : 你現在在開發一個人力資源(HR)系統 (其實是我們ERP課程的一個作業 ^_^) 裡面要處理大量的數據尤其是在輸入各種資料時 如 登記員工信息 如果你公司的員工的年齡要求是 那麼你所輸入的年齡就不能超出這個范圍 你可能會說這很容易啊 不用Validator就可以解決啊這保持數據前驗證就可以啦 如if ( egetAge() > || egetAge() < ) 給出錯誤信息 然後提示重新輸入不就OK啦 用得著 興師動眾的來個第三方框架嗎?

  是啊 當就驗證這一個屬性時 沒有必要啊 ! 但是一個真正的HR 系統會只有一個屬性要驗證嗎? 恐怕要有N多吧

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


From:http://tw.wingwit.com/Article/program/Java/ky/201311/28573.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.