Hibernate 驗證器文檔
前言:
Annotations 是為域?qū)ο笾付ㄒ粋€不變約束的便利而優(yōu)雅的途徑.例如通過它,你可以表示一個屬性不應(yīng)該是Null值,賬戶余額絕對不能是負(fù)值,等等。這些域模型的約束通過注釋它的屬性聲明在bean自身。驗證器可以讀取這些注釋并檢查約束違反性。驗證機(jī)制可以在沒有重復(fù)這些規(guī)則的情況下在應(yīng)用程序的不同層里執(zhí)行(表示層,數(shù)據(jù)訪問層).Hibernate驗證器在遵循DRY規(guī)則的情況下設(shè)計.
Hibernate 驗證器工作在兩個級別。首先,它能檢測位于內(nèi)存的類實例的約束違反性.其次,它可以把約束應(yīng)用在hibernate的元模型中并且把它們應(yīng)用在生成的數(shù)據(jù)庫中.
每一個約束注釋都與一個為檢查實體實例而實現(xiàn)的驗證器對應(yīng)關(guān)聯(lián)。一個驗證器也可以可選的應(yīng)用約束到hibernate元模型,允許hibernate生成DDL來表達(dá)這些約束。利用合適的事件監(jiān)聽器,你可以通過hibernate在插入或更新的時候檢查約束性。Hibernate驗證器沒有限定在必須配合hibernate執(zhí)行驗證。你也可以容易的把它用在其他java的持久化提供者上面(實現(xiàn)了實體監(jiān)聽器).
在運行期檢查實例時,hibernate驗證器把有關(guān)違反驗證的信息放在一個InvalidValue類型的數(shù)組里返回.在其他信息中,InvalidValue所包含的錯誤描述消息可以嵌入?yún)?shù)值和注釋綁定,并且消息字符串可以以資源文件的形式提供.
第一章 定義約束
1.1 什么是約束
約束是一個給定的元素(可以使field,property,或bean)所必須遵循的規(guī)則.規(guī)則的語義可以由注釋表達(dá)。約束通常有一些屬性用來參數(shù)化約束限制。這些約束應(yīng)用到被注釋的元素。
1.2 內(nèi)建約束
與Hibernate 驗證器一起內(nèi)建了一些約束,他們已經(jīng)覆蓋了大多數(shù)基本的數(shù)據(jù)檢查,當(dāng)然我們后來會看到,你不一定使用它們,你可以在一分鐘內(nèi)寫出你自己的約束。
表 1.1. 內(nèi)建約束
1.3.錯誤消息 隨Hibernate 驗證器一起的有一個被翻譯成十種語言的默認(rèn)錯誤消息(如果沒有你所在地區(qū)的語言,請發(fā)送給我們一個補(bǔ)丁)你可以通過創(chuàng)建一個ValidatorMessages.properties( ValidatorMessages_loc.properties )文件覆蓋這些消息,甚至當(dāng)你在寫你的驗證器注釋的時候你可以添加你自己的消息集合。如果hibernate驗證器在你的資源文件里或者ValidatorMessage里不能找到一個key的對應(yīng)值,那么他將返回默認(rèn)的內(nèi)建值。 作為選擇,當(dāng)你程序化在一個bean上檢查驗證規(guī)則或者你要一個完全不同的修改機(jī)制時你可以提供一個資源綁定,你可以提供一個org.hibernate.validator.MessageInterpolator接口的實現(xiàn)。 1.4. 定義你的約束 擴(kuò)展內(nèi)建的約束集合非常容易,任何約束有兩個固定的部分:約束描述器(注釋) 和約束驗證器(實現(xiàn)的類)下面是一個簡單的用戶定義的描述器, @ValidatorClass(CapitalizedValidator.class)
@Target(METHOD)
@Retention(RUNTIME)
@Documented
public @interface Capitalized {
CapitalizeType type() default Capitalize.FIRST;
String message() default "has incorrect capitalization"
}
Type 是一個描述屬性如何被使用的參數(shù),這是一個用戶的參數(shù)完全依賴注釋業(yè)務(wù) Message用來描述約束違反強(qiáng)制性的默認(rèn)字符串,你可以硬編碼或者部分或者全部利用資源綁定機(jī)制。參數(shù)值將被注入消息里面當(dāng){parameter}字符串被找到(在我們的例子Capitalization is not {type} 將產(chǎn)生 Capitalization is not FIRST )把所有字符串都放在屬性文件ValidatorMessages.properties是個好的實踐. @ValidatorClass(CapitalizedValidator.class)
@Target(METHOD)
@Retention(RUNTIME)
@Documented
public @interface Capitalized {
CapitalizeType type() default Capitalize.FIRST;
String message() default "{validator.capitalized}";
}
#in ValidatorMessages.properties
validator.capitalized = Capitalization is not {type}
然后你可以看見{}符號是遞歸的 為了鏈接一個描述器到他的驗證器實現(xiàn)我們用@ValidatorClass元注釋驗證器類必須命名一個實現(xiàn)了Validator<ConstraintAnnotation>的類。 public class CapitalizedValidator
implements Validator<Capitalized>, PropertyConstraint {
private CapitalizeType type;
//part of the Validator<Annotation> contract,
//allows to get and use the annotation values
public void initialize(Capitalized parameters) {
type = parameters.type();
}
//part of the property constraint contract
public boolean isValid(Object value) {
if (value==null) return true;
if ( !(value instanceof String) ) return false;
String string = (String) value;
if (type == CapitalizeType.ALL) {
return string.equals( string.toUpperCase() );
}
else {
String first = string.substring(0,1);
return first.equals( first.toUpperCase();
}
}
}
isValid()方法應(yīng)該返回false如果約束已經(jīng)被違反,更多的例子請參考內(nèi)建驗證器實現(xiàn). 我們明白屬性級別的驗證,但是你可以寫一個bean級別的驗證注釋。替代于接受返回的實例屬性,bean自身將被傳進(jìn)驗證器。為了激活驗證檢查,僅僅替代的注釋bean自身。在單元測試?yán)镉幸粋€小的例子。 如果你的約束可以在一些屬性或者類型上被應(yīng)用多次(用不同的參數(shù))你可以用下面的注釋形式 @Target(METHOD)
@Retention(RUNTIME)
@Documented
public @interface Patterns { Pattern[] value();
}
@Target(METHOD)
@Retention(RUNTIME)
@Documented
@ValidatorClass(PatternValidator.class)
public @interface Pattern {
String regexp();
}
基本上,注釋以一個驗證器注釋數(shù)組的形式包含值屬性 1.5 注釋域模型 由于你現(xiàn)在已經(jīng)熟悉了注釋,下面語法應(yīng)該是非常熟悉的 public class Address {
private String line1;
private String line2;
private String zip;
private String state;
private String country;
private long id;
// a not null string of 20 characters maximum
@Length(max=20)
@NotNull
public String getCountry() {
return country;
}
// a non null string
@NotNull
public String getLine1() {
return line1;
}
//no constraint
public String getLine2() {
return line2;
}
// a not null string of 3 characters maximum
@Length(max=3) @NotNull
public String getState() {
return state;
}
// a not null numeric string of 5 characters maximum
// if the string is longer, the message will
//be searched in the resource bundle at key ‘long‘
@Length(max=5, message="{long}")
@Pattern(regex="[0-9]+")
@NotNull
public String getZip() {
return zip;
}
// should always be true
@AssertTrue
public boolean isValid() {
return true;
}
// a numeric between 1 and 2000
@Id @Min(1)
@Range(max=2000)
public long getId() {
return id;
}
}
然而這個例子僅僅演示了共用的屬性驗證,你也可以以可見的形式注釋 @MyBeanConstraint(max=45
public class Dog {
@AssertTrue private boolean isMale;
@NotNull protected String getName() { ... };
...
}
也可以注釋接口,hibernate驗證器將檢查所有實現(xiàn)此接口的子類或子接口通過一個給定的bean來讀取合適的驗證注釋。 public interface Named {
@NotNull String getName();
...
}
public class Dog implements Named {
@AssertTrue private boolean isMale;
public String getName() { ... };
}
Dog類的Name屬性將被檢查null約束 第一章 使用驗證框架 Hibernate驗證器有意被用來實現(xiàn)多層數(shù)據(jù)驗證,這些數(shù)據(jù)約束位于僅一個地方(被注釋的域模型)并且在應(yīng)用的不同層被檢查。 這章我們將涵蓋hibernate驗證器在不同層的使用 2.1數(shù)據(jù)庫模式級別驗證 Out of the box ,hibernate驗證器將把你為你的實體定義的約束傳進(jìn)映射元數(shù)據(jù),例如,如果你實體的一個屬性被注釋為@NotNull 他的列將被聲明為 not null 在由hibernate生成的 DDL 里。 使用 hbm2ddl,域模型約束將被在數(shù)據(jù)庫中表示。 如果 ,因為某些原因,這些特征需要禁用,設(shè)置 hibernate.validator.apply_to_ddl 為 false 2.2 ORM 集成 Hibernate 驗證器與hibernate和所有純java的持久化提供者集成。 2.2.1基于hibernate事件的驗證 Hibernate驗證器已經(jīng)內(nèi)置兩個hibernate事件監(jiān)聽器,任何時候一個PreInsertEvent 或者 PreUpdateEvent事件發(fā)生,監(jiān)聽器將確認(rèn)這個實例的所 有約束并且在當(dāng)任何約束被違反的時候拋出一個異常。一般地,對象將在由hibernate進(jìn)行的插入和更新前被檢查。這個將被級聯(lián)的應(yīng)用。這是激活驗證流程最方便和容易的途徑。在驗證違反發(fā)生時,事件將拋出一個包含了用來描述每個失敗消息的InvalidValues類型的數(shù)組的InvalidStateException類型的運行期異常。 如果hibernate 驗證器被放在類路徑里,Hibernate Annonations(或Hibernate EntityManager)將透明的使用他,如果由于某些原因需要禁用這個集成特征設(shè)置hibernate.validator.autoregister_listeners 為 false 注意:如果beans沒有用驗證注釋注釋,將不會有運行時性能消耗 在這種情況下你需要手工為hibernate設(shè)置事件監(jiān)聽器,下面是配置 <hibernate-configuration>
...
<event type="pre-update">
<listener
class="org.hibernate.validator.event.ValidateEventListener"/>
</event>
<event type="pre-insert">
<listener
class="org.hibernate.validator.event.ValidateEventListener"/>
</event>
</hibernate-configuration>
Hibernate 驗證器與hibernate在基于事件的驗證上沒有關(guān)聯(lián),一個java持久化實體監(jiān)聽器是可用的。任何時候一個被監(jiān)聽的實體被持久化或者更新,hibernate驗證器將確認(rèn)所有此實體實例的約束并且在約束別違反的時候拋出異常,一般地,對象將在由java持久化提供者進(jìn)行的插入和更新前被檢查。這個將被級聯(lián)的應(yīng)用。在驗證違反發(fā)生時,事件將拋出一個包含了用來描述每個失敗消息的InvalidValues類型的數(shù)組的InvalidStateException類型的運行期異常。 如何使一個類可驗證 @Entity
@EntityListeners( JPAValidateListener.class )
public class Submarine {
...
}
注意:與hibernate事件相比 java 持久化監(jiān)聽器有兩個缺點。你需要為每個可驗證的實體定義一個實體監(jiān)聽器。由你的提供者生成的DDL 將不會反射這些約束. 2.3 應(yīng)用程序級別的驗證 Hibernate 驗證器可被應(yīng)用到代碼的任何地方 ClassValidator personValidator = new ClassValidator( Person.class );
ClassValidator addressValidator = new ClassValidator( Address.class, ResourceBundle.getBundle("messages", Locale.ENGLISH) );
InvalidValue[] validationMessages = addressValidator.getInvalidValues(address);
|
|