SpringMVC 使用JSR-303進行校驗 @Valid
使用注解
一、准備校驗時使用的JAR
validation-api-1.0.0.GA.jar:JDK的接口;
hibernate-validator-4.2.0.Final.jar是對上述接口的實現;
log4j、slf4j、slf4j-log4j
<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.1.0.Final</version> </dependency> <dependency> <groupId>javax.el</groupId> <artifactId>el-api</artifactId> <version>2.2</version> </dependency>
http://hibernate.org/validator/documentation/getting-started/
... 128 common frames omitted
Caused by: javax.validation.ValidationException: HV000183: Unable to load 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath
at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:172) ~[hibernate-validator-5.1.0.Final.jar:5.1.0.Final]
at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:118) ~[hibernate-validator-5.1.0.Final.jar:5.1.0.Final]
at org.hibernate.validator.internal.engine.ConfigurationImpl.<init>(ConfigurationImpl.java:110) ~[hibernate-validator-5.1.0.Final.jar:5.1.0.Final]
at org.hibernate.validator.internal.engine.ConfigurationImpl.<init>(ConfigurationImpl.java:86) ~[hibernate-validator-5.1.0.Final.jar:5.1.0.Final]
at org.hibernate.validator.HibernateValidator.createGenericConfiguration(HibernateValidator.java:41) ~[hibernate-validator-5.1.0.Final.jar:5.1.0.Final]
at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:276) ~[validation-api-1.1.0.Final.jar:na]
... 137 common frames omitted
http://www.tuicool.com/articles/eQf2Ejv
http://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/http-entity/
二、編寫需要校驗的bean
@NotNull(message="名字不能為空") private String userName; @Max(value=120,message="年齡最大不能查過120") private int age; @Email(message="郵箱格式錯誤") private String email;
三、校驗方法
@RequestMapping("/login") public String testValid(@Valid User user, BindingResult result){ if (result.hasErrors()){ List<ObjectError> errorList = result.getAllErrors(); for(ObjectError error : errorList){ System.out.println(error.getDefaultMessage()); } } return "test"; }
備注:這里一個@Valid的參數后必須緊挨着一個BindingResult 參數,否則spring會在校驗不通過時直接拋出異常
前台可以使用spring的標簽庫也可以自己自定義處理
spring標簽庫的用法:
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <html> <head> <title>Reservation Form</title> <style> .error { color: #ff0000; font-weight: bold; } </style> </head> <body> <form:form method="post" modelAttribute="vm"> <form:errors path="*" cssClass="error" /> <table> <tr> <td>Name</td> <td><form:input path="userName" /> </td> <td><form:errors path="userName" cssClass="error" /> </td> </tr> <tr> <td>email</td> <td><form:input path="email" /> </td> <td><form:errors path="email" cssClass="error" /> </td> </tr> <tr> <td colspan="3"><input type="submit" /> </td> </tr> </table> </form:form> </body> </html>
四、開啟spring的Valid功能
<mvc:annotation-driven />
五、JSR303定義的校驗類型
空檢查
@Null 驗證對象是否為null
@NotNull 驗證對象是否不為null, 無法查檢長度為0的字符串
@NotBlank 檢查約束字符串是不是Null還有被Trim的長度是否大於0,只對字符串,且會去掉前后空格.
@NotEmpty 檢查約束元素是否為NULL或者是EMPTY.
Booelan檢查
@AssertTrue 驗證 Boolean 對象是否為 true
@AssertFalse 驗證 Boolean 對象是否為 false
長度檢查
@Size(min=, max=) 驗證對象(Array,Collection,Map,String)長度是否在給定的范圍之內
@Length(min=, max=) Validates that the annotated string is between min and max included.
日期檢查
@Past 驗證 Date 和 Calendar 對象是否在當前時間之前
@Future 驗證 Date 和 Calendar 對象是否在當前時間之后
@Pattern 驗證 String 對象是否符合正則表達式的規則
數值檢查,建議使用在Stirng,Integer類型,不建議使用在int類型上,因為表單值為“”時無法轉換為int,但可以轉換為Stirng為"",Integer為null
@Min 驗證 Number 和 String 對象是否大等於指定的值
@Max 驗證 Number 和 String 對象是否小等於指定的值
@DecimalMax 被標注的值必須不大於約束中指定的最大值. 這個約束的參數是一個通過BigDecimal定義的最大值的字符串表示.小數存在精度
@DecimalMin 被標注的值必須不小於約束中指定的最小值. 這個約束的參數是一個通過BigDecimal定義的最小值的字符串表示.小數存在精度
@Digits 驗證 Number 和 String 的構成是否合法
@Digits(integer=,fraction=) 驗證字符串是否是符合指定格式的數字,interger指定整數精度,fraction指定小數精度。
@Range(min=, max=) Checks whether the annotated value lies between (inclusive) the specified minimum and maximum.
@Range(min=10000,max=50000,message="range.bean.wage")
private BigDecimal wage;
@Valid 遞歸的對關聯對象進行校驗, 如果關聯對象是個集合或者數組,那么對其中的元素進行遞歸校驗,如果是一個map,則對其中的值部分進行校驗.(是否進行遞歸驗證)
@CreditCardNumber信用卡驗證
@Email 驗證是否是郵件地址,如果為null,不進行驗證,算通過驗證。
@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=,host=, port=,regexp=, flags=)
6、自定義校驗類型
可以參考:http://exceptioneye.iteye.com/blog/1305040
使用接口
可以參考:http://elf8848.iteye.com/blog/1299587
http://www.cnblogs.com/yangzhilong/p/3724967.html
@RequestMapping("/add2") public String addStudentValid(@Valid @ModelAttribute("s") Student s,BindingResult result){ if(result.hasErrors()){ List<FieldError> fieldErrors = result.getFieldErrors(); for (FieldError fieldError : fieldErrors) { log.info("errors --"+fieldError.getField()+fieldError.getDefaultMessage()); } } log.info("s.name="+s.getName()); log.info("s.age="+s.getAge()); return "success"; }
import javax.validation.constraints.Min; import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.NotEmpty; public class Student { @NotEmpty @Length(min=4,message="{stu.name}") private String name; @Min(value=18,message="{stu.age}") private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "toString - name="+name+";age="+age; } }
需要開啟注解 <mvc:annotation-driven/>才能啟用驗證。否則@valid不管用。
如果要使用錯誤提示的國際化消息,如stu.name為properties文件中的鍵值對
@Length(min=4,message="{stu.name}")
則需要在dispatcher-servlet.xml中配置
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="classpath:validmessages"/> <property name="fileEncodings" value="utf-8"/> <property name="cacheSeconds" value="120"/> </bean> <!-- 以下 validator ConversionService 在使用 mvc:annotation-driven 會 自動注冊--> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <property name="providerClass" value="org.hibernate.validator.HibernateValidator" /> <!-- 如果不加默認到 使用classpath下的 ValidationMessages.properties --> <property name="validationMessageSource" ref="messageSource" /> </bean> <mvc:annotation-driven validator="validator"/>
在src/main/resources下放入validmessages.properties即可。
上面的配置設置了自定義validator,使用messageSource為錯誤消息提示資源文件。
validmessages.properties內容為
stu.name=\u540D\u79F0\u7684\u957F\u5EA6\u4E0D\u80FD\u5C0F\u4E8E{min}\u554A!
stu.age=\u5E74\u9F84\u5FC5\u987B\u5927\u4E8E{value}\u5C81\u554A!
可以通過{value} {min} {max}等引用注解里的值。
當名稱長度小於4 age小於18 輸出:
名稱的長度不能小於4啊!
age年齡必須大於18歲啊!
本次測試的dispatcher-servlet.xml為
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd "> <context:component-scan base-package="com.upper"/> <!-- freemarker的配置 --> <bean id="freemarkerConfigurer" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <property name="templateLoaderPath" value="/WEB-INF/views/" /> <property name="defaultEncoding" value="GBK" /> <property name="freemarkerSettings"> <props> <prop key="template_update_delay">0</prop> <prop key="locale">zh_CN</prop> <prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop> <prop key="date_format">yyyy-MM-dd</prop> <prop key="number_format">#.##</prop> <!-- <prop key="auto_import">c_index.tpl as p</prop> --> </props> </property> </bean> <!-- FreeMarker視圖解析 如返回userinfo。。在這里配置后綴名ftl和視圖解析器。。 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" /> <property name="suffix" value=".ftl" /> <property name="contentType" value="text/html;charset=GBK" /> <property name="exposeRequestAttributes" value="true" /> <property name="exposeSessionAttributes" value="true" /> <property name="exposeSpringMacroHelpers" value="true" /> <property name="requestContextAttribute" value="rc" /> <property name="allowSessionOverride" value="true"/> </bean> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="classpath:validmessages"/> <property name="fileEncodings" value="utf-8"/> <property name="cacheSeconds" value="120"/> </bean> <!-- 以下 validator ConversionService 在使用 mvc:annotation-driven 會 自動注冊--> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <!-- 如果不加默認到 使用classpath下的 ValidationMessages.properties --> <property name="validationMessageSource" ref="messageSource" /> </bean> <mvc:annotation-driven validator="validator"/> </beans>
http://www.cnblogs.com/beenupper/p/3395872.html
對於后端的參數校驗,我們一直在強調的驗證規則,提示信息的重用。這不,springmvc通過集成Valid最大程序減少了我們的工作量。其實后端的參數過濾,是分幾種請求來源的。每種的處理都不太一樣,但是我們如果能重用驗證規則,提示信息,那就很強大了。
1 常用的表單提交,需要頁面返回錯誤信息
2 AJAX提交,需要JSON格式返回,或者XML
3 接口調用,同樣需要對應的數據格式返回
對於這3類請求,我今天講的是第3種,是可以重用第1種的資源和驗證規則。
考慮通過AOP加注解,攔截方法中的BEAN,通過獲取期驗證返回信息,提前拋出驗證異常。
里面的processValidationError方法會處理具體異常的返回值並以JSON輸出,大功告成.
整體代碼鏈接。
demo代碼:https://github.com/igool/validatedemo
子模塊:https://github.com/igool/lombakcode
當這樣處理之后,我們的resetful的接口只用處理真正的業務,完全不用做常用的參數檢查。
http://www.blogjava.net/zuxiong/archive/2015/11/27/428389.html