B/S系统中对http请求数据的校验多数在客户端进行,这也是出于简单及用户体验性上考虑。但是在一些安全性要求高的系统中服务端校验是不可缺少的,SpringMVC实现控制层添加校验。SpringMVC使用Hibernate Validator的校验框架(和Hibernate ORM没有任何关系)
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Titletitle>
head>
<body>
<div style="text-align: center">
<h1>数据验证h1>
<p><a href="views/front.jsp">前端验证a>p>
<p><a href="views/add.jsp">员工新增a>p>
<p><a href="views/edit.jsp">员工编辑a>p>
div>
body>
html>
front.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Titletitle>
<script type="text/javascript" src="js/jquery-3.3.1.min.js">script>
<script type="text/javascript">
//客户端验证
//优点:快捷,减轻服务器的压力
//缺点:可控制性低
function doVaildate(){
var ename = $('#ename').val().trim();
var job = $('#job').val().trim();
var sal = $('#sal').val().trim();
if(ename==null || ename==''){
alert('员工姓名不能为空');
return false;
}
var reg1 = /^\S{2,8}$/;
if(!reg1.test(ename)){
alert('员工姓名必须为2~8位非空白字符');
return false;
}
if(job==null || job==''){
alert('员工岗位不能为空');
return false;
}
if(sal==null || sal==''){
alert('员工薪资不能为空');
return false;
}
var reg2 = /^\d+(.\d{1,2})?$/;
if(!reg2.test(sal)){
alert('员工薪资必须为整数或两位小数');
return false;
}
return true;
}
script>
head>
<body>
<div style="text-align: center;">
<h3>前端验证h3>
<form action="views/success.jsp" method="post" onsubmit="return doVaildate()" >
<p>员工姓名:<input type="text" id="ename" name="ename">p>
<p>员工岗位:<input type="text" id="job" name="job">p>
<p>员工薪资:<input type="text" id="sal" name="sal">p>
<p><button>提交button>p>
form>
div>
body>
html>
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Titletitle>
head>
<body>
<div style="text-align: center">
<h1>操作成功h1>
div>
body>
html>
导入hibernate-validator的jar包
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>4.3.18.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>4.3.18.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>4.3.18.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-expressionartifactId>
<version>4.3.18.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>4.3.18.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>4.3.18.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>4.3.18.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>4.3.18.RELEASEversion>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.1version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-coreartifactId>
<version>2.9.5version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.9.5version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-annotationsartifactId>
<version>2.9.5version>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-validatorartifactId>
<version>5.4.1.Finalversion>
dependency>
dependencies>
web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>HiddenHttpMethodFilterfilter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>HttpPutFormContentFilterfilter-name>
<filter-class>org.springframework.web.filter.HttpPutFormContentFilterfilter-class>
filter>
<filter-mapping>
<filter-name>HttpPutFormContentFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<servlet>
<servlet-name>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<welcome-file-list>
<welcome-file>/views/index.jspwelcome-file>
welcome-file-list>
web-app>
springmvc.xml
<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:aop="http://www.springframework.org/schema/aop"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.newcapec"/>
<mvc:annotation-driven validator="validator"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/views/"/>
<property name="suffix" value=".jsp"/>
bean>
<mvc:default-servlet-handler/>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator" />
bean>
beans>
校验注解 | 校验的数据类型 | 说明 |
---|---|---|
@AssertFalse | Boolean,boolean | 被注释的元素值必须为false |
@AssertTrue | Boolean,boolean | 被注释的元素值必须为true |
@DecimalMax(value) | BigDecimal,BigInteger,byte,short,int,long以及基本数据类型相应的包装类,任何Number的子类型,String(由String表示的数值) | 被注释的元素值必须小于等于@DecimalMax指定的value值 |
@DecimalMin(value) | 和@DecimalMax要求一样 | 被注释的元素值必须大于等于@DecimalMin指定的value值 |
@Digits (integer=整数位, fraction=小数位) | 和@DecimalMax要求一样 | 被注释的元素值的整数位数和小数位数上限 |
@Future | java.util.Date,java.util.Calendar,Joda Time类库的日期类型 | 被注释的元素值必须比当前时间晚 |
@Max(value) | 和@DecimalMax要求一样 | 被注释的元素值必须小于等于@Max指定的value值 |
@Min(value) | 和@DecimalMax要求一样 | 被注释的元素值必须大于等于@Min指定的value值 |
@NotNull | 任意类型 | 被注释的元素值必须不为null |
@Null | 任意类型 | 被注释的元素值必须为null |
@Past | 和@Future要求一样 | 被注释的元素值必须比当前时间早 |
@Pattern(regex=正则表达式,flag=标志模式) | 字符串 | 被注释的元素值必须符合指定的正则表达式 |
@Size(max=, min=) | 字符串,Collection集合,Map集合,数组 | 被注释的元素值的大小必须在指定的范围内 |
校验注解 | 校验的数据类型 | 说明 |
---|---|---|
字符串 | 被注释的元素值必须是电子邮箱地址 | |
@Length(min=,max=) | 字符串 | 被注释的元素值的大小必须在指定的范围内 |
@NotBlank | 字符串 | 被注释的元素值必须非空,非空值或非全空白字符。功能强大于@NotEmpty |
@NotEmpty | 字符串,Collection集合,Map集合,数组 | 被注释的元素值必须非空或非空值。功能强于@NotNull |
@Range(min=,max=) | BigDecimal,BigInteger,byte,short,int,long以及基本数据类型相应的包装类 | 被注释的元素值必须在合适的范围内 |
Hibernate Validator是通过注解的方式对实体类中的成员变量进行校验,即在成员变量上配置校验规则
/**
* hibernate validator数据验证框架
* 作用:通过注解的方式进行数据验证,注解需要添加在实体的成员变量上
*
* 注解中通过的属性:
* message: 当前验证失败时给用户提示信息
*/
public class Emp {
private Integer empno;
@NotBlank(message = "员工姓名不能为空")
@Length(message = "员工姓名必须为2~8位字符",min = 2, max = 8)
private String ename;
@NotBlank(message = "员工岗位不能为空")
private String job;
@NotNull(message = "员工薪资不能为空")
@DecimalMin(message = "员工薪资不能低于1000",value = "1000")
private Double sal;
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Double getSal() {
return sal;
}
public void setSal(Double sal) {
this.sal = sal;
}
@Override
public String toString() {
return "Emp{" +
"empno=" + empno +
", ename='" + ename + '\'' +
", job='" + job + '\'' +
", sal=" + sal +
'}';
}
}
@Controller
@RequestMapping("/emp")
public class EmpController {
/**
* 开启数据验证
* @Validated
* 位置:形参
* 作用:开启了请求参数的验证
*
* 注意:@Validated注解不能单独使用,需要在每个开启数据验证的形参后,跟随一个BindingResult类型的形参
* BindingResult:判断数据是否验证通过,并接收验证失败信息
*/
@RequestMapping("/add")
public String add(@Validated Emp emp, BindingResult bindingResult, Model model){
System.out.println(emp);
//判断数据验证是否通过
if(bindingResult.hasErrors()) {
//数据验证没有全部通过
List<ObjectError> list = bindingResult.getAllErrors();
for (ObjectError objectError : list) {
//getDefaultMessage()获取验证失败信息
System.out.println(objectError.getDefaultMessage());
}
model.addAttribute("errors", list);
return "add";
}
return "success";
}
}
注意:@Validated表示在对Controller方法形参绑定时进行校验,校验信息写入BindingResult中,在要校验的实体类后边添加BingdingResult,一个BindingResult对应一个实体类,且BingdingResult放在实体类的后边
在Controller中已经把错误列表对象存入作用域中,在页面直接取出,遍历并显示即可
add.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Titletitle>
head>
<body>
<div style="text-align: center;">
<h3>员工新增h3>
<div style="color: red;">
<ol>
<c:forEach items="${errors}" var="e">
<li>${e.defaultMessage}li>
c:forEach>
ol>
div>
<form action="emp/add" method="post">
<p>员工姓名:<input type="text" name="ename">p>
<p>员工岗位:<input type="text" name="job">p>
<p>员工薪资:<input type="text" name="sal">p>
<p><button>提交button>p>
form>
div>
body>
html>
如果两处校验使用同一个实体类则可以设定校验分组,通过分组校验可以对每处的校验个性化
定义分组标识,就是定义一个空接口
public interface EmpAddValidator {
}
public interface EmpEditValidator {
}
/**
* hibernate validator数据验证框架
* 是通过注解的方式对数据进行验证
* 注解需要添加在实体类的属性上,因为在springmvc中是通过实体类类型的形参接收请求参数
*
* 注解中通用的属性:
* message : 当前验证失败是给用户的提交信息
* groups : 分组校验
*/
public class Emp {
@NotNull(message = "员工编号不能为空",groups= EmpEditValidator.class)
private Integer empno;
// @NotBlank(message = "员工姓名不能为空")
@NotBlank(message = "员工姓名不能为空",groups= {
EmpEditValidator.class, EmpAddValidator.class})
// @Length(message = "员工姓名必须为2~8位字符",min = 2, max = 8)
@Length(message = "员工姓名必须为2~8个字符", min = 2, max = 8,groups= {
EmpEditValidator.class, EmpAddValidator.class})
private String ename;
// @NotBlank(message = "员工岗位不能为空")
@NotBlank(message = "员工岗位不能为空",groups= {
EmpEditValidator.class, EmpAddValidator.class})
private String job;
// @NotNull(message = "员工薪资不能为空")
@NotNull(message = "员工薪资不能为空",groups= {
EmpEditValidator.class, EmpAddValidator.class})
// @DecimalMin(message = "员工薪资不能低于1000",value = "1000")
@DecimalMin(message = "员工薪资不能低于1000", value = "1000", groups = {
EmpEditValidator.class, EmpAddValidator.class})
private Double sal;
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Double getSal() {
return sal;
}
public void setSal(Double sal) {
this.sal = sal;
}
@Override
public String toString() {
return "Emp{" +
"empno=" + empno +
", ename='" + ename + '\'' +
", job='" + job + '\'' +
", sal=" + sal +
'}';
}
}
@Controller
@RequestMapping("/emp")
public class EmpController {
/**
* 开启数据验证
* @Validated
* 位置:形参
* 作用:开启了请求参数的验证
* 属性:指定分组
*
* 注意:@Validated注解不能单独使用,需要在每个开启数据验证的形参后,跟随一个BindingResult类型的形参
* BindingResult:判断数据是否验证通过,并接收验证失败信息
*/
@RequestMapping("/add")
public String add(@Validated(EmpAddValidator.class) Emp emp, BindingResult bindingResult, Model model){
System.out.println(emp);
//判断数据验证是否通过
if(bindingResult.hasErrors()) {
//数据验证没有全部通过
List<ObjectError> list = bindingResult.getAllErrors();
for (ObjectError objectError : list) {
//getDefaultMessage()获取验证失败信息
System.out.println(objectError.getDefaultMessage());
}
model.addAttribute("errors", list);
return "add";
}
return "success";
}
@RequestMapping("/edit")
public String edit(@Validated(EmpEditValidator.class) Emp emp, BindingResult bindingResult, Model model){
System.out.println(emp);
//判断数据验证是否通过
if(bindingResult.hasErrors()) {
//数据验证没有全部通过
List<ObjectError> list = bindingResult.getAllErrors();
model.addAttribute("errors", list);
return "edit";
}
return "success";
}
}
edit.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Titletitle>
head>
<body>
<div style="text-align: center;">
<h3>员工编辑h3>
<div style="color: red;">
<ol>
<c:forEach items="${errors}" var="e">
<li>${e.defaultMessage}li>
c:forEach>
ol>
div>
<form action="emp/edit" method="post">
<p>员工编号:<input type="text" name="empno">p>
<p>员工姓名:<input type="text" name="ename">p>
<p>员工岗位:<input type="text" name="job">p>
<p>员工薪资:<input type="text" name="sal">p>
<p><button>提交button>p>
form>
div>
body>
html>
当属性值校验失败后,其提示信息可配置在一个资源文件中,文件名称默认为classpath:ValidationMessages.properties
emp.empno.NotNull=员工编号不能为空--2
emp.ename.NotBlank=员工姓名不能为空--2
emp.ename.Length=员工姓名必须为2~8位字符--2
emp.job.NotBlank=员工岗位不能为空--2
emp.salary.NotNull=员工薪资不能为空--2
emp.salary.DecimalMin=员工薪资不能低于1000--2
在实体中通过{}引用资源文件中的数据
/**
* hibernate validator数据验证框架
* 是通过注解的方式对数据进行验证
* 注解需要添加在实体类的属性上,因为在springmvc中是通过实体类类型的形参接收请求参数
*
* 注解中通用的属性:
* message : 当前验证失败是给用户的提交信息
* groups : 分组校验
*/
public class Emp {
// @NotNull(message = "员工编号不能为空",groups= EmpEditValidator.class)
@NotNull(message = "{emp.empno.NotNull}",groups= EmpEditValidator.class)
private Integer empno;
// @NotBlank(message = "员工姓名不能为空")
// @NotBlank(message = "员工姓名不能为空",groups= {EmpEditValidator.class, EmpAddValidator.class})
@NotBlank(message = "{emp.ename.NotBlank}",groups= {
EmpEditValidator.class, EmpAddValidator.class})
// @Length(message = "员工姓名必须为2~8位字符",min = 2, max = 8)
// @Length(message = "员工姓名必须为2~8个字符", min = 2, max = 8,groups= {EmpEditValidator.class, EmpAddValidator.class})
@Length(message = "{emp.ename.Length}", min = 2, max = 8,groups= {
EmpEditValidator.class, EmpAddValidator.class})
private String ename;
// @NotBlank(message = "员工岗位不能为空")
// @NotBlank(message = "员工岗位不能为空",groups= {EmpEditValidator.class, EmpAddValidator.class})
@NotBlank(message = "{emp.job.NotBlank}",groups= {
EmpEditValidator.class, EmpAddValidator.class})
private String job;
// @NotNull(message = "员工薪资不能为空")
// @NotNull(message = "员工薪资不能为空",groups= {EmpEditValidator.class, EmpAddValidator.class})
@NotNull(message = "{emp.salary.NotNull}",groups= {
EmpEditValidator.class, EmpAddValidator.class})
// @DecimalMin(message = "员工薪资不能低于1000",value = "1000")
// @DecimalMin(message = "员工薪资不能低于1000", value = "1000", groups = {EmpEditValidator.class, EmpAddValidator.class})
@DecimalMin(message = "{emp.salary.DecimalMin}", value = "1000", groups = {
EmpEditValidator.class, EmpAddValidator.class})
private Double sal;
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Double getSal() {
return sal;
}
public void setSal(Double sal) {
this.sal = sal;
}
@Override
public String toString() {
return "Emp{" +
"empno=" + empno +
", ename='" + ename + '\'' +
", job='" + job + '\'' +
", sal=" + sal +
'}';
}
}
错误提示信息资源文件也可自定义名称和位置,配置如下:
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator" />
<property name="validationMessageSource" ref="validationMessageSource">property>
bean>
<bean id="validationMessageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:messagevalue>
list>
property>
<property name="fileEncodings" >
<props>
<prop key="classpath:message">utf-8prop>
props>
property>
<property name="cacheSeconds" value="120">property>
bean>