目录
概述
对于用户输入的表单数据必须进行验证,以保证数据的合法性。
数据验证分为客户端验证和服务器端验证,客户端验证主要是过滤正常用户的误操作,通过JavaScript代码完成;服务器端验证是整个应用阻止非法数据的最后防线,通过在应用中编程实现。
客户端验证
客户端验证使用JavaScript进行验证:
- 编写验证函数
- 在提交表单的事件中调用验证函数
- 根据验证函数来判断是否进行表单提交
服务器端验证
在spring mvc中,先进行数据类型的转换,然后再进行数据验证。
在Spring MVC框架中有两种方法可以验证输入数据,一种是利用Spring自带的验证框架,另一种是利用JSR 303实现。
Spring验证器
概述
创建自定义Spring验证器实现的Validator接口:
package springmvcdemo.validator;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
public class TestValidator implements Validator {
@Override
public boolean supports(Class<?> aClass) {
// 当supports方法返回true时,验证器可以处理指定的Class
return false;
}
@Override
public void validate(Object object, Errors errors) {
// 验证目标对象object,并将验证错误信息存入Errors对象
}
}
往Errors对象存入错误消息的方法是reject或rejectValue,其方法有如下:
除此之外,还有ValidationUtils工具类,该类中有几个方法判断是否为空。
如:
if(student.getUsername()==null||student.getUsername().isEmpty()){
errors.reject("username","student.username.required");
}
使用ValidationUtils工具类后可以简化成如下代码:
ValidationUtils.rejectIfEmpty(errors,"username","student.username.required");
实例
创建springmvc项目并按照下图创建文件夹及文件:
说明:
验证要求:
- 姓名必须填写;
- 密码必须填写;
- 年龄必须大于0岁,小于150岁
JSP页面
register.jsp
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>注册</title>
<style>
.red {
color: red;
}
</style>
</head>
<body>
<form:form modelAttribute="student" action="/register" method="post">
姓名:<form:input path="username"/><form:errors path="username" cssClass="red"/><br/>
密码:<form:password path="password"/><form:errors path="password" cssClass="red"/> <br/>
年龄:<form:input path="age"/><form:errors path="age" cssClass="red"/> <br/>
<input type="reset">
<input type="submit" value="注册"><br>
<%--显示所有的错误--%>
<form:errors path="*" cssClass="red"/>
</form:form>
</body>
</html>
studentsList.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<table>
<tr>
<td>姓名</td>
<td>密码</td>
<td>年龄</td>
</tr>
<c:forEach items="${studentsList}" var="student">
<tr>
<td>${student.username}</td>
<td>${student.password}</td>
<td>${student.age}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
编写实体类
Student.java
package pojo;
public class Student {
private String username;
private String password;
private int age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
编写验证器类
验证器类即是实现Validator接口。使用@Component注解将RegisterValidator类声明为验证组件。
RegisterValidator.java
package validator;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import pojo.Student;
@Component
public class RegisterValidator implements Validator {
@Override
public boolean supports(Class<?> aClass) {
return Student.class.isAssignableFrom(aClass);
}
@Override
public void validate(Object object, Errors errors) {
Student student=(Student)object;
ValidationUtils.rejectIfEmpty(errors,"username","student.username.required");
ValidationUtils.rejectIfEmpty(errors,"password","student.password.required");
if(student.getAge()<=0||student.getAge()>150){
errors.rejectValue("age","age.invalid");
}
}
}
编写错误消息属性文件
errorMessages.properties
student.username.required=请输入用户名
student.password.required=请输入密码
age.invalid=年龄必须大于0岁,小于150岁
Unicode编码(IDEA将中文转换成Unicode编码需要进行配置)属性文件内容如下:
student.username.required=请输入用户名
student.password.required=请输入密码
age.invalid=年龄必须大于0岁,小于150岁
在属性文件创建完成后需要告诉Spring MVC从该属性文件中获取错误消息,则需要在配置文件中声明一个messageSource bean。因此,配置
<!-- 配置消息属性文件 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/WEB-INF/resource/errorMessages"/>
</bean>
springmvc-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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 使用扫描机制,扫描包 -->
<context:component-scan base-package="controller"/>
<context:component-scan base-package="service"/>
<context:component-scan base-package="validator"/>
<!-- 注册格式化转换器,因为用到日期转换-->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"/>
<mvc:annotation-driven conversion-service="conversionService"/>
<!-- 配置消息属性文件 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/WEB-INF/resource/errorMessages"/>
</bean>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
</beans>
编写Service层
RegisterService.java
package service;
import pojo.Student;
import java.util.ArrayList;
public interface RegisterService {
boolean register(Student student);
ArrayList<Student> getStudentsList();
}
RegisterServiceImpl.java
package service;
import org.springframework.stereotype.Service;
import pojo.Student;
import java.util.ArrayList;
@Service
public class RegisterServiceImpl implements RegisterService {
static ArrayList<Student> students = new ArrayList<>();
@Override
public boolean register(Student student) {
if (!"hello".equals(student.getUsername())) {
students.add(student);
return true;
}
return false;
}
@Override
public ArrayList<Student> getStudentsList() {
return students;
}
}
编写控制器类
在该类中使用@Resource注解注入自定义验证器。
package controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import pojo.Student;
import service.RegisterService;
import javax.annotation.Resource;
@Controller
public class RegisterController {
@Autowired
private RegisterService registerService;
@Resource
private Validator validator;
@RequestMapping("toRegister")
public String toRegister(Model model) {
model.addAttribute("student", new Student());
return "register";
}
@RequestMapping("register")
public String register(@ModelAttribute Student student, BindingResult result, Model model) {
this.validator.validate(student, result);
if (result.hasErrors()) {
return "register";
}
registerService.register(student);
model.addAttribute("studentsList", registerService.getStudentsList());
return "studentsList";
}
}
创建web.xml文件
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 避免中文乱码 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
运行效果
输入地址:http://localhost:8080/toRegister填写注册信息
如果什么也不填写,点击【注册】按钮,就会进行数据验证
如果只是填写一部分也会进行验证
填写全部数据,注册成功,验证通过。
如果对完整源码有兴趣。
可搜索微信公众号【Java实例程序】或者扫描下方二维码关注公众号获取更多。
注意:在公众号后台回复【CSDN201911161949】可获取本节源码。
JSR 303验证
概述
对于JSR 303验证,分别有两个实现:Hibernate Validator和Apache BVal。
这里使用的是Hibernate Validator,在使用之前要进行配置。
点击超链接:https://sourceforge.net/projects/hibernate/files/hibernate-validator/进行下载
点击蓝色版本后进入下载
将下载压缩包解压
因此所需要的包为:
- hibernate-validator-6.0.17.Final.jar
- classmate-1.3.4.jar
- javax.el-3.0.1-b09.jar
- jboss-logging-3.3.2.Final.jar
- validation-api-2.0.1.Final.jar
标注类型
JSR 303不需要编写验证器,使用标注类型即可。
空检查
- @Null:验证对象是否为null。
- @NotNull:验证对象是否不为null,无法检查长度为0的字符串。
- @NotBlank:检查约束字符串是不是null,以及被trim后的长度是否大于0,只针
对字符串,且会去掉前后空格。 - @NotEmpty:检查约束元素是否为null或者是empty。
例:
// student.username.required为属性文件的错误代码
@NotBlank(message="{student.username.required}")
private String username;
boolean检查
- @AssertTrue:验证Boolean属性是否为true。
- @AssertFalse:验证boolean属性是否为false。
例:
@AssertTrue
private boolean isLogin;
长度检查
- @Size(min=,max=):验证对象(Arrya、Collection、Map、String)长度是否在给定的范围之内。
- @Length(min=,max=):验证字符串长度是否在给定的范围之内。
例:
@Length(min=1,max=100)
private String memo;
日期检查
- @Past:验证Date和Calendar对象是否在当前时间之前。
- @Future:验证Date和Calendar对象是否在当前时间之后。
- @Pattem:验证String对象是否符合正则表达式的规则。
例:
@Past(message="{birthDate.invalid}")
private Date birthDate;
数值检查
- @Min:验证Number和String对象是否大于指定的值。
- @Max:验证Number和String对象是否小于指定的值。
- @DecimalMax:被标注的值必须不大于约束中指定的最大值,这个约束的参数是一
个通过BigDecimal定义的最大值的字符串表示,小数存在精度。 - @DecimalMin:被标注的值必须不小于约束中指定的最小值,这个约束的参数是一
个通过BigDecimal定义的最小值的字符串表示,小数存在精度。 - @Digits:验证Number和String的构成是否合法。
- @Digits(integer=,fraction=):验证字符串是否符合指定格式的数字,integer指定整数
精度,fraction指定小数精度。 - @Range(min=,max=):检查数字是否介于min和max之间。
- @Valid:对关联对象进行校验,如果关联对象是个集合或者数组,那么对其中的元
素进行校验,如果是一个map,则对其中的值部分进行校验。 - @CreditCardNumber:信用卡验证。
- @Email:验证是否为邮件地址,如果为null,不进行验证,通过验证。
例:
@Range(min=0,max=100,message="{score.invalid}")
private float score;
实例
本项目中所要用到的jar包如下:
创建springmvc项目并按照下图创建文件夹及文件(也可以修改上面的实例项目代码)。
本项目和上面实例项目的区别是:不需要创建验证器类RegisterValidator,除实体类Student.java、控制器RegisterController.java及springmvc-servlet.xml配置文件不同之外,其他文件都是相同的。
实体类Student.java
package pojo;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.Range;
public class Student {
@NotBlank(message = "{student.username.required}")
private String username;
@NotBlank(message = "{student.password.required}")
private String password;
@Range(min = 1, max = 150, message = "{age.invalid}")
private int age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
控制器类RegisterController.java
使用@Valid对实体对象进行验证。
package controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import pojo.Student;
import service.RegisterService;
import javax.annotation.Resource;
import javax.validation.Valid;
@Controller
public class RegisterController {
@Autowired
private RegisterService registerService;
@Resource
private Validator validator;
@RequestMapping("toRegister")
public String toRegister(Model model) {
model.addAttribute("student", new Student());
return "register";
}
@RequestMapping("register")
public String register(@Valid @ModelAttribute Student student, BindingResult result, Model model) {
this.validator.validate(student, result);
if (result.hasErrors()) {
return "register";
}
registerService.register(student);
model.addAttribute("studentsList", registerService.getStudentsList());
return "studentsList";
}
}
配置文件springmvc-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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 使用扫描机制,扫描包 -->
<context:component-scan base-package="controller"/>
<context:component-scan base-package="service"/>
<!-- 注册格式化转换器,因为用到日期转换-->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"/>
<mvc:annotation-driven conversion-service="conversionService"/>
<!--配置属性文件-->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<!--资源文件名-->
<property name="basenames">
<list>
<value>/WEB-INF/resource/errorMessages</value>
</list>
</property>
<!--资源文件编码格式-->
<property name="fileEncodings" value="utf-8"/>
<!--对资源文件内容缓存的时间,单位为秒-->
<property name="cacheSeconds" value="120"/>
</bean>
<!--注册校验器-->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<!--hibernate校验器-->
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
<!--指定校验使用的资源文件,在文件中配置校验错误信息,如果不指定则默认使用-->
<property name="validationMessageSource" ref="messageSource"/>
</bean>
<!--开启Spring的Valid功能-->
<mvc:annotation-driven conversion-service="conversionService" validator="validator"/>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
</beans>
其他文件的代码可以查看上面的实例的内容,未修改的文件代码都是一样的,或者通过下面的二维码获取完整代码。
运行项目进行测试
通过地址:http://localhost:8080/toRegister访问注册页面
如果什么也不输入就会报验证错误提示
点击【注册】按钮注册成功
如果对完整源码有兴趣。
可搜索微信公众号【Java实例程序】或者扫描下方二维码关注公众号获取更多。
注意:在公众号后台回复【CSDN201911162115】可获取本节源码。