这就是我们本篇要说的内容 —> 数据验证。
这里我们采用Hibernate-validator来进行验证,Hibernate-validator实现了JSR-303验证框架支持注解风格的验证。首先我们要到http://hibernate.org/validator/下载需要的jar包,这里以4.3.1.Final作为演示,解压后把hibernate-validator-4.3.1.Final.jar、jboss-logging-3.1.0.jar、validation-api-1.0.0.GA.jar这三个包添加到项目中。
Maven:
<!-- https://mvnrepository.com/artifact/org.jboss.logging/jboss-logging --> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.3.0.Final</version> </dependency> <!-- https://mvnrepository.com/artifact/javax.validation/validation-api --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency>
配置之前项目中的dispatcherServlet-servlet.xml文件,添加如下:
<!-- 默认的注解映射的支持 --> <mvc:annotation-driven validator="validator"/> <!-- 配置校验器 --> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <!-- 校验器,使用hibernate校验器 --> <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/> <!--指定校验使用的资源文件,不设置则默认为classpath下的 ValidationMessages.properties --> <property name="validationMessageSource" ref="validatemessageSource"/> </bean> <!-- 校验错误信息配置文件 --> <bean id="validatemessageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <!-- 资源文件名 --> <property name="basename" value="classpath:validatemessages"/> <!-- 资源文件编码格式 --> <property name="fileEncodings" value="utf-8"/> <!-- 对资源文件内容缓存时间,单位秒 --> <property name="cacheSeconds" value="120"/> </bean> </beans>
其中<property name="basename" value="classpath:validatemessages"/>中的classpath:validatemessages为注解验证消息所在的文件,需要我们在resources文件夹下添加。
在注解验证消息所在的文件即validatemessages.properties文件中添加以下内容:
name.not.empty=\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A\u3002 age.not.inrange=\u5E74\u9F84\u8D85\u51FA\u8303\u56F4\u3002 email.not.correct=\u90AE\u7BB1\u5730\u5740\u4E0D\u6B63\u786E\u3002 email.not.empty=\u90ae\u7bb1\u4e0d\u80fd\u4e3a\u7a7a\u3002
其中name.not.empty等分别对应了ValidateModel.java文件中message=”xxx”中的xxx名称,后面的内容是在输入中文是自动转换的ASCII编码
ValidateController.java内容如下:
package com.ray.controllers; import com.ray.models.ValidateModel; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import javax.validation.Valid; /** * @author Ray * @date 2018/4/20 0020 */ @Controller @RequestMapping(value = "/validate") public class ValidateController { @RequestMapping(value = "/test", method = RequestMethod.GET) public String test(Model model){ if(!model.containsAttribute("contentModel")){ model.addAttribute("contentModel", new ValidateModel()); } return "validatetest"; } @RequestMapping(value = "/test", method = RequestMethod.POST) public String test(Model model, @Valid @ModelAttribute("contentModel") ValidateModel validateModel, BindingResult result){ //如果有验证错误, 返回form页面 if(result.hasErrors()){ return test(model); } return "validatesuccess"; } }
其中@Valid @ModelAttribute("contentModel") ValidateModel validateModel的@Valid 意思是在把数据绑定到@ModelAttribute("contentModel") 后就进行验证。
ValidateModel.java内容如下:
package com.ray.models; import org.hibernate.validator.constraints.Email; import org.hibernate.validator.constraints.NotEmpty; import org.hibernate.validator.constraints.Range; /** * @author Ray * @date 2018/4/20 0020 */ public class ValidateModel { @NotEmpty(message = "{name.not.empty}") private String name; @Range(min = 0, max = 100, message = "{age.not.inrange}") private String age; @NotEmpty(message = "{email.not.empty}") @Email(message = "{email.not.correct}") private String eamil; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public String getEamil() { return eamil; } public void setEamil(String eamil) { this.eamil = eamil; } }
在views文件夹中添加validatetest.jsp和validatesuccess.jsp两个视图,内容分别如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>Insert title here</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> <form:form modelAttribute="contentModel" method="post"> <form:errors path="*"></form:errors><br/><br/> name:<form:input path="name"/><br/> <form:errors path="name"></form:errors><br/> age:<form:input path="age"/><br/> <form:errors path="age"></form:errors><br/> email:<form:input path="eamil"/><br/> <form:errors path="eamil"></form:errors><br/> <input type="submit" value="Submit"> </form:form> </body> </html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>Insert title here</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> 验证成功! </body> </html>
其中特别要指出的是validatetest.jsp视图中<form:form modelAttribute="contentModel" method="post">的modelAttribute="xxx"后面的名称xxx必须与对应的@Valid @ModelAttribute("xxx") 中的xxx名称一致,否则模型数据和错误信息都绑定不到。
<form:errors path="name"></form:errors>即会显示模型对应属性的错误信息,当path="*"时则显示模型全部属性的错误信息。
运行测试:
可以看到验证成功。
hibernate校验框架提供了很多注解校验,我先简单罗列一下:
注解 | 运行时检查 |
---|---|
@AssertFalse | 被注解的元素必须为false |
@AssertTrue | 被注解的元素必须为true |
@DecimalMax(value) | 被注解的元素必须为一个数字,其值必须小于等于指定的最小值 |
@DecimalMin(Value) | 被注解的元素必须为一个数字,其值必须大于等于指定的最小值 |
@Digits(integer=, fraction=) | 被注解的元素必须为一个数字,其值必须在可接受的范围内 |
@Future | 被注解的元素必须是日期,检查给定的日期是否比现在晚 |
@Max(value) | 被注解的元素必须为一个数字,其值必须小于等于指定的最小值 |
@Min(value) | 被注解的元素必须为一个数字,其值必须大于等于指定的最小值 |
@NotNull | 被注解的元素必须不为null |
@Null | 被注解的元素必须为null |
@Past(java.util.Date/Calendar) | 被注解的元素必须过去的日期,检查标注对象中的值表示的日期比当前早 |
@Pattern(regex=, flag=) | 被注解的元素必须符合正则表达式,检查该字符串是否能够在match指定的情况下被regex定义的正则表达式匹配 |
@Size(min=, max=) | 被注解的元素必须在制定的范围(数据类型:String, Collection, Map and arrays) |
@Valid | 递归的对关联对象进行校验, 如果关联对象是个集合或者数组, 那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验 |
@CreditCardNumber | 对信用卡号进行一个大致的验证 |
被注释的元素必须是电子邮箱地址 | |
@Length(min=, max=) | 被注解的对象必须是字符串的大小必须在制定的范围内 |
@NotBlank | 被注解的对象必须为字符串,不能为空,检查时会将空格忽略 |
@NotEmpty | 被注释的对象必须为空(数据:String,Collection,Map,arrays) |
@Range(min=, max=) | 被注释的元素必须在合适的范围内 (数据:BigDecimal, BigInteger, String, byte, short, int, long and 原始类型的包装类 ) |
@URL(protocol=, host=, port=, regexp=, flags=) | 被注解的对象必须是字符串,检查是否是一个有效的URL,如果提供了protocol,host等,则该URL还需满足提供的条件 |
上面我简单罗列了一些校验的注解,不同的注解的具体使用方法可以参考官方文档或者网上资料,这里我选择两个注解来说明如何使用这个hibernate验证框架。首先在自己的pojo中需要验证的属性上添加相应的验证注解:
我们看到注解中可以指定message,那么这个message中的内容是错误消息配置文件中对应的key,取出来的就是对应的错误消息,所以针对这两个错误消息,我们写一下配置文件:
更多信息请参考官方文档:http://docs.jboss.org/hibernate/validator/4.3/reference/en-US/html/validator-usingvalidator.html