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