每篇一句
吾皇一日不退役创淡,爾等都是臣子
相關(guān)閱讀
<center>對(duì)Spring感興趣可掃碼加入wx群:Java高工、架構(gòu)師3群
(文末有二維碼)</center>
前言
前幾篇文章在講Spring的數(shù)據(jù)綁定的時(shí)候,多次提到過數(shù)據(jù)校驗(yàn)醋界〔娲瘢可能有人認(rèn)為數(shù)據(jù)校驗(yàn)?zāi)K并不是那么的重要膳帕,因?yàn)橛簿幋a都可以做。若是這么想的話房揭,那就大錯(cuò)特錯(cuò)了~
前面講解DataBinder
的時(shí)候一個(gè)小細(xì)節(jié)备闲,它所在的包是:org.springframework.validation
,并且在分析源碼的時(shí)候能看到DataBinder
它不僅能夠完成數(shù)據(jù)綁定捅暴,也提供了對(duì)數(shù)據(jù)校驗(yàn)的支持且還保存了校驗(yàn)結(jié)果恬砂。
我以數(shù)據(jù)綁定DataBinder
為引子引出了數(shù)據(jù)校驗(yàn)這一塊,是想表明它的重要性蓬痒。連Java都把它抽象成了JSR標(biāo)準(zhǔn)
進(jìn)行提出泻骤,so我認(rèn)為這塊是必修課,有必要了解本章的內(nèi)容。
為什么要有數(shù)據(jù)校驗(yàn)狱掂?
數(shù)據(jù)校驗(yàn) 是非常常見的工作演痒,在日常的開發(fā)中貫穿于代碼的各個(gè)層次,從上層的View層到底層的數(shù)據(jù)層趋惨。
在此處有必要再?gòu)?qiáng)調(diào)一句:前面說了數(shù)據(jù)綁定并不屬于Spring MVC的專利鸟顺,同樣的數(shù)據(jù)校驗(yàn)也不是只會(huì)發(fā)生在web層,它可以在任意一層器虾,從后面的示例中你會(huì)有更深的理解
在任何時(shí)候讯嫂,當(dāng)你要處理一個(gè)應(yīng)用程序的業(yè)務(wù)邏輯,數(shù)據(jù)校驗(yàn)是你必須
要考慮和面對(duì)的事情兆沙。應(yīng)用程序必須通過某種手段來確保輸入進(jìn)來的數(shù)據(jù)從語義上來講是正確的(比如生日必須是過去時(shí)欧芽,年齡必須>0等等~)。
我們知道通常情況下程序肯定是分層的葛圃,不同的層一般由不同的人來開發(fā)千扔。若你是一個(gè)有經(jīng)驗(yàn)的程序員, 我相信你肯定見過在不同的層了都出現(xiàn)了相同的校驗(yàn)代碼库正,這就是某種意義上的垃圾代碼曲楚。
public String queryValueByKey(String parmTemplateCode, String conditionName, String conditionKey, String resultName) {
checkNotNull(parmTemplateCode, "parmTemplateCode not null");
checkNotNull(conditionName, "conditionName not null");
checkNotNull(conditionKey, "conditionKey not null");
checkNotNull(resultName, "resultName not null");
...
}
從這個(gè)簡(jiǎn)單的方法入?yún)⑿r?yàn)至少能發(fā)現(xiàn)如下問題:
- 需要寫大量的代碼來進(jìn)行參數(shù)驗(yàn)證。(這種代碼多了就算垃圾代碼)
- 需要通過注釋來知道每個(gè)入?yún)⒌募s束是什么(否則別人咋看得懂)
- 每個(gè)程序員做參數(shù)驗(yàn)證的方式不一樣诀诊,參數(shù)驗(yàn)證不通過拋出的異常也不一樣(后期幾乎沒法維護(hù))
如上會(huì)導(dǎo)致代碼冗余和一些管理的問題(代碼量越大洞渤,管理起來維護(hù)起來就越困難),比如說語義的一致性等属瓣。為了避免這樣的情況發(fā)生载迄,最好是將驗(yàn)證邏輯與相應(yīng)的域模型(領(lǐng)域模型的概念)進(jìn)行綁定,這就是本文提供的一個(gè)新思路(其實(shí)是JavaEE提供的思路)
為了解決這個(gè)問題抡蛙,Bean Validation
為 JavaBean
驗(yàn)證定義了相應(yīng)的元數(shù)據(jù)模型和 API护昧。默認(rèn)的元數(shù)據(jù)是 各種Java Annotations
,當(dāng)然也支持xml方式并且你也可以擴(kuò)展~
可以說Bean Validation
是JavaBean
的一個(gè)拓展粗截,它可以布局于任意一層代碼惋耙,不局限于Web應(yīng)用還是端應(yīng)用。
Java Bean Validation
JSR是Java Specification Requests
的縮寫熊昌,意思是Java 規(guī)范提案绽榛。關(guān)于數(shù)據(jù)校驗(yàn)這塊,最新的是JSR380
婿屹,也就是我們常說的Bean Validation 2.0
灭美。
Bean Validation 2.0 是JSR第380號(hào)標(biāo)準(zhǔn)。該標(biāo)準(zhǔn)連接如下:https://www.jcp.org/en/egc/view?id=380
Bean Validation的主頁(yè):http://beanvalidation.org
Bean Validation的參考實(shí)現(xiàn):https://github.com/hibernate/hibernate-validator
Bean Validation
是一個(gè)通過配置注解來驗(yàn)證參數(shù)的框架昂利,它包含兩部分Bean Validation API
(規(guī)范)和Hibernate Validator
(實(shí)現(xiàn))届腐。
Bean Validation
是Java定義的一套基于注解/xml的數(shù)據(jù)校驗(yàn)規(guī)范铁坎,目前已經(jīng)從JSR 303
的1.0版本升級(jí)到JSR 349
的1.1版本,再到JSR 380
的2.0版本(2.0完成于2017.08)犁苏,已經(jīng)經(jīng)歷了三個(gè)版本(我截圖如下:)
現(xiàn)在絕大多數(shù)coder使用者其實(shí)都還在使用
Bean Validation 1.1
硬萍,畢竟一般來說它已經(jīng)夠用了~本文會(huì)介紹
Bean Validation 2.0
提供的一些實(shí)用的新東西,畢竟Java8現(xiàn)在已成為主流围详,完全可以使用了~
簡(jiǎn)單Demo示例
要想使用它朴乖,首先就得導(dǎo)包嘛~根據(jù)經(jīng)驗(yàn),和JCache類似Java只提供了規(guī)范短曾,并沒有提供實(shí)現(xiàn)寒砖,所以我們可以先找到它的API包然后導(dǎo)入:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<!-- <version>1.1.0.Final</version> -->
<version>2.0.1.Final</version>
</dependency>
關(guān)于版本之間的差異其實(shí)不是本文說明的重點(diǎn)赐劣,畢竟2.0做到了很好的向下兼容嫉拐,使用起來是無縫的。
但是本處還是給個(gè)1.1版本和2.0.1的截圖魁兼,感官上簡(jiǎn)單對(duì)比一下區(qū)別:
兼容性表格
Bean Validation | Hibernate Validation | JDK | Spring Boot |
---|---|---|---|
1.1 | 5.4 + | 6+ | 1.5.x |
2.0 | 6.0 + | 8+ | 2.0.x |
關(guān)于Bean Validation 2.0的關(guān)注點(diǎn)(新特性)
因?yàn)?.0推出的時(shí)間確實(shí)不算長(zhǎng)婉徘,so此處我把一些重要的關(guān)注點(diǎn)列舉如下:
- 對(duì)Java的最低版本要求是Java 8
- 支持容器的校驗(yàn),通過TYPE_USE類型的注解實(shí)現(xiàn)對(duì)容器內(nèi)容的約束:
List<@Email String>
- 支持日期/時(shí)間的校驗(yàn)咐汞,
@Past
和@Future
- 拓展元數(shù)據(jù)(新增注解):
@Email盖呼,@NotEmpty,@NotBlank化撕,@Positive几晤, @PositiveOrZero,@Negative植阴,@NegativeOrZero蟹瘾,@PastOrPresent和@FutureOrPresent
1. 像@Email、@NotEmpty掠手、@NotBlank
之前是Hibernate額外提供的憾朴,2.0標(biāo)準(zhǔn)后hibernate自動(dòng)退位讓賢并且標(biāo)注為過期了 -
Bean Validation 2.0
的唯一實(shí)現(xiàn)為Hibernate Validator
。(其實(shí)還有Apache BVal
喷鸽,但是你懂的众雷,forget it) - 對(duì)于
Hibernate Validator
,它自己也擴(kuò)展了一些注解支持做祝。
1. 6.0以上版本新增(對(duì)應(yīng)標(biāo)準(zhǔn)2.0版本):@UniqueElements砾省、@ISBN、@CodePointLength混槐、编兄、、纵隔、翻诉、炮姨、、碰煌、
2. 6.0以下版本可以使用的:@URL舒岸、@ScriptAssert、@SafeHtml芦圾、@Range蛾派、@ParameterScriptAssert、@Mod11Check个少、@Mod10Check洪乍、@LuhnCheck、@Length夜焦、@EAN壳澳、@Currency、@CreditCardNumber茫经、@ConstraintComposition巷波、@DurationMax、@DurationMin卸伞、**@REGON抹镊、@PESEL、@NIP荤傲、@TituloEleitoral垮耳、@CPF、@CNPJ**
3.Hibernate Validator
默認(rèn)會(huì)校驗(yàn)完所有的屬性遂黍,然后返回所有的驗(yàn)證失敗信息
终佛。開啟fail fast mode后,只要有一個(gè)驗(yàn)證失敗妓湘,則返回驗(yàn)證失敗信息查蓉。
so,對(duì)于Java Bean Validation
的實(shí)現(xiàn)落地產(chǎn)品就沒啥好選的榜贴,導(dǎo)入Hibernate Validator
(最新版本)吧:
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
</dependency>
==小細(xì)節(jié):==
可以看到豌研,導(dǎo)入了
hibernate-validator
就必要再自己導(dǎo)入Java Bean Validation
API了,因此建議不用再手動(dòng)導(dǎo)入API唬党,交給內(nèi)部來管理依賴鹃共。
定義一個(gè)待校驗(yàn)的普通JavaBean:
@Getter
@Setter
@ToString
public class Person {
// 錯(cuò)誤消息message是可以自定義的
@NotNull(message = "名字不能為null")
public String name;
@Positive
public Integer age;
@NotNull
@NotEmpty
private List<@Email String> emails;
@Future
private Date start;
}
書寫測(cè)試用例:
public static void main(String[] args) {
Person person = new Person();
//person.setName("fsx");
person.setAge(-1);
// email校驗(yàn):雖然是List都可以校驗(yàn)哦
person.setEmails(Arrays.asList("fsx@gmail.com", "baidu@baidu.com", "aaa.com"));
//person.setStart(new Date()); //start 需要是一個(gè)將來的時(shí)間: Sun Jul 21 10:45:03 CST 2019
//person.setStart(new Date(System.currentTimeMillis() + 10000)); //校驗(yàn)通過
// 對(duì)person進(jìn)行校驗(yàn)然后拿到結(jié)果(顯然使用時(shí)默認(rèn)的校驗(yàn)器) 會(huì)保留下校驗(yàn)失敗的消息
Set<ConstraintViolation<Person>> result = Validation.buildDefaultValidatorFactory().getValidator().validate(person);
// 對(duì)結(jié)果進(jìn)行遍歷輸出
result.stream().map(v -> v.getPropertyPath() + " " + v.getMessage() + ": " + v.getInvalidValue())
.forEach(System.out::println);
}
運(yùn)行,報(bào)錯(cuò)啦:
Caused by: java.lang.ClassNotFoundException: javax.el.ELManager
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
...
可以看到運(yùn)行必須依賴于javax.el
這個(gè)包驶拱。(其實(shí)我是比較費(fèi)解的霜浴,為何校驗(yàn)框架非得依賴它呢?有小伙伴可以幫忙解釋一下嗎蓝纲?)
那行阴孟,導(dǎo)入依賴javax.el
以及它的實(shí)現(xiàn):
<!-- 注意這里導(dǎo)入的是Apr, 2013發(fā)布的el3.x的版本晌纫,但是glassfish并沒有對(duì)此版本進(jìn)行支持了 當(dāng)然tomcat肯定是支持的 -->
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.1-b06</version>
</dependency>
<!-- servlet容器大都對(duì)el有實(shí)現(xiàn)(支持jsp的都對(duì)此有實(shí)現(xiàn)),比如tomcat/glassfish等 -->
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.6</version>
</dependency>
需要注意的是永丝,網(wǎng)上大都建議導(dǎo)入
org.glassfish.web
包锹漱。但是EL3.0后它并沒有再提供支持了,因此我個(gè)人是不建議使用它慕嚷,而是使用下面tomcat的實(shí)現(xiàn)的~
關(guān)于EL的實(shí)現(xiàn)此處啰嗦一句:JavaEE并沒有提供el的實(shí)現(xiàn)哥牍,需要容器自行提供,比如上面你想要導(dǎo)入最為流行的tomcat
喝检,你可以導(dǎo)入如下jar即可:
<!-- 嵌入式的tomcat -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>9.0.22</version>
</dependency>
<!-- 傳統(tǒng)的tomcat(需要注意的是:傳統(tǒng)的tomcat這種jar是不需要你手動(dòng)導(dǎo)入的嗅辣,tomcat自帶的) -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper-el</artifactId>
<version>9.0.22</version>
<scope>provided</scope>
</dependency>
此處還需要說明一點(diǎn)的是:嵌入式tomcat(比如SpringBoot環(huán)境)若要使用時(shí)需要顯示導(dǎo)入的。但是傳統(tǒng)tomcat中你若要使用是不用自己導(dǎo)入的(tomcat自帶此jar)挠说。
但是澡谭,但是,但是自從tomcat8.5后不再自帶jsper-el的包了纺涤,需要手動(dòng)導(dǎo)入译暂。(tomcat7還是有的~)
==最佳實(shí)踐:==
一般來說,javax.el-api
以及validation-api
都是沒有必要單獨(dú)導(dǎo)入的撩炊,第三方包都會(huì)自帶。所以絕大數(shù)情況下崎脉,我們只需要這么導(dǎo)入即可正常work拧咳,形如下面這樣非常趕緊整潔:
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>9.0.22</version>
</dependency>
此處可能有伙伴會(huì)問:為何自己在使用的時(shí)候從來都沒有導(dǎo)入過EL相關(guān)Jar包,也能正常數(shù)據(jù)校驗(yàn)?zāi)兀?/h6>
答:那是因?yàn)榻^大多數(shù)情況下你使用@Valid是使用在Spring MVC上囚灼,它是不依賴于EL方式的骆膝,下篇文章會(huì)詳細(xì)說明關(guān)于數(shù)據(jù)校驗(yàn)在Spring上的使用。而本文主要還是講解API的方式~
經(jīng)過一番導(dǎo)包后灶体,再次運(yùn)行打印如下(方式一阅签、方式二結(jié)果一致):
name名字不能為null: null // 此處錯(cuò)誤消息是自己的自定義內(nèi)容
age必須是正數(shù): -1
emails[2].<list element>不是一個(gè)合法的電子郵件地址: aaa.com
這樣通過API調(diào)用的方式就完成了對(duì)這個(gè)JavaBean
的屬性校驗(yàn)~
核心API分析
Validation
官方給它的定義為:This class is the entry point for Bean Validation.
它作為校驗(yàn)的入口,有三種方式來啟動(dòng)它:
- 最簡(jiǎn)單方式:使用默認(rèn)的
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
雖然是默認(rèn)的單也會(huì)有如下2種情況:
1. 若使用了xml配置了一個(gè)provider蝎抽,那就會(huì)使用這個(gè)provider來提供Factory
2. 若沒有xml或者xml力沒有配置provider政钟,那就是用默認(rèn)的ValidationProviderResolver
實(shí)現(xiàn)類來處理 - 方式二:選擇自定義的
ValidationProviderResolver
來跟XML配置邏輯選出一個(gè)ValidationProvider
來。大致代碼如下:
Configuration configuration = Validation.byDefaultProvider()
.providerResolver(new MyResolverStrategy()) // 自定義一個(gè)ValidationProviderResolver的實(shí)現(xiàn)類
.configure();
ValidatorFactory factory = configuration.buildValidatorFactory();
- 第三種方式就更加自由了:你可以直接提供一個(gè)類型安全的
ValidationProvider
實(shí)現(xiàn)樟结。比如HibernateValidator
就是一個(gè)ValidationProvider
的實(shí)現(xiàn):
HibernateValidatorConfiguration configuration = Validation.byProvider(HibernateValidator.class)
// .providerResolver( ... ) // 因?yàn)橹贫薖rovider养交,這個(gè)參數(shù)就可選了
.configure()
.failFast(false);
ValidatorFactory validatorFactory = configuration.buildValidatorFactory();
這三種初始化方式,在源碼處就是對(duì)應(yīng)提供的三個(gè)public static
方法:
public class Validation {
// 方式一
public static ValidatorFactory buildDefaultValidatorFactory() {
return byDefaultProvider().configure().buildValidatorFactory();
}
// 方式二
public static GenericBootstrap byDefaultProvider() {
return new GenericBootstrapImpl();
}
// 方式三
public static <T extends Configuration<T>, U extends ValidationProvider<T>> ProviderSpecificBootstrap<T> byProvider(Class<U> providerType) {
return new ProviderSpecificBootstrapImpl<>( providerType );
}
...
}
對(duì)于若你想使用xml文件獨(dú)立配置校驗(yàn)規(guī)則瓢宦,可以使用Configuration.addMapping(new FileInputStream(validationFile));
碎连,現(xiàn)在很少這么使用,略~
使用注意事項(xiàng):ValidatorFactory
被創(chuàng)建后應(yīng)該緩存起來再提供使用驮履,因?yàn)樗强h城安全的鱼辙。
因?yàn)楝F(xiàn)在都會(huì)使用Hibernate-Validation
來處理校驗(yàn)廉嚼,因此此處只關(guān)心方式三~
HibernateValidatorConfiguration
此接口表示配置,繼承自標(biāo)注接口javax.validation.Configuration
倒戏。很明顯前鹅,它是HibernateValidator
的專屬配置類
先看頂級(jí)接口:
javax.validation.Configuration
,為構(gòu)建ValidatorFactory
的配置類峭梳。默認(rèn)情況下舰绘,它會(huì)讀取配置文件META-INF/validation.xml
,Configuration提供的API方法是覆蓋xml配置文件項(xiàng)的葱椭。若沒有找到validation.xml
捂寿,就會(huì)使用默認(rèn)的ValidationProviderResolver
也就是:DefaultValidationProviderResolver
。
public interface Configuration<T extends Configuration<T>> {
// 該方法調(diào)用后就不會(huì)再去找META-INF/validation.xml了
T ignoreXmlConfiguration();
// 消息內(nèi)插器 它是個(gè)狠角色孵运,關(guān)于它的使用場(chǎng)景秦陋,后續(xù)會(huì)有詳解(包括Spring都實(shí)現(xiàn)了它來做事)
// 它的作用是:插入給定的約束沖突消息
T messageInterpolator(MessageInterpolator interpolator);
// 確定bean驗(yàn)證提供程序是否可以訪問屬性的協(xié)定。對(duì)每個(gè)正在驗(yàn)證或級(jí)聯(lián)的屬性調(diào)用此約定治笨。(Spring木有實(shí)現(xiàn)它)
// 對(duì)每個(gè)正在驗(yàn)證或級(jí)聯(lián)的屬性都會(huì)調(diào)用此約定
// Traversable: 可移動(dòng)的
T traversableResolver(TraversableResolver resolver);
// 創(chuàng)建ConstraintValidator的工廠
// ConstraintValidator:定義邏輯以驗(yàn)證給定對(duì)象類型T的給定約束A驳概。(A是個(gè)注解類型)
T constraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory);
// ParameterNameProvider:提供Constructor/Method的方法名們
T parameterNameProvider(ParameterNameProvider parameterNameProvider);
// java.time.Clock 用作判定@Future和@Past(默認(rèn)取值當(dāng)前時(shí)間)
// 若你希望他是個(gè)邏輯實(shí)現(xiàn),提供一個(gè)它即可
// @since 2.0
T clockProvider(ClockProvider clockProvider);
// 值提取器旷赖。這是add哦~ 負(fù)責(zé)從Optional顺又、List等這種容器里提取值~
// @since 2.0
T addValueExtractor(ValueExtractor<?> extractor);
// 加載xml文件
T addMapping(InputStream stream);
// 添加特定的屬性給Provider用的。此屬性等效于XML配置屬性稚照。
// 此方法通常是框架自己分析xml文件得到屬性值然后放進(jìn)去,調(diào)用者一般不使用(當(dāng)然也可以用)
T addProperty(String name, String value);
// 下面都是get方法嘍
MessageInterpolator getDefaultMessageInterpolator();
TraversableResolver getDefaultTraversableResolver();
ConstraintValidatorFactory getDefaultConstraintValidatorFactory();
ParameterNameProvider getDefaultParameterNameProvider();
ClockProvider getDefaultClockProvider();
BootstrapConfiguration getBootstrapConfiguration(); // 整個(gè)配置也可返回出去
// 上面都是工作俯萌,這個(gè)方法才是最終需要調(diào)用的:得到一個(gè)ValidatorFactory
ValidatorFactory buildValidatorFactory();
}
該接口提供了一些標(biāo)準(zhǔn)的配置項(xiàng)果录。在實(shí)際應(yīng)用中都是使用Hibernate Validation
,所以再看看這個(gè)具體的子接口:
public interface HibernateValidatorConfiguration extends Configuration<HibernateValidatorConfiguration> {
// 這批屬性咐熙,證明直接可以通過System屬性值來控制弱恒,大大地方便~
// 這個(gè)機(jī)制快速失敗機(jī)制:true檢查完一個(gè)有錯(cuò)誤就返回,false全部檢查完把錯(cuò)誤消息一起返回 默認(rèn)false
String FAIL_FAST = "hibernate.validator.fail_fast";
String ALLOW_PARAMETER_CONSTRAINT_OVERRIDE = "hibernate.validator.allow_parameter_constraint_override";
String ALLOW_MULTIPLE_CASCADED_VALIDATION_ON_RESULT = "hibernate.validator.allow_multiple_cascaded_validation_on_result";
String ALLOW_PARALLEL_METHODS_DEFINE_PARAMETER_CONSTRAINTS = "hibernate.validator.allow_parallel_method_parameter_constraint";
// @since 5.2
@Deprecated
String CONSTRAINT_MAPPING_CONTRIBUTOR = "hibernate.validator.constraint_mapping_contributor";
// @since 5.3
String CONSTRAINT_MAPPING_CONTRIBUTORS = "hibernate.validator.constraint_mapping_contributors";
// @since 6.0.3
String ENABLE_TRAVERSABLE_RESOLVER_RESULT_CACHE = "hibernate.validator.enable_traversable_resolver_result_cache";
// @since 6.0.3 ScriptEvaluatorFactory:執(zhí)行腳本
@Incubating
String SCRIPT_EVALUATOR_FACTORY_CLASSNAME = "hibernate.validator.script_evaluator_factory";
// @since 6.0.5 comparing date/time in temporal constraints. In milliseconds.
@Incubating
String TEMPORAL_VALIDATION_TOLERANCE = "hibernate.validator.temporal_validation_tolerance";
// ResourceBundleMessageInterpolator用于 load resource bundles
ResourceBundleLocator getDefaultResourceBundleLocator();
// 創(chuàng)建一個(gè)ConstraintMapping:通過編程API配置的約束映射
// 設(shè)置映射后棋恼,必須通過addMapping(constraintmapping)將其添加到此配置中返弹。
ConstraintMapping createConstraintMapping();
// 拿到所有的值提取器 @since 6.0
@Incubating
Set<ValueExtractor<?>> getDefaultValueExtractors();
// 往下就開始配置了~~~~~~~~~~
HibernateValidatorConfiguration addMapping(ConstraintMapping mapping);
HibernateValidatorConfiguration failFast(boolean failFast);
// used for loading user-provided resources:
HibernateValidatorConfiguration externalClassLoader(ClassLoader externalClassLoader);
// true:表示允許覆蓋約束的方法。false表示不予許(拋出異常) 默認(rèn)值是false
HibernateValidatorConfiguration allowOverridingMethodAlterParameterConstraint(boolean allow);
// 定義是否允許對(duì)返回值標(biāo)記多個(gè)約束以進(jìn)行級(jí)聯(lián)驗(yàn)證蘸泻。 默認(rèn)是false
HibernateValidatorConfiguration allowMultipleCascadedValidationOnReturnValues(boolean allow);
// 定義約束的**并行方法**是否應(yīng)引發(fā)ConstraintDefinitionException
HibernateValidatorConfiguration allowParallelMethodsDefineParameterConstraints(boolean allow);
// 是否允許緩存TraversableResolver 默認(rèn)值是true
HibernateValidatorConfiguration enableTraversableResolverResultCache(boolean enabled);
// 設(shè)置一個(gè)腳本執(zhí)行器
@Incubating
HibernateValidatorConfiguration scriptEvaluatorFactory(ScriptEvaluatorFactory scriptEvaluatorFactory);
// 允許在時(shí)間約束中比較日期/時(shí)間時(shí)設(shè)置可接受的誤差范圍
// 比如@Past @PastOrPresent @Future @FutureOrPresent
@Incubating
HibernateValidatorConfiguration temporalValidationTolerance(Duration temporalValidationTolerance);
// 允許設(shè)置將傳遞給約束驗(yàn)證器的有效負(fù)載琉苇。如果多次調(diào)用該方法,則只傳播最后傳遞的有效負(fù)載悦施。
@Incubating
HibernateValidatorConfiguration constraintValidatorPayload(Object constraintValidatorPayload);
}
關(guān)于此接口的唯一實(shí)現(xiàn)類:ConfigurationImpl
并扇,這里就不用再做分析了,因?yàn)閷?duì)于Validation
這塊抡诞,咱們面向接口編程是完全沒有問題的~
準(zhǔn)備好了Configuration
后穷蛹,下一步顯然就是configuration.buildValidatorFactory()
來得到一個(gè)ValidatorFactory
嘍土陪,關(guān)于ValidatorFactory
這塊的內(nèi)容,請(qǐng)聽下文分解~
總結(jié)
該文講解是關(guān)于Bean Validation
數(shù)據(jù)校驗(yàn)肴熏,在現(xiàn)在Spring的高度封裝下卧晓,越來越少的人能夠主動(dòng)去發(fā)現(xiàn)Java實(shí)現(xiàn)/標(biāo)準(zhǔn)了~
實(shí)際上Spring
的強(qiáng)大并不是自己創(chuàng)造了多少輪子拉盾,而是它主要是帶來了更為簡(jiǎn)單的抽象性含,從而減少樣板代碼稽物、促進(jìn)解耦、提高可單測(cè)性鸦做。因此對(duì)于有些常用的功能還是建議稍微了解多一點(diǎn)励烦,做到心中有數(shù),運(yùn)用起來也才會(huì)更加的游刃有余
知識(shí)交流
若文章格式混亂泼诱,可點(diǎn)擊
:原文鏈接-原文鏈接-原文鏈接-原文鏈接-原文鏈接
==The last:如果覺得本文對(duì)你有幫助坛掠,不妨點(diǎn)個(gè)贊唄。當(dāng)然分享到你的朋友圈讓更多小伙伴看到也是被作者本人許可的~
==
若對(duì)技術(shù)內(nèi)容感興趣可以加入wx群交流:Java高工治筒、架構(gòu)師3群
屉栓。
若群二維碼失效,請(qǐng)加wx號(hào):fsx641385712
(或者掃描下方wx二維碼)耸袜。并且備注:"java入群"
字樣友多,會(huì)手動(dòng)邀請(qǐng)入群