Form表单的验证验证,就是在提交表单的时候进行验证是否为空,是否满足特定条件才可以创建。常见的表单有前端验证和后端验证。
其中,前端验证有:HTML验证,JS验证,Jquery验证。 后端验证有:JSR303验证 、 Spring 验证框架。
目录
一.先讲解下JSR303的验证方式
二.逻辑方法验证适合Spring框架验证
我们先来讲述下,JSR303的验证。
接上上个项目:
我们在后台先增一个路径add,提交表单处理的路径。
add(UserForm userForm, BindingResult bindingResult, Model model)
package com.form.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import com.form.forms.UserForm;
@Controller
@RequestMapping("user")
public class UserController {
@RequestMapping("show")
public String show(Model model) {
UserForm userForm = new UserForm();
userForm.setId("zhm");
userForm.setName("001");
this.setModel(model);
model.addAttribute("userForm",userForm);
return "addUser";
}
@RequestMapping("add")
public String add(UserForm userForm, BindingResult bindingResult, Model model) {
String id = userForm.getId();
String name = userForm.getName();
model.addAttribute("id", id);
model.addAttribute("name", name);
return "success";
}
private void setModel(Model model) {
//set gender
Map<String, String> genderMap = new HashMap<String, String>();
genderMap.put("man", "Man");
genderMap.put("woman", "Woman");
//set Hobby
Map<String, String> hobbyMap = new HashMap<String, String>();
hobbyMap.put("dancing", "Dancing");
hobbyMap.put("singing", "Singing");
hobbyMap.put("printing", "Printing");
//Country
Map<String, String> countryMap = new HashMap<String, String>();
countryMap.put("china", "China");
countryMap.put("japan", "Japan");
countryMap.put("us", "US");
model.addAttribute("genderMap", genderMap);
model.addAttribute("hobbyMap", hobbyMap);
model.addAttribute("countryMap", countryMap);
}
}
让其跳转到success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
form application is successful.
${id }<br/>
${name }
</body>
</html>
运行tomcat,测试结果
但是这种是没有进行表单处理的,直接提交到了后台。所以我们在controller层进行表单验证
一.先讲解下JSR303的验证方式
我们需要在pom.xml中进行添加依赖:添加下列两个依赖包:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.form</groupId>
<artifactId>SpringMVC-FormProject</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>SpringMVC-FormProject Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.1.2.RELEASE</version>
</dependency>
</dependencies>
<build>
<finalName>SpringMVC-FormProject</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
同时也需要在springmvc的XML中进行配置使用上面的两个库:
需要使用创建下面三个类:
解读下下面三个类的关系:
1. 我们通过创建一个名叫“messageSource”的类对象,该对象的功能是去读取resources目录下的一个配置文件名叫“message.properties”,并且设置加载编码为UTF8格式,设置缓存时间为120.
2.我们通过一个名叫“validator”的类对象。该对象的功能是:调用“messageSource”的类对象,get它的message信息作为验证信息。
3.通过创建一个名叫“conversion”的类对象,该对象的功能是通过mvc:annotation-driven 的注解驱动将validator对象里的验证信息进行转换,中翻译为英文,或者英文翻译为中文。即多语言功能
<?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">
<!-- 配置扫描的包 == application.xml-->
<context:component-scan base-package="com.form"/>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 加载外部的语言文件 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:message"></property>
<property name="useCodeAsDefaultMessage" value="false"></property>
<property name="fileEncodings" value="UTF-8"></property>
<property name="cacheSeconds" value="120"></property>
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
<property name="validationMessageSource" ref="messageSource"></property>
</bean>
<bean id="conversion" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"/>
</beans>
我们创建一个名为“message.properties”的文件信息:
id.validator=id is required
name.validator=name length must be between 3 and 10
password.required=password is required
password.validator=password length must be between 6 and 10
Min.userForm.age=the min value of age is 1
Max.userForm.age=the max value of age is 110
phone.validator=phone format is error
birthday.validator=birthday should be a past year
repeatPassword.validate=repeat password should be the same with password
然后我们在userForm类中直接加入验证
package com.form.forms;
import java.util.Date;
import java.util.List;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Past;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;
public class UserForm {
@NotEmpty(message="{id.validator}")
private String id;
@Length(min=3, max=10, message="{name.validator}")
private String name;
@NotEmpty(message="{password.required}")
@Length(min=6, max=10, message="{password.validator}")
private String password;
@NotEmpty(message="{password.required}")
@Length(min=6, max=10, message="{password.validator}")
private String repeatPassword;
@Min(1)
@Max(110)
private int age;
@Pattern(regexp="[1][3|4|5|7|8][0-9]{9}$", message="{phone.validator}")
private String phoneNumber;
private String gender;
private List<String> hobby;
private String country;
private String remark;
//@Future
@Past(message="{birthday.validator}")
@DateTimeFormat(pattern="yyyy/MM/dd")
private Date birthday;
@Email
private String email;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRepeatPassword() {
return repeatPassword;
}
public void setRepeatPassword(String repeatPassword) {
this.repeatPassword = repeatPassword;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public List<String> getHobby() {
return hobby;
}
public void setHobby(List<String> hobby) {
this.hobby = hobby;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
同时也是需要在controller层进行验证userForm,只需要加一个@Valid
@Valid UserForm userForm 解读:该功能是递归验证方法,当提交userForm表单时,会验证userForm对象里的属性参数,也就是上面设置的UserForm.java里面的每个属性验证。
bindingResult.hasErrors() 解读:通常我们提交表单,如果验证失败,我们不用再次填写表单,此时就需要进行数据回源。即,返回原来的页面,并将userForm原本返回
package com.form.controller;
import java.util.HashMap;
import java.util.Map;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import com.form.forms.UserForm;
@Controller
@RequestMapping("user")
public class UserController {
@RequestMapping("show")
public String show(Model model) {
UserForm userForm = new UserForm();
userForm.setId("zhm");
userForm.setName("001");
this.setModel(model);
model.addAttribute("userForm",userForm);
return "addUser";
}
@RequestMapping("add")
public String add(@Valid UserForm userForm, BindingResult bindingResult, Model model) {
if(bindingResult.hasErrors()) {
model.addAttribute("userForm", userForm);
this.setModel(model);
return "addUser";
}
String id = userForm.getId();
String name = userForm.getName();
model.addAttribute("id", id);
model.addAttribute("name", name);
return "success";
}
private void setModel(Model model) {
//set gender
Map<String, String> genderMap = new HashMap<String, String>();
genderMap.put("man", "Man");
genderMap.put("woman", "Woman");
//set Hobby
Map<String, String> hobbyMap = new HashMap<String, String>();
hobbyMap.put("dancing", "Dancing");
hobbyMap.put("singing", "Singing");
hobbyMap.put("printing", "Printing");
//Country
Map<String, String> countryMap = new HashMap<String, String>();
countryMap.put("china", "China");
countryMap.put("japan", "Japan");
countryMap.put("us", "US");
model.addAttribute("genderMap", genderMap);
model.addAttribute("hobbyMap", hobbyMap);
model.addAttribute("countryMap", countryMap);
}
}
jsp页面也需要添加,数据回源的表单:modelAttribute="userForm"
<form:form method="POST" action="add" commandName="userForm" modelAttribute="userForm">
<form:errors 解读,用于页面显示验证信息。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Add User</title>
<style type="text/css">
</style>
</head>
<body>
<h2> Add User</h2>
<!-- 表单的名字: action = 响应路径 , commandName =表单名称 ,method == 提交方式 -->
<form:form method="POST" action="add" commandName="userForm" modelAttribute="userForm">
<table>
<tr>
<td><form:label path="id">ID</form:label></td>
<td><form:input path="id" maxlength="8"/> * <form:errors path="id"/></td>
</tr>
<tr>
<td><form:label path="name">Name</form:label></td>
<td><form:input path="name"/><form:errors path="name"/></td>
</tr>
<tr>
<td><form:label path="password">Password</form:label></td>
<td><form:password path="password"/><form:errors path="password"/></td>
</tr>
<tr>
<td><form:label path="repeatPassword">Repeat Password</form:label></td>
<td><form:password path="repeatPassword"/><form:errors path="repeatPassword"/></td>
</tr>
<tr>
<td><form:label path="age">Age</form:label></td>
<td><form:input path="age"/></td>
</tr>
<tr>
<td><form:label path="phoneNumber">Phone Number</form:label></td>
<td><form:input path="phoneNumber"/><form:errors path="phoneNumber"/></td>
</tr>
<tr>
<td><form:label path="gender">Gender</form:label></td>
<td>
<%-- <form:radiobutton path="gender" value="man"/>男
<form:radiobutton path="gender" value="woman"/>女 --%>
<form:radiobuttons path="gender" items="${genderMap }"/>
</td>
</tr>
<tr>
<td><form:label path="hobby">Hobby</form:label></td>
<td>
<%-- <form:checkbox path="hobby" value="dancing"/>Dancing
<form:checkbox path="hobby" value="singing"/>Singing
<form:checkbox path="hobby" value="Printing"/>Printing --%>
<form:checkboxes items="${hobbyMap }" path="hobby"/>
</td>
</tr>
<tr>
<td><form:label path="country">Country</form:label></td>
<td>
<%-- <form:select path="country">
<form:option value="china">China</form:option>
<form:option value="japan">Japan</form:option>
<form:option value="us">US</form:option>
</form:select> --%>
<form:select path="country" items="${countryMap }"/>
</td>
</tr>
<tr>
<td><form:label path="remark">Remark</form:label></td>
<td><form:textarea path="remark"/></td>
</tr>
<tr>
<td><form:label path="birthday">Birthday</form:label></td>
<td><form:input path="birthday"/></td>
</tr>
<tr>
<td><form:label path="email">Email</form:label></td>
<td><form:input path="email"/></td>
</tr>
<tr>
<td colspan="2"><form:button>Submit</form:button></td>
</tr>
</table>
</form:form>
</body>
<script type="text/javascript">
</script>
</html>
运行tomcat,测试结果。
会展示相关的验证提醒信息。
二.逻辑方法验证适合Spring框架验证
首先,我们需要实现springFramework框架下的Validator验证接口。
并实现里面的方法:
supports方法 解读 : 要支持验证哪一个Form表单?
validate 方法 解读: 验证前台传过来的表单数据:target = 前台表单数据 Errors =返回显示验证信息
package com.form.validator;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import com.form.forms.UserForm;
public class UserValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
// 在这里你要支持验证哪一个Form表单?
return UserForm.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
// 验证前台传过来的表单数据:target = 前台表单数据
UserForm userForm = (UserForm)target;
String id = userForm.getId();
String name = userForm.getName();
String password = userForm.getPassword();
String repeatPassword = userForm.getRepeatPassword();
//验证:如果错误则提示消息,会自动调用在springmvc中配置好的message验证消息。
if(!password.equals(repeatPassword)) {
errors.rejectValue("repeatPassword", "repeatPassword.validate");
}
//其余剩下的不写了,省略。。。。。。
}
}
然后在控制层,调用该验证方法即可:
InitBinder 解读:spring的表单验证方式,程序启动时会进行初始化,提交表单会自动配置并且验证
package com.form.controller;
import java.util.HashMap;
import java.util.Map;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.DataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import com.form.forms.UserForm;
import com.form.validator.UserValidator;
@Controller
@RequestMapping("user")
public class UserController {
@RequestMapping("show")
public String show(Model model) {
UserForm userForm = new UserForm();
userForm.setId("zhm");
userForm.setName("001");
this.setModel(model);
model.addAttribute("userForm", userForm);
return "addUser";
}
@RequestMapping("add")
public String add(@Valid UserForm userForm, BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
model.addAttribute("userForm", userForm);
this.setModel(model);
return "addUser";
}
String id = userForm.getId();
String name = userForm.getName();
model.addAttribute("id", id);
model.addAttribute("name", name);
return "success";
}
// spring的表单验证方式,程序启动时会进行初始化,提交表单会自动配置并且验证
@InitBinder
public void bindValidator(DataBinder dataBinder) {
dataBinder.setValidator(new UserValidator());
}
private void setModel(Model model) {
// set gender
Map<String, String> genderMap = new HashMap<String, String>();
genderMap.put("man", "Man");
genderMap.put("woman", "Woman");
// set Hobby
Map<String, String> hobbyMap = new HashMap<String, String>();
hobbyMap.put("dancing", "Dancing");
hobbyMap.put("singing", "Singing");
hobbyMap.put("printing", "Printing");
// Country
Map<String, String> countryMap = new HashMap<String, String>();
countryMap.put("china", "China");
countryMap.put("japan", "Japan");
countryMap.put("us", "US");
model.addAttribute("genderMap", genderMap);
model.addAttribute("hobbyMap", hobbyMap);
model.addAttribute("countryMap", countryMap);
}
}
运行tomcat,测试输入不一样的密码进行验证:
三用Springmvc配置国际化语言的验证消息
我需要再添加两个文件:
英文的验证信息文件名:message_en.properties
id.validator=id is required
name.validator=name length must be between 3 and 10
password.required=password is required
中文的验证信息文件名:message_zh.properties,在该文件里修改验证信息会自动转码
id.validator=\u8D26\u53F7\u4E0D\u80FD\u4E3A\u7A7A
name.validator=\u540D\u5B57\u7684\u957F\u5EA6\u5728 3 \u81F3 10 \u4E4B\u95F4
password.required=\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A
我们在springmvc-servlet.xml中配置了多语言转换功能。直接测试既可以
第二:标签也可以改为国际化语言:
在jsp中加入 tags头标签即可:
<%@taglib prefix="spring" uri="http://www.springframework.org/tags" %>
在jsp中使用方法:
<h2><spring:message code="text.user.title"/></h2>
<spring:message code="text.id"/>
<spring:message code="text.name"/>
全文如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Add User</title>
<style type="text/css">
</style>
</head>
<body>
<h2><spring:message code="text.user.title"/></h2>
<!-- 表单的名字: action = 响应路径 , commandName =表单名称 ,method == 提交方式 -->
<form:form method="POST" action="add" commandName="userForm" modelAttribute="userForm">
<table>
<tr>
<td><form:label path="id"><spring:message code="text.id"/></form:label></td>
<td><form:input path="id" maxlength="8"/> * <form:errors path="id"/></td>
</tr>
<tr>
<td><form:label path="name"><spring:message code="text.name"/></form:label></td>
<td><form:input path="name"/><form:errors path="name"/></td>
</tr>
<tr>
<td><form:label path="password">Password</form:label></td>
<td><form:password path="password"/><form:errors path="password"/></td>
</tr>
<tr>
<td><form:label path="repeatPassword">Repeat Password</form:label></td>
<td><form:password path="repeatPassword"/><form:errors path="repeatPassword"/></td>
</tr>
<tr>
<td><form:label path="age">Age</form:label></td>
<td><form:input path="age"/></td>
</tr>
<tr>
<td><form:label path="phoneNumber">Phone Number</form:label></td>
<td><form:input path="phoneNumber"/><form:errors path="phoneNumber"/></td>
</tr>
<tr>
<td><form:label path="gender">Gender</form:label></td>
<td>
<%-- <form:radiobutton path="gender" value="man"/>男
<form:radiobutton path="gender" value="woman"/>女 --%>
<form:radiobuttons path="gender" items="${genderMap }"/>
</td>
</tr>
<tr>
<td><form:label path="hobby">Hobby</form:label></td>
<td>
<%-- <form:checkbox path="hobby" value="dancing"/>Dancing
<form:checkbox path="hobby" value="singing"/>Singing
<form:checkbox path="hobby" value="Printing"/>Printing --%>
<form:checkboxes items="${hobbyMap }" path="hobby"/>
</td>
</tr>
<tr>
<td><form:label path="country">Country</form:label></td>
<td>
<%-- <form:select path="country">
<form:option value="china">China</form:option>
<form:option value="japan">Japan</form:option>
<form:option value="us">US</form:option>
</form:select> --%>
<form:select path="country" items="${countryMap }"/>
</td>
</tr>
<tr>
<td><form:label path="remark">Remark</form:label></td>
<td><form:textarea path="remark"/></td>
</tr>
<tr>
<td><form:label path="birthday">Birthday</form:label></td>
<td><form:input path="birthday"/></td>
</tr>
<tr>
<td><form:label path="email">Email</form:label></td>
<td><form:input path="email"/></td>
</tr>
<tr>
<td colspan="2"><form:button>Submit</form:button></td>
</tr>
</table>
</form:form>
</body>
<script type="text/javascript">
</script>
</html>
当然,需要在message_zh.properties的配置文件中加入
text.user.title=\u65B0\u589E\u7528\u6237
text.id=\u8D26\u53F7
text.name=\u59D3\u540D
测试结果:实现了国际化
四.Filter过滤器
我们在属于中文信息进行验证的时候,数据回流,出现乱码。这时候,我们就需要用到Filter过滤器
只需要在web.xml中进行配置:
标签解读:
<filter-class>解读:相当于new 了一个CharacterEncodingFilter类对象
<filter-name>解读:将新建的类对象命名为 “characterEncodingFilter”
<init-param>解读:将characterEncodingFilter对象设置属性功能 :encoding = UTF8
<url-pattern>解读:调用characterEncodingFilter对象 去过滤哪些页面?
/* 解读: 所有页面
<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">
<display-name>Archetype Created Web Application</display-name>
<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 重新定义springmvc文件存放的位置 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- 会直接读取resources文件目录下的配置 -->
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- tomcat启动的时候会重新加载 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<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>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
修改后测试:数据回流正常
filter还能过滤一些敏感词汇