使用SpringMVC時(shí)配合hibernate-validate進(jìn)行參數(shù)的合法性校驗(yàn),驗(yàn)證客戶輸入的數(shù)據(jù)是否合法捆昏,能節(jié)省一定的代碼量赚楚。
1. 搭建Web工程并引入hibernate-validate依賴
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.2.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-cdi</artifactId>
<version>6.1.2.Final</version>
</dependency>
2. SpringMVC.xml配置
<!-- 將校驗(yàn)器交給適配器 -->
<mvc:annotation-driven validator="validator"></mvc:annotation-driven>
<!-- 配置校驗(yàn)器 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<!-- 提供校驗(yàn)的類 -->
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
<!-- 可以配置國際化錯(cuò)誤信息保存的文件,也可在校驗(yàn)注解使用message屬性進(jìn)行配置但會(huì)失去國際化的功能 -->
<property name="validationMessageSource" ref="messageSource"></property>
</bean>
<!-- 讀取外部配置文件 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<!-- 文件路徑 -->
<property name="basenames">
<array>
<value>classpath:CustomValidationMessages</value>
</array>
</property>
<!-- 設(shè)置編碼格式 -->
<property name="defaultEncoding" value="utf-8"></property>
<!-- 文件緩存的時(shí)間 :以秒為單位 -->
<property name="cacheSeconds" value="60"></property>
</bean>
自定義校驗(yàn)信息提示文件CustomValidationMessages.properties
emp.empno=\u96C7\u5458\u7F16\u53F7\u53EA\u80FD\u4E3A\u56DB\u4F4D\u6570\u5B57\u7EC4\u6210 //雇員編號(hào)只能為四位數(shù)字組成
emp.ename=\u96C7\u5458\u59D3\u540D\u53EA\u80FD\u7531\u6570\u5B57\u3001\u5B57\u6BCD\u3001\u4E0B\u5212\u7EBF\u3001\u957F\u77ED\u5FC5\u987B\u57286-10\u4F4D\u4E4B\u95F4 //雇員編號(hào)只能為四位數(shù)字組成
emp.job=\u804C\u4F4D\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A //職位名稱不能為空
emp.email=\u975E\u6CD5\u90AE\u7BB1 //非法郵箱
3. 使用校驗(yàn)注解標(biāo)注在屬性上(DTO)
*每個(gè)注解都有message屬性骗卜,該屬性用于填寫校驗(yàn)失敗時(shí)的異常描述信息宠页,當(dāng)校驗(yàn)失敗時(shí)可以獲取對(duì)應(yīng)的message屬性值。
4. Spring MVC 數(shù)據(jù)校驗(yàn)
- Spring 4.0 擁有自己獨(dú)立的數(shù)據(jù)校驗(yàn)框架寇仓,同時(shí)支持 JSR 303 標(biāo)準(zhǔn)的校驗(yàn)框架举户。
- Spring 在進(jìn)行數(shù)據(jù)綁定時(shí),可同時(shí)調(diào)用校驗(yàn)框架完成數(shù)據(jù)校驗(yàn)工作遍烦。在 Spring MVC 中俭嘁,可直接通過注解驅(qū)動(dòng)的方式進(jìn)行數(shù)據(jù)校驗(yàn)
- Spring 的 LocalValidatorFactroyBean 既實(shí)現(xiàn)了 Spring 的 Validator 接口,也實(shí)現(xiàn)了 JSR 303 的 Validator 接口服猪。只要在 Spring 容器中定義了一個(gè) LocalValidatorFactoryBean供填,即可將其注入到需要數(shù)據(jù)校驗(yàn)的 Bean 中拐云。
- Spring 本身并沒有提供 JSR303 的實(shí)現(xiàn),所以必須將 JSR303 的實(shí)現(xiàn)者的 jar 包放到類路徑下近她。
- <mvc:annotation-driven/> 會(huì)默認(rèn)裝配好一個(gè) LocalValidatorFactoryBean慨丐,通過在處理方法的入?yún)⑸蠘?biāo)注 @valid 注解即可讓 Spring MVC 在完成數(shù)據(jù)綁定后執(zhí)行數(shù)據(jù)校驗(yàn)的工作
- Spring MVC 是通過對(duì)處理方法簽名的規(guī)約來保存校驗(yàn)結(jié)果的:前一個(gè)表單/命令對(duì)象的校驗(yàn)結(jié)果保存到隨后的入?yún)⒅校@個(gè)保存校驗(yàn)結(jié)果的入?yún)⒈仨毷?BindingResult 或 Errors 類型泄私,這兩個(gè)類都位于 org.springframework.validation 包中
- 需校驗(yàn)的 Bean 對(duì)象和其綁定結(jié)果對(duì)象或錯(cuò)誤對(duì)象時(shí)成對(duì)出現(xiàn)的,它們之間不允許聲明其他的入?yún)?/strong>
- Errors 接口提供了獲取錯(cuò)誤信息的方法备闲,如 getErrorCount() 或 getFieldErrors(String field)
-
BindingResult 擴(kuò)展了 Errors 接口
image.png
5. 使用@Validated/@Valid注解開啟對(duì)參數(shù)的校驗(yàn)
- @Validated注解表示開啟Spring的校驗(yàn)機(jī)制晌端,支持分組校驗(yàn),聲明在入?yún)⑸稀?/li>
- @Valid注解表示開啟Hibernate的校驗(yàn)機(jī)制,不支持分組校驗(yàn),聲明在入?yún)⑸稀?/li>
- 在DTO后面緊跟BindingResult對(duì)象恬砂,那么當(dāng)參數(shù)不符合時(shí)咧纠,能通過該對(duì)象直接獲取不符合校驗(yàn)的message描述信息。
- 若使用了@Validated/@Valid注解開啟校驗(yàn)泻骤,但DTO后面沒有緊跟BindingResult對(duì)象漆羔,那么當(dāng)參數(shù)不符合時(shí),將直接返回400 Bad Request狀態(tài)碼狱掂。
6. 在頁面上顯示錯(cuò)誤(需要引入SpringMVC表單標(biāo)簽庫)
- Spring MVC 除了會(huì)將表單/命令對(duì)象的校驗(yàn)結(jié)果保存到對(duì)應(yīng)的 BindingResult 或 Errors 對(duì)象中外演痒,還會(huì)將所有校驗(yàn)結(jié)果保存到 “隱含模型”
- 即使處理方法的簽名中沒有對(duì)應(yīng)于表單/命令對(duì)象的結(jié)果入?yún)ⅲr?yàn)結(jié)果也會(huì)保存在 “隱含對(duì)象” 中趋惨。
- 隱含模型中的所有數(shù)據(jù)最終將通過 HttpServletRequest 的屬性列表暴露給 JSP 視圖對(duì)象鸟顺,因此在 JSP 中可以獲取錯(cuò)誤信息
- 在 JSP 頁面上可通過 <form:errors path=“userName”> 顯示錯(cuò)誤消息
7. 示例
public class Emp {
@Max(value = 9999L)
@Min(value = 1000)
private int empno;
@Pattern(regexp = "[0-9A-Za-z_]{6,10}", message = "雇員姓名只能由數(shù)字、字母器虾、下劃線讯嫂、長短必須在6-10位之間")
private String ename;
@NotBlank(message = "工作不能為空")
private String job;
private int mgr;
private Date hiredate;
@Email(message = "非法郵箱!")
private String email;
private double sal;
private double comm;
private Dept dept;
...
@RequestMapping("/adduser")
public void addUser(@Validated Emp emp, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
List<ObjectError> errors = bindingResult.getAllErrors();
for (ObjectError objectError : errors) {
System.out.println(objectError.getDefaultMessage());
}
}
System.out.println(emp.getHiredate());
}
8. 提示消息的國際化
上述例子代碼中,我們自定義錯(cuò)誤消息兆沙,使用了message 屬性來自定義消息描述欧芽,但是這樣做我們就失去了國際化的功能,消息國際化我們可以通過編寫國際化配置文件來實(shí)現(xiàn)
當(dāng)使用 Spring MVC 標(biāo)簽顯示錯(cuò)誤消息時(shí)葛圃, Spring MVC 會(huì)查看 WEB 上下文是否裝配了對(duì)應(yīng)的國際化消息千扔,如果沒有,則顯示默認(rèn)的錯(cuò)誤消息装悲,否則使用國際化消息昏鹃。
配置校驗(yàn)器以及國際化配置文件
<!-- 將校驗(yàn)器交給適配器 -->
<mvc:annotation-driven validator="validator"></mvc:annotation-driven>
<!-- 配置校驗(yàn)器 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<!-- 提供校驗(yàn)的類 -->
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
<!-- 可以配置國際化錯(cuò)誤信息保存的文件,也可在校驗(yàn)注解使用message屬性進(jìn)行配置但會(huì)失去國際化的功能 -->
<property name="validationMessageSource" ref="messageSource"></property>
</bean>
<!-- 讀取外部配置文件 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<!-- 文件路徑 -->
<property name="basenames">
<array>
<value>classpath:CustomValidationMessages</value>
</array>
</property>
<!-- 設(shè)置編碼格式 -->
<property name="defaultEncoding" value="utf-8"></property>
<!-- 文件緩存的時(shí)間 :以秒為單位 -->
<property name="cacheSeconds" value="60"></property>
</bean>
自定義校驗(yàn)信息提示文件CustomValidationMessages.properties
emp.empno=\u96C7\u5458\u7F16\u53F7\u53EA\u80FD\u4E3A\u56DB\u4F4D\u6570\u5B57\u7EC4\u6210 //雇員編號(hào)只能為四位數(shù)字組成
emp.ename=\u96C7\u5458\u59D3\u540D\u53EA\u80FD\u7531\u6570\u5B57\u3001\u5B57\u6BCD\u3001\u4E0B\u5212\u7EBF\u3001\u957F\u77ED\u5FC5\u987B\u57286-10\u4F4D\u4E4B\u95F4 //雇員編號(hào)只能為四位數(shù)字組成
emp.job=\u804C\u4F4D\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A //職位名稱不能為空
emp.email=\u975E\u6CD5\u90AE\u7BB1 //非法郵箱
校驗(yàn)?zāi)繕?biāo)類
public class Emp {
@Max(value = 9999L)
@Min(value = 1000)
private int empno;
@Pattern(regexp = "[0-9A-Za-z_]{6,10}", message = "{emp.ename}")
private String ename;
@NotBlank(message = "{emp.job}")
private String job;
private int mgr;
private Date hiredate;
@Email(message = "{emp.email}")
private String email;
private double sal;
private double comm;
private Dept dept;// 一對(duì)一
...
9.分組校驗(yàn)
9.1. 什么是分組校驗(yàn)诀诊?
校驗(yàn)規(guī)則是在pojo 制定的洞渤,而同一個(gè)pojo可以被多個(gè)Controller使用,此時(shí)會(huì)有問題属瓣,即:不同的Controller方法對(duì)同一個(gè)pojo進(jìn)行校驗(yàn)载迄,此時(shí)這些校驗(yàn)信息是共享在這不同的Controller方法中讯柔,但是實(shí)際上每個(gè)Controller方法可能需要不同的校驗(yàn),在這種情況下护昧,就需要使用分組校驗(yàn)來解決這種問題魂迄。
通俗的講,一個(gè)pojo中有很多屬性惋耙,controller中的方法1可能只需要校驗(yàn)pojo中的屬性1捣炬,controller中的方法2只需要校驗(yàn)pojo中的屬性2,但是pojo中的校驗(yàn)注解有很多绽榛,怎樣才能使方法1只校驗(yàn)屬性1湿酸,方法二只校驗(yàn)屬性2呢?就需要用分組校驗(yàn)來解決了灭美。
9.2. 定義分組
就是定義空的接口推溃,接口類只作為這個(gè)分組標(biāo)識(shí)來使用,看下面的用法届腐,就知道其意義何在了
9.3. 使用分組
9.4. controller方法
在這個(gè)方法中铁坎,那么就只會(huì)校驗(yàn)Emp這個(gè)pojo中有Group1.class這個(gè)分組的校驗(yàn)注解,而不會(huì)在校驗(yàn)其他的
10 擴(kuò)展知識(shí)
使用SpringMVC表單標(biāo)簽庫來參數(shù)校驗(yàn)https://www.cnblogs.com/hemou/p/12356175.html
SpringMVC表單標(biāo)簽庫http://www.reibang.com/p/b1f2d50b671c
SpringMVC_數(shù)據(jù)校驗(yàn)https://blog.csdn.net/qq_40794973/article/details/97967016