前言:最近項目裏面用到了hibernate-validator做接口的參數校驗,第一感覺很好用,但是返回的提示還不夠友好,這裏全面瞭解一下這個項目的用法和功能。
此工具的中文文檔我有傳到我的下載中 可以在這裏下載 https://download.csdn.net/download/zhanjunpeng01/11217481
什麼是Hibernate validator呢?它是基於JSR-303接口的標準,在數據模型上添加需要校驗的方式(基於註解或者XML擴展),實現對數據模型的驗證框架。
爲什麼要用?1. 將數據驗證從業務代碼中抽離,降低了業務代碼的複雜性。2. 可以在任意地方對實體進行校驗,是否是符合標準的數據。 3. 可以減少很大的工作量,尤其是在數據模型比較龐大的地方。
一、構建基本工程
首先可以根據官方的maven archetype創建一個簡單的項目,瞭解一下這個工具的用法
mvn archetype:generate -DarchetypeGroupId=org.hibernate \
-DarchetypeArtifactId=hibernate-validator-quickstart-archetype \
-DarchetypeVersion=4.2.0.Final \
-DarchetypeRepository=http://repository.jboss.org/nexus/content/
groups/public-jboss/ \
-DgroupId=com.mycompany \
-DartifactId=hv-quickstart
也可以直接在idea裏面創建maven項目,輸入上面的參數創建出項目:
創建出來的工程即包含了一些基礎代碼和測試類
如果創建不出來,可以在maven裏面加一下阿里雲的鏡像試試
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>*</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
二、簡單介紹重要知識點
基礎用法先參考代碼中的Car類,以及CarTest類
給javabean添加校驗註解有三種方式
1. 添加到類的字段上(field level)
2. 添加到字段的get方法上(property level)
3. 添加到類上(class level)
註解到字段上和屬性上的區別好像不太大,官方也比較推薦註解到字段上,
而類級別的驗證,則是由於某些場景,需要多個字段同時滿足條件的時候比較有用。
在父類中定義的約束對子類一樣有效,就像定義在子類上一樣的效果
@Valid用於級聯校驗,如果一個類中引入了另外一個類,比如 ClassRoom類中有 List<Student> 的屬性,那麼在這個屬性上添加@Valid,在這個屬性不爲空的情況下,會對關聯屬性的實體進行數據校驗。而如果@Valid標註的屬性是null,則不會進行校驗
Validator接口是HV(Hibernate Validator)中對實體進行校驗操作的最重要的一個接口。對校驗的功能進行了定義
下面是獲取Validator默認實現的代碼
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
這個接口提供了三個對實體校驗的方法:大致的使用方法爲
Set<ConstraintViolation> violations = validator.xxx( [xxx]... );
返回的violations結果中包含了所有不符合規則定義的錯誤集合,可以接收0個或多個校驗組作爲參數
三個校驗方法分別爲:
1. 對對象的校驗: validate(obj)
2. 對字段的校驗: validateProperty(obj, fieldName)
3. 校驗某個字段使用某個值是否是合法的:validateValue(obj, fieldName, value)
返回的ConstraintViolation集合的主要方法如下:
三、關於驗證失敗的錯誤信息:
每個驗證失敗的消息提示都來自於一個消息模板,聲明一個註解校驗約束的時候,可以通過設置message屬性來更改這個模板。模板中還可以使用佔位符來設置不確定的內容,如下:
同時,你配置的MessageInterpolator可以用來解析這個模板,系統默認的MessageInterpolator會優先查找類路徑下找名稱
爲ValidationMessages.properties的ResourceBundle, 如果能匹配不成功,則去HV自帶的資源文件位於/org/hibernate/
validator/ValidationMessages.properties的ResourceBundle,如下圖:
由此可見,HV支持國際化也是很方便的,正好可以在項目中用到,後面我將會在代碼中測試一下這個功能。
4. 關於校驗組:
校驗組是校驗註解中的一個屬性groups,一個實體內的所有字段,可能在不同的情況下有不同的校驗需求,下面先簡單描述一下,詳細的代碼可以看官方文檔第2.3章節進行了解。
比如,一個商品實體裏面有商品名稱,庫存,是否已審覈三個字段,其中商品是否能上架需要庫存>0, 且是已審覈的,而簡單的保存商品信息則不需要檢查。那麼首先我們需要先定義一個接口表示一個組,這裏我定義了一個空的接口OnSaleCheck.java ,使用接口作爲組的定義而不是字符串是因爲接口可以做到類型安全,而且對重構也比較友好,
定義上架檢查分組的接口類:
public interface OnSaleCheck {
}
在實體類中使用分組,注意看屬性上面的註解屬性groups = {OnSaleCheck.class}
public class Goods {
@NotNull
private String goodsName;
@NotNull
@Min(value = 1, groups = {OnSaleCheck.class})
private Integer stockNum;
@AssertTrue(groups = {OnSaleCheck.class})
private boolean approvedPass;
//get、set方法省略...
}
在測試類中使用:
@Test
public void goodsOnSaleCheck(){
Goods goods = new Goods();
goods.setGoodsName("測試");
goods.setStockNum(0);
goods.setApprovedPass(true);
assertEquals(1, validator.validate(goods, OnSaleCheck.class).size());
assertEquals(0, validator.validate(goods).size());
goods.setGoodsName(null);
assertEquals(2, validator.validate(goods, OnSaleCheck.class, Default.class).size());
}
測試通過,最後兩行的代碼說明,使用了OnSaleCheck.class分組的校驗,纔會對該分組下面的屬性做校驗
需要注意的是,其實每個校驗註解都會有一個分組,如果沒有明確定義,則會使默認分組:javax.validation.groups.Default接口
而validate方法,可以接收多個校驗組作爲參數,如果你想校驗所有的屬性,那麼在validate()方法再加上一個參數Default.class就可以啦
另外需要注意的是,如果是在validate方法中傳入多個校驗組,這些校驗組的校驗是沒有順序的,然而有些時候我們希望能夠按照一定的順序進行校驗,那麼需要再定義一個新的接口,並且用@GroupSequence註解這個接口。
但是,用@GroupSequence註解的接口,聚合了多個校驗組,在發現第一個不符合條件的校驗以後,就會返回,並不會再繼續對後面的其它條件進行校驗。
這裏用校驗組組序列(GroupSequence)做一個例子
定義一個新的接口 OnSaleCheckAll ,我們希望先校驗基礎信息,再校驗是否可以上架
/**
* Describe 先校驗商品基礎信息,再校驗是否可以上架
* Created by zhanjp on 2019/6/1
*/
@GroupSequence({Default.class, OnSaleCheck.class})
public interface OnSaleCheckAll {
}
測試:
這裏我們可以發現,校驗序列組的檢查再發現第一個錯誤之後就返回了。
還有一個需要注意的地方,校驗序列組不可包含循環引用,什麼意思呢?就是校驗序列組A中包含了B,而校驗序列組B中又包含了A,這種情況是會報錯的。
如果想在子類中重新去定義校驗序列組,直接在子類上添加@GroupSequence註解就好了,不過不可再次在@GroupSequence中加入Default.class, 而是用"子類.class"替代,感覺這個不是常用,這裏不再描述,感興趣的可以看2.3.2節
@GroupSequenceProvider註解 是官方提供的一個非標準重新定義校驗序列組的功能,相較於在子類上添加@GroupSequence改變父類的校驗序列組,使用@GroupSequenceProvider可以按照一些條件動態添加校驗組。
5. 關於支持的校驗規則
校驗規則分爲三種,1. java默認支持的規則(註解位於javax.validation.constraints) 2. HV自己實現的規則 (位於org.hibernate.validator.constraints.impl),3. 客戶端自定義(自己開發)
java支持的註解和HV支持的註解,直接可以在開發包中看,這裏不再描述
主要介紹自定義校驗規則
未完待續...