java 開發(fā)中,參數(shù)校驗是非常常見的需求。
鼓樓網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)建站!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站開發(fā)等網(wǎng)站項目制作,到程序開發(fā),運營維護。創(chuàng)新互聯(lián)建站于2013年成立到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)建站。
但是 hibernate-validator 在使用過程中,依然會存在一些問題。
支持 fluent-validation
支持 jsr-303 注解
支持 i18n
支持用戶自定義策略
valid
如今 java 最流行的 hibernate-validator 框架,但是有些場景是無法滿足的。
比如:
驗證新密碼和確認密碼是否相同。(同一對象下的不同屬性之間關(guān)系)
當(dāng)一個屬性值滿足某個條件時,才進行其他值的參數(shù)校驗。
其實,在對于多個字段的關(guān)聯(lián)關(guān)系處理時,hibernate-validator 就會比較弱。
本項目結(jié)合原有的優(yōu)點,進行這一點的功能強化。
validation-api 提供了豐富的特性定義,也同時帶來了一個問題。
實現(xiàn)起來,特別復(fù)雜。
然而我們實際使用中,常常不需要這么復(fù)雜的實現(xiàn)。
valid-api 提供了一套簡化很多的 api,便于用戶自行實現(xiàn)。
hibernate-validator 在使用中,自定義約束實現(xiàn)是基于注解的,針對單個屬性校驗不夠靈活。
本項目中,將屬性校驗約束和注解約束區(qū)分開,便于復(fù)用和拓展。
hibernate-validator 核心支持的是注解式編程,基于 bean 的校驗。
一個問題是針對屬性校驗不靈活,有時候針對 bean 的校驗,還是要自己寫判斷。
本項目支持 fluent-api 進行過程式編程,同時支持注解式編程。
盡可能兼顧靈活性與便利性。
模塊名稱 | 說明 |
---|---|
valid-api | 核心 api 及注解定義 |
valid-core | 針對 valid-api 的核心實現(xiàn) |
valid-jsr | 針對 JSR-303 標準注解的實現(xiàn) |
valid-test | 測試代碼模塊 |
valid-core 默認引入 valid-api
valid-jsr 默認引入 valid-core
JDK1.7+
Maven 3.X+
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>valid-jsr</artifactId>
<version>0.1.2</version>
</dependency>
我們直接利用 jsr 內(nèi)置的約束類:
public void helloValidTest() {
IResult result = ValidBs.on(null, JsrConstraints.notNullConstraint())
.result()
.print();
Assert.assertFalse(result.pass());
}
對應(yīng)日志輸出為:
DefaultResult{pass=false, notPassList=[DefaultConstraintResult{pass=false, message='預(yù)期值為 <not null>,實際值為 <null>', value=null, constraint='NotNullConstraint', expectValue='not null'}], allList=null}
ValidBs 用來進行驗證的引導(dǎo)類,上述的寫法等價于如下:
public void helloValidAllConfigTest() {
IResult result = ValidBs.on(null, JsrConstraints.notNullConstraint())
.fail(Fails.failFast())
.group()
.valid(DefaultValidator.getInstance())
.result()
.print();
Assert.assertFalse(result.pass());
}
Object 可以是對象,也可以是普通的值。
constraints 為對應(yīng)的約束列表,為默認的約束驗證提供便利性。
IConstraint 相關(guān)創(chuàng)建工具類 Constraints
、JsrConstraints
可以指定失敗時的處理策略,支持用戶自定義失敗策略。
實現(xiàn) | 說明 |
---|---|
failOver | 失敗后繼續(xù)驗證,直到驗證完所有屬性 |
failFast | 失敗后快速返回 |
有時候我們希望,只驗證指定某一分組的約束。
可以通過 group() 屬性指定,與 IConstraint 中的 group() 屬性匹配的約束才會被執(zhí)行。
默認為 DefaultValidator,為 valid-api 的實現(xiàn)驗證。
如果你希望使用 jsr-303 注解,可以使用 JsrValidator
。
支持自定義驗證策略。
默認為 simple() 的簡單結(jié)果處理。
可以指定為 detail() 進行詳細結(jié)果處理查看。
支持用戶自定義結(jié)果處理策略。
simple()/detail() 處理的結(jié)果為 IResult 實現(xiàn)類。
IResult 支持如下方法:
對結(jié)果進行打印,主要便于調(diào)試。
對于參數(shù)的校驗,一般都是基于異常結(jié)合 spring aop來處理的。
throwsEx 會在驗證不通過時,拋出 ValidRuntimeException 異常,對應(yīng) message 為提示消息。
@Test(expected = ValidRuntimeException.class)
public void resultThrowsExTest() {
ValidBs.on(null, notNullValidatorEntry())
.valid()
.result()
.throwsEx();
}
上面我們對 ValidBs 有了一個整體的了解,下面來看一看系統(tǒng)內(nèi)置的屬性約束有哪些。
每個屬性約束都有對應(yīng)注解。
針對單個屬性,直接使用屬性約束即可,靈活快捷。
針對 bean 校驗,可以結(jié)合注解實現(xiàn),類似于 hibernate-validator。
核心內(nèi)置屬性約束實現(xiàn)。
枚舉類指定范圍約束
參見工具類 Constraints#enumRangesConstraint
/**
* 枚舉范圍內(nèi)約束
* (1)當(dāng)前值必須在枚舉類對應(yīng)枚舉的 toString() 列表中。
* @param enumClass 枚舉類,不可為空
* @return 約束類
* @since 0.1.1
* @see com.github.houbb.valid.core.annotation.constraint.EnumRanges 枚舉類指定范圍注解
*/
public static IConstraint enumRangesConstraint(final Class<? extends Enum> enumClass)
參見測試類 EnumsRangesConstraintTest
IResult result = ValidBs.on("DEFINE", Constraints.enumRangesConstraint(FailTypeEnum.class))
.result();
Assert.assertFalse(result.pass());
FailTypeEnum 是 valid-api 內(nèi)置的枚舉類,枚舉值為 FAIL_FAST/FAIL_OVER。
只有屬性值在枚舉值范圍內(nèi),驗證才會通過。
指定屬性范圍內(nèi)約束
參見工具類 Constraints#rangesConstraint
* 值在指定范圍內(nèi)約束
* (1)這里為了和注解保持一致性,暫時只支持 String
* @param strings 對象范圍
* @return 約束類
* @since 0.1.1
* @see com.github.houbb.valid.core.annotation.constraint.Ranges String 指定范圍內(nèi)注解
*/
public static IConstraint rangesConstraint(String ... strings)
參見測試類 RangesConstraintTest
IResult result = ValidBs.on("DEFINE", Constraints.rangesConstraint("FAIL_OVER",
"FAIL_FAST"))
.result();
Assert.assertFalse(result.pass());
這個相對于枚舉值,更加靈活一些。
可以根據(jù)自己的需要,指定屬性的范圍。
valid-jsr 中內(nèi)置注解,和 jsr-303 標準一一對應(yīng),此處不再贅述。
創(chuàng)建方式見工具類 JsrConstraints
,測試代碼見 xxxConstraintTest。
對應(yīng)列表如下:
屬性約束 | 注解 | 簡介 |
---|---|---|
AssertFalseConstraint | @AssertFalse | 指定值必須為 false |
AssertTrueConstraint | @AssertTrue | 指定值必須為 true |
MinConstraint | @Min | 指定值必須大于等于最小值 |
MaxConstraint | @Max | 指定值必須小于等于最大值 |
DecimalMinConstraint | @DecimalMin | 指定金額必須大于等于最小值 |
DecimalMaxConstraint | @DecimalMax | 指定金額必須小于等于最大值 |
DigitsConstraint | @Digits | 指定值位數(shù)必須符合要求 |
FutureConstraint | @Future | 指定日期必須在未來 |
PastConstraint | @Past | 指定日期必須在過去 |
PatternConstraint | @Pattern | 指定值必須滿足正則表達式 |
SizeConstraint | @Size | 指定值必須在指定大小內(nèi) |
實際業(yè)務(wù)需求的是不斷變化的,內(nèi)置的屬性約束常常無法滿足我們的實際需求。
我們可以通過自定義屬性,來實現(xiàn)自己的需求。
參見類 DefineConstraintTest
notNullConstraint 對于 null 值是嚴格的。
所以繼承自 AbstractStrictConstraint
,如下:
IResult result = ValidBs.on(null, new AbstractStrictConstraint() {
@Override
protected boolean pass(IConstraintContext context, Object value) {
return value != null;
}
}).result();
Assert.assertFalse(result.pass());
在 jsr-303 標準中,除卻 @NotNull
對于 null 值都是非嚴格校驗的。
繼承自 AbstractConstraint
即可,如下:
IConstraint assertTrueConstraint = new AbstractConstraint<Boolean>() {
@Override
protected boolean pass(IConstraintContext context, Boolean value) {
return false;
}
};
IResult nullValid = ValidBs.on(null, assertTrueConstraint)
.result();
Assert.assertTrue(nullValid.pass());
IResult falseValid = ValidBs.on(false, assertTrueConstraint)
.result();
Assert.assertFalse(falseValid.pass());
注解 | 說明 |
---|---|
@AllEquals | 當(dāng)前字段及指定字段值必須全部相等 |
@HasNotNull | 當(dāng)前字段及指定字段值至少有一個不為 null |
@EnumRanges | 當(dāng)前字段值必須在枚舉屬性范圍內(nèi) |
@Ranges | 當(dāng)前字段值必須在指定屬性范圍內(nèi) |
public class User {
/**
* 名稱
*/
@HasNotNull({"nickName"})
private String name;
/**
* 昵稱
*/
private String nickName;
/**
* 原始密碼
*/
@AllEquals("password2")
private String password;
/**
* 新密碼
*/
private String password2;
/**
* 性別
*/
@Ranges({"boy", "girl"})
private String sex;
/**
* 失敗類型枚舉
*/
@EnumRanges(FailTypeEnum.class)
private String failType;
//fluent getter & setter
}
我們限制 name/nickName 至少有一個不為空,password/password2 值要一致。
以及限定了 sex 的范圍值和 failType 的枚舉值。
User user = new User();
user.sex("what").password("old").password2("new")
.failType("DEFINE");
IResult result = ValidBs.on(user)
.fail(Fails.failOver())
.result()
.print();
Assert.assertFalse(result.pass());
DefaultResult{pass=false, notPassList=[DefaultConstraintResult{pass=false, message='值 <null> 不是預(yù)期值', value=null, constraint='HasNotNullConstraint', expectValue=''}, DefaultConstraintResult{pass=false, message='值 <old> 不是預(yù)期值', value=old, constraint='AllEqualsConstraint', expectValue=''}, DefaultConstraintResult{pass=false, message='值 <what> 不是預(yù)期值', value=what, constraint='RangesConstraint', expectValue=''}, DefaultConstraintResult{pass=false, message='值 <DEFINE> 不是預(yù)期值', value=DEFINE, constraint='EnumRangesConstraint', expectValue=''}], allList=null}
與 jsr-303 注解標準保持一致。
為了演示,簡單定義如下:
public class JsrUser {
@Null
private Object nullVal;
@NotNull
private String notNullVal;
@AssertFalse
private boolean assertFalse;
@AssertTrue
private boolean assertTrue;
@Pattern(regexp = "[123456]{2}")
private String pattern;
@Size(min = 2, max = 5)
private String size;
@DecimalMax("12.22")
private BigDecimal decimalMax;
@DecimalMin("1.22")
private BigDecimal decimalMin;
@Min(10)
private long min;
@Max(10)
private long max;
@Past
private Date past;
@Future
private Date future;
@Digits(integer = 2, fraction = 4)
private Long digits;
//fluent getter and setter
}
參見測試類 ValidBsJsrBeanTest
public void beanFailTest() {
Date future = DateUtil.getFormatDate("90190101", DateUtil.PURE_DATE_FORMAT);
Date past = DateUtil.getFormatDate("20190101", DateUtil.PURE_DATE_FORMAT);
JsrUser jsrUser = new JsrUser();
jsrUser.assertFalse(true)
.assertTrue(false)
.decimalMin(new BigDecimal("1"))
.decimalMax(new BigDecimal("55.55"))
.min(5)
.max(20)
.digits(333333L)
.future(past)
.past(future)
.nullVal("123")
.notNullVal(null)
.pattern("asdfasdf")
.size("22222222222222222222");
IResult result = ValidBs.on(jsrUser)
.fail(Fails.failOver())
.valid(JsrValidator.getInstance())
.result()
.print();
Assert.assertFalse(result.pass());
}
DefaultResult{pass=false, notPassList=[DefaultConstraintResult{pass=false, message='值必須為空', value=123, constraint='NullConstraint', expectValue='null'}, DefaultConstraintResult{pass=false, message='值必須為非空', value=null, constraint='NotNullConstraint', expectValue='not null'}, DefaultConstraintResult{pass=false, message='值必須為假', value=true, constraint='AssertFalseConstraint', expectValue='false'}, DefaultConstraintResult{pass=false, message='值必須為真', value=false, constraint='AssertTrueConstraint', expectValue='true'}, DefaultConstraintResult{pass=false, message='值必須滿足正則表達式', value=asdfasdf, constraint='PatternConstraint', expectValue='必須匹配正則表達式 [123456]{2}'}, DefaultConstraintResult{pass=false, message='值必須為在指定范圍內(nèi)', value=22222222222222222222, constraint='SizeConstraint', expectValue='大小必須在范圍內(nèi) [2, 5]'}, DefaultConstraintResult{pass=false, message='值必須小于金額最大值', value=55.55, constraint='DecimalMaxConstraint', expectValue='小于等于 12.22'}, DefaultConstraintResult{pass=false, message='值必須大于金額最小值', value=1, constraint='DecimalMinConstraint', expectValue='大于等于 1.22'}, DefaultConstraintResult{pass=false, message='值必須大于最小值', value=5, constraint='MinConstraint', expectValue='大于等于 10'}, DefaultConstraintResult{pass=false, message='值必須小于最大值', value=20, constraint='MaxConstraint', expectValue='小于等于 10'}, DefaultConstraintResult{pass=false, message='時間必須在過去', value=Fri Jan 01 00:00:00 CST 9019, constraint='PastConstraint', expectValue='小于等于 Sun Oct 13 12:12:07 CST 2019'}, DefaultConstraintResult{pass=false, message='時間必須在未來', value=Tue Jan 01 00:00:00 CST 2019, constraint='FutureConstraint', expectValue='大于等于 Sun Oct 13 12:12:07 CST 2019'}, DefaultConstraintResult{pass=false, message='值必須滿足位數(shù)', value=333333, constraint='DigitsConstraint', expectValue='整數(shù)位數(shù) [2], 小數(shù)位數(shù) [4]'}], allList=null}
有時候我們一個對象中,會引入其他子對象。
我們希望對子對象也進行相關(guān)屬性的驗證,這時候就可以使用 @Valid
注解。
該注解為 jsr-303 標準注解。
public class ValidUser {
/**
* 子節(jié)點
*/
@Valid
private User user;
//fluent setter & getter
}
參見測試類 ValidBsValidBeanTest
public void beanFailTest() {
User user = new User();
user.sex("default").password("old").password2("new")
.failType("DEFINE");
ValidUser validUser = new ValidUser();
validUser.user(user);
IResult result = ValidBs.on(validUser)
.fail(Fails.failOver())
.result()
.print();
Assert.assertFalse(result.pass());
}
DefaultResult{pass=false, notPassList=[DefaultConstraintResult{pass=false, message='值 <null> 不是預(yù)期值', value=null, constraint='HasNotNullConstraint', expectValue=''}, DefaultConstraintResult{pass=false, message='值 <old> 不是預(yù)期值', value=old, constraint='AllEqualsConstraint', expectValue=''}, DefaultConstraintResult{pass=false, message='值 <default> 不是預(yù)期值', value=default, constraint='RangesConstraint', expectValue=''}, DefaultConstraintResult{pass=false, message='值 <DEFINE> 不是預(yù)期值', value=DEFINE, constraint='EnumRangesConstraint', expectValue=''}], allList=null}
有時候我們可能會引用自身,這個也做了測試,是符合預(yù)期的。
參見 ValidBsSelfValidBeanTest
不同國家對于語言的要求肯定也不同。
本項目目前支持中文/英文國際化支持,默認以當(dāng)前地區(qū)編碼為準,如果不存在,則使用英文。
感覺其他語言,暫時使用中沒有用到。(個人也不會,錯了也不知道。暫時不添加)
測試代碼參加 ValidBsI18NTest
public void i18nEnTest() {
Locale.setDefault(Locale.ENGLISH);
IResult result = ValidBs.on(null, JsrConstraints.notNullConstraint())
.result()
.print();
Assert.assertEquals("Expect is <not null>, but actual is <null>.", result.notPassList().get(0).message());
}
public void i18nZhTest() {
Locale.setDefault(Locale.CHINESE);
IResult result = ValidBs.on(null, JsrConstraints.notNullConstraint())
.result()
.print();
Assert.assertEquals("預(yù)期值為 <not null>,實際值為 <null>", result.notPassList().get(0).message());
}
對于不符合約束條件的處理方式,主要有以下兩種:
快速失敗。遇到一個約束不符合條件,直接返回。
優(yōu)點:耗時較短。
全部驗證,將所有的屬性都驗證一遍。
優(yōu)點:可以一次性獲得所有失敗信息。
參見工具類 Fails
,返回的實例為單例,且線程安全。
參見測試類 ValidBsFailTest
我們指定要求屬性值長度最小為3,且必須滿足正則表達式。
IResult result = ValidBs.on("12", JsrConstraints.sizeConstraintMin(3),
JsrConstraints.patternConstraint("[678]{3}"))
.fail(Fails.failFast())
.result()
.print();
Assert.assertEquals(1, result.notPassList().size());
采用快速失敗模式,只有一個失敗驗證結(jié)果。
DefaultResult{pass=false, notPassList=[DefaultConstraintResult{pass=false, message='預(yù)期值為 <必須匹配正則表達式 [678]{3}>,實際值為 <12>', value=12, constraint='PatternConstraint', expectValue='必須匹配正則表達式 [678]{3}'}], allList=null}
保持其他部分不變,我們調(diào)整下失敗處理策略。
IResult result = ValidBs.on("12", JsrConstraints.sizeConstraintMin(3),
JsrConstraints.patternConstraint("[678]{3}"))
.fail(Fails.failOver())
.result()
.print();
Assert.assertEquals(2, result.notPassList().size());
此時失敗處理結(jié)果為2,日志如下:
DefaultResult{pass=false, notPassList=[DefaultConstraintResult{pass=false, message='預(yù)期值為 <必須匹配正則表達式 [678]{3}>,實際值為 <12>', value=12, constraint='PatternConstraint', expectValue='必須匹配正則表達式 [678]{3}'}, DefaultConstraintResult{pass=false, message='預(yù)期值為 <大小必須在范圍內(nèi) [3, 2147483647]>,實際值為 <2>', value=12, constraint='SizeConstraint', expectValue='大小必須在范圍內(nèi) [3, 2147483647]'}], allList=null}
為了便于集成不同框架的測試驗證,本框架支持 IValidator。
同時也允許用戶自定義自己的實現(xiàn)方式。
指定 valid 對應(yīng)的驗證器,通過 ValidBs.valid(IValidator)
方法指定。
默認為 DefaultValidator。
該驗證策略,支持符合 valid-api 的內(nèi)置注解,及用戶自定義注解。
JsrValidator 支持 jsr-303 標準注解,及 valid-api 標準的相關(guān)注解實現(xiàn)和約束實現(xiàn)。
通過 valid 方法指定即可。
IResult result = ValidBs.on(jsrUser)
.valid(JsrValidator.getInstance())
.result()
.print();
如果你想添加自己的實現(xiàn),直接實現(xiàn) IValidator,并且在 valid() 中指定即可。
可以參考 DefaultValidator,建議繼承自 AbstractValidator
。
對于驗證的結(jié)果,不同的場景,需求也各不相同。
你可能有如下需求:
(1)輸出驗證失敗的信息
(2)輸出所有驗證信息
(3)針對驗證失敗的信息拋出異常
(4)對驗證結(jié)果進行自定義處理。
為了滿足上述需求,提供了如下的接口,及內(nèi)置默認實現(xiàn)。
public interface IResultHandler<T> {
/**
* 對約束結(jié)果進行統(tǒng)一處理
* @param constraintResultList 約束結(jié)果列表
* @return 結(jié)果
*/
T handle(final List<IConstraintResult> constraintResultList);
}
如果你想自定義處理方式,實現(xiàn)此接口。
并在 ValidBs.result(IResultHandler)
方法中指定使用即可。
僅僅對沒有通過測試的驗證結(jié)果進行保留。
參見測試代碼 ValidBsResultHandlerTest
ValidBs.on("12", JsrConstraints.sizeConstraintMin(2))
.result(ResultHandlers.simple())
.print();
DefaultResult{pass=true, notPassList=[], allList=null}
保留所有驗證結(jié)果信息,包含通過驗證測試的明細信息。
參見測試代碼 ValidBsResultHandlerTest
ValidBs.on("12", JsrConstraints.sizeConstraintMin(2))
.result(ResultHandlers.detail())
.print();
DefaultResult{pass=true, notPassList=[], allList=[DefaultConstraintResult{pass=true, message='null', value=12, constraint='SizeConstraint', expectValue='null'}]}
IResult 為驗證結(jié)果處理的內(nèi)置實現(xiàn)接口。
擁有以下常見方法:
方法 | 說明 |
---|---|
pass() | 是否通過驗證 |
notPassList() | 未通過驗證的列表 |
allList() | 所有驗證的列表 |
print() | 控臺輸出驗證結(jié)果 |
throwsEx() | 針對未通過驗證的信息拋出 ValidRuntimeException |
@Test(expected = ValidRuntimeException.class)
public void methodsTest() {
IResult result = ValidBs.on("12", JsrConstraints.sizeConstraintMin(3))
.result(ResultHandlers.detail())
.print()
.throwsEx();
Assert.assertFalse(result.pass());
Assert.assertEquals(1, result.notPassList().size());
Assert.assertEquals(1, result.allList().size());
}
DefaultResult{pass=false, notPassList=[DefaultConstraintResult{pass=false, message='預(yù)期值為 <大小必須在范圍內(nèi) [3, 2147483647]>,實際值為 <2>', value=12, constraint='SizeConstraint', expectValue='大小必須在范圍內(nèi) [3, 2147483647]'}], allList=[DefaultConstraintResult{pass=false, message='預(yù)期值為 <大小必須在范圍內(nèi) [3, 2147483647]>,實際值為 <2>', value=12, constraint='SizeConstraint', expectValue='大小必須在范圍內(nèi) [3, 2147483647]'}]}
Hibernate-validator 主要是基于注解的 Bean 驗證,所以將注解和實現(xiàn)耦合在了一起。
Valid 作為一個 fluent-api 驗證框架,支持過程式編程,所以將針對屬性驗證的約束獨立出來,便于復(fù)用。
public interface IConstraint {
/**
* 觸發(fā)約束規(guī)則
* @param context 上下文
* @return 結(jié)果
* @since 0.0.3
*/
IConstraintResult constraint(final IConstraintContext context);
}
前面的例子已經(jīng)演示了如何自定義實現(xiàn)。
直接實現(xiàn)上述接口也可以,建議繼承 AbstractConstraint
等內(nèi)置的各種約束抽象類。
當(dāng)我們將 IConstraint 獨立出來時,同時有下面的一些問題:
(1)如何指定對應(yīng) message
(2)如何指定約束生效條件 condition
(3)如何指定約束的分組信息 group
IValidEntry 接口就是為了解決這些問題,在 IConstraint 的基礎(chǔ)之上進行一系列的功能增強。
測試代碼,參見類 ValidBsValidEntryTest
IValidEntry validEntry = ValidEntry.of(JsrConstraints.notNullConstraint());
IResult result = ValidBs.on(null, validEntry)
.result()
.print();
Assert.assertFalse(result.pass());
我們可以自定義改約束條件的提示消息。
final IValidEntry validEntry = ValidEntry.of(JsrConstraints.notNullConstraint())
.message("自定義:指定值不能為空");
IResult result = ValidBs.on(null, validEntry)
.valid()
.result();
Assert.assertEquals("自定義:指定值不能為空", result.notPassList().get(0).message());
有時候我們希望只驗證某一種分組的約束條件。
按照如下方式制定,只有當(dāng) ValidEntry 的 group 信息與 ValidBs.group() 符合時,才會被執(zhí)行。
final IValidEntry firstEntry = ValidEntry.of(JsrConstraints.sizeConstraint(5, 10))
.group(String.class);
final IValidEntry otherEntry = ValidEntry.of(JsrConstraints.sizeConstraint(3, 20))
.group(Integer.class);
IResult result = ValidBs
.on("12", firstEntry, otherEntry)
.fail(Fails.failOver())
.group(String.class)
.result();
Assert.assertEquals(1, result.notPassList().size());
其實可以 group() 只是 condition 的一個特例。
后續(xù)將實現(xiàn) ICondition 接口的相關(guān)內(nèi)置支持,和 @Condition
注解的相關(guān)支持。
說到 hibernate-validator,個人覺得最靈魂的設(shè)計就是支持用戶自定義注解了。
注解使得使用便利,自定義注解同時保證了靈活性。
下面來看看,如何實現(xiàn)自定義注解。
你可以認為內(nèi)置注解也是一種自定義注解。
本框架的所有實現(xiàn)理念都是如此,可以認為所有的內(nèi)置實現(xiàn),都是可以被替換的。
我們以 @AllEquals
注解為例,
@Inherited
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(AtAllEqualsConstraint.class)
public @interface AllEquals {
/**
* 當(dāng)前字段及其指定的字段 全部相等
* 1. 字段類型及其他字段相同
* @return 指定的字段列表
*/
String[] value();
/**
* 提示消息
* @return 錯誤提示
*/
String message() default "";
/**
* 分組信息
* @return 分組類
* @since 0.1.2
*/
Class[] group() default {};
}
其中 group()/message() 和 IValidEntry 中的方法一一對應(yīng)。
當(dāng)然你設(shè)計的注解中如果沒有這兩個方法也沒關(guān)系,建議提供這兩個屬性。
@Constraint(AtAllEqualsConstraint.class)
這個注解指定了當(dāng)前注解與對應(yīng)的約束實現(xiàn),是最核心的部分。
@Inherited
@Documented
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraint {
/**
* 約束條件實現(xiàn)類
* @return 實現(xiàn)類 class
*/
Class<? extends IAnnotationConstraint> value();
}
這個就是注解相關(guān)的約束接口,內(nèi)容如下:
/**
* 注解約束規(guī)則接口
* 注意:所有的實現(xiàn)類都需要提供無參構(gòu)造函數(shù)。
* @author binbin.hou
* @since 0.0.9
*/
public interface IAnnotationConstraint<A extends Annotation> extends IConstraint {
/**
* 初始化映射關(guān)系
* @param annotation 注解信息
* @since 0.0.9
*/
void initialize(A annotation);
}
豐富 IConstraintResult 特性
優(yōu)化 IResult 使用體驗
@Condition 注解支持和 ICondition 的支持。
JSR 380
JSR 303
bean validation 2.0
hibernate validate
apache bval
fluent-validator
FluentValidation
分享文章:javabean屬性驗證框架valid
瀏覽路徑:http://chinadenli.net/article4/gdddie.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)、面包屑導(dǎo)航、品牌網(wǎng)站建設(shè)、定制開發(fā)、網(wǎng)站改版、網(wǎng)站設(shè)計
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)