| 注釋 | 用于 | 運行時(shí)檢查 | Hibernate Metadata 兼容 |
| @Length(min=, max=) | property (字符串) | 檢查是字符串長(cháng)度范圍 | 列長(cháng)度被設置到最大 |
| @Max(value=) | property (數字,或代表數字的字符串) | 檢查值是否=或<max | 在列上添加一個(gè)約束 |
| @Min(value=) | property (數字,或代表數字的字符串) | 檢查值是否=或>min | 在列上添加一個(gè)約束 |
| @NotNull | property | 是否null | 列不為null |
| @NotEmpty | property | 字符串不空或非NULl 鏈接不空或非null | 對字符列非null約束 |
| @Past | property (date 或 calendar) | 檢查是否日期在過(guò)去 | 在列上添加一個(gè)約束 |
| @Future | property (date 或 calendar) | 檢查是否日期在將來(lái) | 無(wú) |
| @Pattern(regex="regexp", flag=) or @Patterns( {@Pattern(...)} ) | property (字符串) | 檢查是否屬性匹配規則表達式給定的匹配標志 (see java.util.regex.Pattern ) | 無(wú) |
| @Range(min=, max=) | property (數字,或代表數字的字符串) | 是否值min<=value<=max | 在列上添加一個(gè)約束 |
| @Size(min=, max=) | property (數組, 集合, map) | Min<=Size<=max | 無(wú) |
| @AssertFalse | property | 檢查方法計算到false (多用在代碼里檢查約束) | 無(wú) |
| @AssertTrue | property | 檢查方法計算到true (多用在代碼里檢查約束) | none |
| @Valid | property (對象) | 在一個(gè)關(guān)聯(lián)對象上遞歸的執行檢驗.如果對象是一個(gè)數組或者集合,對象將被遞歸的檢驗. 如果對象是一個(gè)map,元素將被遞歸的驗證. | none |
| @Email | property (String) | 檢查是否字符創(chuàng )符合email規范 | none |
| @CreditCardNumber | property (String) | 字符串是否一個(gè)格式好的信譽(yù)卡號碼(derivative of the Luhn algorithm) | none |
| @Digits | property (數字,或代表數字的字符串) | 數字是否符合整數部分和小數部分的精度 | 定義列精度和范圍 |
| @EAN | property (字符串) | 字符是否是格式化的 EAN 或者 UPC-A 編碼 | none |
| @Digits | property (numeric or string representation of a numeric) | check whether the property is a number having up to integerDigits integer digits and fractionalDigits fractonal digits | define column precision and scale |
1.3.錯誤消息
隨Hibernate 驗證器一起的有一個(gè)被翻譯成十種語(yǔ)言的默認錯誤消息(如果沒(méi)有你所在地區的語(yǔ)言,請發(fā)送給我們一個(gè)補丁)你可以通過(guò)創(chuàng )建一個(gè)ValidatorMessages.properties( ValidatorMessages_loc.properties )文件覆蓋這些消息,甚至當你在寫(xiě)你的驗證器注釋的時(shí)候你可以添加你自己的消息集合。如果hibernate驗證器在你的資源文件里或者ValidatorMessage里不能找到一個(gè)key的對應值,那么他將返回默認的內建值。
作為選擇,當你程序化在一個(gè)bean上檢查驗證規則或者你要一個(gè)完全不同的修改機制時(shí)你可以提供一個(gè)資源綁定,你可以提供一個(gè)org.hibernate.validator.MessageInterpolator接口的實(shí)現。
1.4. 定義你的約束
擴展內建的約束集合非常容易,任何約束有兩個(gè)固定的部分:約束描述器(注釋)
和約束驗證器(實(shí)現的類(lèi))下面是一個(gè)簡(jiǎn)單的用戶(hù)定義的描述器,
@ValidatorClass(CapitalizedValidator.class)@Target(METHOD)@Retention(RUNTIME)@Documentedpublic @interface Capitalized { CapitalizeType type() default Capitalize.FIRST; String message() default "has incorrect capitalization"} Type 是一個(gè)描述屬性如何被使用的參數,這是一個(gè)用戶(hù)的參數完全依賴(lài)注釋業(yè)務(wù)
Message用來(lái)描述約束違反強制性的默認字符串,你可以硬編碼或者部分或者全部利用資源綁定機制。參數值將被注入消息里面當{parameter}字符串被找到(在我們的例子Capitalization is not {type} 將產(chǎn)生 Capitalization is not FIRST )把所有字符串都放在屬性文件ValidatorMessages.properties是個(gè)好的實(shí)踐.
@ValidatorClass(CapitalizedValidator.class)@Target(METHOD)@Retention(RUNTIME)@Documentedpublic @interface Capitalized { CapitalizeType type() default Capitalize.FIRST; String message() default "{validator.capitalized}";} #in ValidatorMessages.propertiesvalidator.capitalized = Capitalization is not {type}
然后你可以看見(jiàn){}符號是遞歸的
為了鏈接一個(gè)描述器到他的驗證器實(shí)現我們用@ValidatorClass元注釋驗證器類(lèi)必須命名一個(gè)實(shí)現了Validator<ConstraintAnnotation>的類(lèi)。
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()方法應該返回false如果約束已經(jīng)被違反,更多的例子請參考內建驗證器實(shí)現.
我們明白屬性級別的驗證,但是你可以寫(xiě)一個(gè)bean級別的驗證注釋。替代于接受返回的實(shí)例屬性,bean自身將被傳進(jìn)驗證器。為了激活驗證檢查,僅僅替代的注釋bean自身。在單元測試里有一個(gè)小的例子。
如果你的約束可以在一些屬性或者類(lèi)型上被應用多次(用不同的參數)你可以用下面的注釋形式
@Target(METHOD)@Retention(RUNTIME)@Documentedpublic @interface Patterns {
Pattern[] value();} @Target(METHOD)@Retention(RUNTIME)@Documented@ValidatorClass(PatternValidator.class)public @interface Pattern { String regexp();}基本上,注釋以一個(gè)驗證器注釋數組的形式包含值屬性
1.5 注釋域模型
由于你現在已經(jīng)熟悉了注釋?zhuān)旅嬲Z(yǔ)法應該是非常熟悉的
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; }} 然而這個(gè)例子僅僅演示了共用的屬性驗證,你也可以以可見(jiàn)的形式注釋
@MyBeanConstraint(max=45public class Dog { @AssertTrue private boolean isMale; @NotNull protected String getName() { ... };...} 也可以注釋接口,hibernate驗證器將檢查所有實(shí)現此接口的子類(lèi)或子接口通過(guò)一個(gè)給定的bean來(lái)讀取合適的驗證注釋。
public interface Named { @NotNull String getName(); ...} public class Dog implements Named { @AssertTrue private boolean isMale; public String getName() { ... }; } Dog類(lèi)的Name屬性將被檢查null約束
第一章 使用驗證框架
Hibernate驗證器有意被用來(lái)實(shí)現多層數據驗證,這些數據約束位于僅一個(gè)地方(被注釋的域模型)并且在應用的不同層被檢查。
這章我們將涵蓋hibernate驗證器在不同層的使用
2.1數據庫模式級別驗證
Out of the box ,hibernate驗證器將把你為你的實(shí)體定義的約束傳進(jìn)映射元數據,例如,如果你實(shí)體的一個(gè)屬性被注釋為@NotNull 他的列將被聲明為 not null 在由hibernate生成的 DDL 里。
使用 hbm2ddl,域模型約束將被在數據庫中表示。
如果 ,因為某些原因,這些特征需要禁用,設置
hibernate.validator.apply_to_ddl 為 false
2.2 ORM 集成
Hibernate 驗證器與hibernate和所有純java的持久化提供者集成。
2.2.1基于hibernate事件的驗證
Hibernate驗證器已經(jīng)內置兩個(gè)hibernate事件監聽(tīng)器,任何時(shí)候一個(gè)PreInsertEvent 或者 PreUpdateEvent事件發(fā)生,監聽(tīng)器將確認這個(gè)實(shí)例的所
有約束并且在當任何約束被違反的時(shí)候拋出一個(gè)異常。一般地,對象將在由hibernate進(jìn)行的插入和更新前被檢查。這個(gè)將被級聯(lián)的應用。這是激活驗證流程最方便和容易的途徑。在驗證違反發(fā)生時(shí),事件將拋出一個(gè)包含了用來(lái)描述每個(gè)失敗消息的InvalidValues類(lèi)型的數組的InvalidStateException類(lèi)型的運行期異常。
如果hibernate 驗證器被放在類(lèi)路徑里,Hibernate Annonations(或Hibernate EntityManager)將透明的使用他,如果由于某些原因需要禁用這個(gè)集成特征設置hibernate.validator.autoregister_listeners 為 false
注意:如果beans沒(méi)有用驗證注釋注釋?zhuān)瑢⒉粫?huì )有運行時(shí)性能消耗
在這種情況下你需要手工為hibernate設置事件監聽(tīng)器,下面是配置
<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在基于事件的驗證上沒(méi)有關(guān)聯(lián),一個(gè)java持久化實(shí)體監聽(tīng)器是可用的。任何時(shí)候一個(gè)被監聽(tīng)的實(shí)體被持久化或者更新,hibernate驗證器將確認所有此實(shí)體實(shí)例的約束并且在約束別違反的時(shí)候拋出異常,一般地,對象將在由java持久化提供者進(jìn)行的插入和更新前被檢查。這個(gè)將被級聯(lián)的應用。在驗證違反發(fā)生時(shí),事件將拋出一個(gè)包含了用來(lái)描述每個(gè)失敗消息的InvalidValues類(lèi)型的數組的InvalidStateException類(lèi)型的運行期異常。
如何使一個(gè)類(lèi)可驗證
@Entity@EntityListeners( JPAValidateListener.class )public class Submarine { ...}注意:與hibernate事件相比 java 持久化監聽(tīng)器有兩個(gè)缺點(diǎn)。你需要為每個(gè)可驗證的實(shí)體定義一個(gè)實(shí)體監聽(tīng)器。由你的提供者生成的DDL 將不會(huì )反射這些約束.
2.3 應用程序級別的驗證
Hibernate 驗證器可被應用到代碼的任何地方
ClassValidator personValidator = new ClassValidator( Person.class );ClassValidator addressValidator = new ClassValidator( Address.class, ResourceBundle.getBundle("messages", Locale.ENGLISH) ); InvalidValue[] validationMessages = addressValidator.getInvalidValues(address);聯(lián)系客服