SpringMVC数据校验

数据校验

B/S系统中对http请求数据的校验多数在客户端进行,这也是出于简单及用户体验性上考虑。但是在一些安全性要求高的系统中服务端校验是不可缺少的,SpringMVC实现控制层添加校验。SpringMVC使用Hibernate Validator的校验框架(和Hibernate ORM没有任何关系)

1. 前端校验

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>

2. maven依赖

导入hibernate-validator的jar包

SpringMVC数据校验_第1张图片

<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>

3. SpringMVC配置

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>

4. 校验注解规则

4.1 Bean Validator内置的注解

校验注解 校验的数据类型 说明
@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集合,数组 被注释的元素值的大小必须在指定的范围内

4.2 Hibernate Validator拓展的注解

校验注解 校验的数据类型 说明
@Email 字符串 被注释的元素值必须是电子邮箱地址
@Length(min=,max=) 字符串 被注释的元素值的大小必须在指定的范围内
@NotBlank 字符串 被注释的元素值必须非空,非空值或非全空白字符。功能强大于@NotEmpty
@NotEmpty 字符串,Collection集合,Map集合,数组 被注释的元素值必须非空或非空值。功能强于@NotNull
@Range(min=,max=) BigDecimal,BigInteger,byte,short,int,long以及基本数据类型相应的包装类 被注释的元素值必须在合适的范围内

5. 添加校验规则

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 +
                '}';
    }
}

6. 捕获校验错误信息

@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放在实体类的后边

7. 在页面显示校验错误信息

在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>

8. 分组校验

如果两处校验使用同一个实体类则可以设定校验分组,通过分组校验可以对每处的校验个性化

8.1 定义分组标识

定义分组标识,就是定义一个空接口

public interface EmpAddValidator {
     
}

public interface EmpEditValidator {
     
}

8.2 在校验规则中添加分组

/**
 * 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 +
                '}';
    }
}

8.3 在@Validated注解中指定分组

@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";
    }
}

8.4 编辑页面

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>

9. 错误提示信息资源文件

9.1 资源文件

当属性值校验失败后,其提示信息可配置在一个资源文件中,文件名称默认为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

9.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 +
                '}';
    }
}

9.3 配置

错误提示信息资源文件也可自定义名称和位置,配置如下:


<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>

你可能感兴趣的:(springmvc,springmvc,spring,java,数据校验)