SpringMVC的数据验证

Posted nuist__NJUPT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringMVC的数据验证相关的知识,希望对你有一定的参考价值。

SpringMVC的数据验证

用户的输入一般是随意的,为了保证数据的合法性,数据验证是所有web应用必须处理的问题。
数据验证分为客户端验证和服务器端验证,客户端验证主要是过滤用户的误操作,通过JS代码实现,服务器端验证应用阻止非法数据的最后防线,通常在应用中编程实现。

在大多数情况下,使用JS代码进行客户端验证包括3步:
1-编写验证函数
2-在提交表单时候调用验证函数
3-根据验证函数判断是否进行表单提交

通常仅有客户端验证是不够的,攻击者可能绕过客户端进行非法输入,这样可能引起系统异常,为保证数据的合法性,必须加上服务器验证。

一般是先进行数据类型转换,再进行服务器端验证。
服务器验证对于系统的安全性,完整性,健壮性起到至关重要的作用。SpringMVC框架中可以利用Spring自带的验证框架进行数据验证,也可以利用JSR303进行数据验证。

本次主要学习Spring自带的验证框架,创建自定义Spring验证器需要实现Validator接口,该接口有两个方法,分别为supports方法和validator方法,当supports返回为true时,验证器可以处理指定的Class,validate方法的功能是验证目标对象object,并将验证错误消息存入Errors对象。在Errors对象存入错误消息的方法是reject或rejectValue。在一般情况下,只需要给reject或rejectValue方法一个错误代码,SpringMVC就会在消息属性文件中查找错误代码,获取相应的错误消息。

ValidationUtils类是一个工具类,该类中有几个方法可以帮助用户判定值是否为空。

下面通过一个案例学习Spring验证器的编写及使用。
1-创建we应用,在WEB-INF文件夹下创建目录lib,并在该目录中导入相关jar包。
2-在WEB-INF创建jsp目录,在该目录中创建数据输入页面addGoods.jsp。

<%@ page language="java" contentType="text/html; charset=utf-8"
         pageEncoding="utf-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Insert title here</title>
</head>
<body>
<form:form modelAttribute = "goods" action = "${pageContext.request.contextPath}/goods/save" method = "post">
    <fieldset>
        <lengend>添加一个商品</lengend>
        <p>
            <label>商品名:</label>
            <form:input path = "gname"/>
        </p>
        <p>
            <label>商品详情:</label>
            <form:input path = "gdescription"/>
        </p>
        <p>
            <label>创建价格:</label>
            <form:input path = "gprice"/>
        </p>
        <p>
            <label>创建日期:</label>
            <form:input path = "gdate"/>(yyyy-MM-dd)
        </p>
        <p id = "buttons">
            <input id = "reset" type = "reset"/>
            <input id = "submit" type = "submit" value = "添加"/>
        </p>
    </fieldset>
    <!--取出所有验证错误-->
    <form:errors path = "*"/>

</form:form>
</body>
</html>

3-在src下创建pojo包,在该包中创建领域模型类Goods类,并封装输入参数。

import org.springframework.format.annotation.DateTimeFormat;

import java.util.Date;

public class Goods {
    private String gname ;
    private String gdescription ;
    private double gprice ;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date gdate ;

    public String getGname() {
        return gname;
    }

    public void setGname(String gname) {
        this.gname = gname;
    }

    public String getGdescription() {
        return gdescription;
    }

    public void setGdescription(String gdescription) {
        this.gdescription = gdescription;
    }

    public double getGprice() {
        return gprice;
    }

    public void setGprice(double gprice) {
        this.gprice = gprice;
    }

    public Date getGdate() {
        return gdate;
    }

    public void setGdate(Date gdate) {
        this.gdate = gdate;
    }
}

4-在src目录下创建valiator包,在该包中创建验证器类GoodsValidator,使用注解@component声明为验证器组件。

import java.util.Date;

@Component //注解为验证器组件
public class GoodsValidator implements Validator { //实现Validator接口,并重写两个方法

    @Override
    public boolean supports(Class<?> aClass) {
        //要验证的model,返回值为false则不验证
        return Goods.class.isAssignableFrom(aClass) ;
    }

    @Override
    public void validate(Object object, Errors errors) {
        Goods goods = (Goods)object ; //要验证的对象那个
        ValidationUtils.rejectIfEmpty(errors, "gname", "goods.gname.required"); //商品名称验证
        ValidationUtils.rejectIfEmpty(errors, "gdescription", "goods.gdescription.required"); //商品描述信息验证
        if(goods.getGprice() > 100 || goods.getGprice() < 0){ //商品价格验证
            errors.rejectValue("gprice", "gprice.invalid") ;
        }
        if(goods.getGdate() != null &&  goods.getGdate().after(new Date())){ //商品创建日期验证
            errors.rejectValue("gdate", "gdate.invalid") ;
        }
    }
}

5-在WEB-INF目录下创建文件夹resource,在该文件夹下编写错误消息属性文件errorMessages.properties

goods.gname.required = 请输入商品名称
goods.gdescription.required = 请输入商品详情
gprice.invalid = 价格为0-100
gdate.invalid = 创建的日期不能再系统日期之后

6-在src目录下创建sevice包,在该包中创建接口和实现类,模拟添加商品和查询商品信息。


import pojo.Goods;

import java.util.ArrayList;

public interface GoodsService {
    boolean save(Goods goods) ; //添加商品
    ArrayList<Goods> getGoods()  ; //查询商品
}


import org.springframework.stereotype.Service;
import pojo.Goods;

import java.util.ArrayList;
@Service
public class GoodsServiceImpl implements GoodsService {
    //使用静态集合变量模拟数据库
    private static ArrayList<Goods> goods = new ArrayList<>() ;

    @Override
    public boolean save(Goods g) {
        goods.add(g) ;
        return true;
    }

    @Override
    public ArrayList<Goods> getGoods() {
        return goods;
    }
}

7-在src目录下创建controller包,在该包中编写控制器类,在该类中使用@Resource注解为自定义验证器,另外在控制器类中包含两个请求处理方法。

import javax.annotation.Resource;

@Controller
@RequestMapping("/goods")
public class GoodsController {
    @Autowired
    private GoodsService goodsService ;
    @Resource //注解验证器相等于创建验证器的实例对象
    private Validator validator ;
    @RequestMapping("/input")
    public String input(Model model){
        //因为表单标签无法找到modelAttribute属性指定的form backing object
        model.addAttribute("goods", new Goods()) ; //如果model中没有goods属性,addGoods.jsp会异常
        return "addGoods" ;
    }
    @RequestMapping("/save")
    public String save(Goods goods, BindingResult result , Model model){
        this.validator.validate(goods, result); //调用验证器的验证方法,验证goods对象,并将结果存入到result中
        if(result.hasErrors()){
            return "addGoods" ;
        }
        goodsService.save(goods) ;
        model.addAttribute("goodsList" , goodsService.getGoods()) ;
        return "goodsList" ;
    }
}

8-在WEB-INF目录下编写配置文件springservlet.xml,在该配置文件中在配置文件中配置错误消息属性文件,告诉SpringMVC从该文件中获取错误消息。扫描指定的包,使注解生效,注册格式转换器,配置视图解析器。

<?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
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--使用扫描机制,扫描控制器类,s使得注解生效-->
    <context:component-scan base-package="controller"/>
    <context:component-scan base-package="service"/>
    <context:component-scan base-package="validator"/>
    <mvc:annotation-driven />

    <!--因为使用了日期格式化转换器,所以需要注册日期格式化转换器-->
    <bean id = "conversionService" class = "org.springframework.format.support.FormattingConversionServiceFactoryBean">
    </bean>
    <mvc:annotation-driven conversion-service="conversionService"/>
    <!--SpringMVC想从属性文件中获取错误信息,需要配置一个MessageSource Bean-->
    <bean id = "messageSource" class = "org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name = "basename" value="/WEB-INF/resource/errorMessages"/>
    <property name="defaultEncoding" value="GBK"></property>
</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>


10-在WEB-INF/jsp目录下创建数据显示文件goodsList.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
  Created by IntelliJ IDEA.
  User: nuist__NJUPT
  Date: 2021/10/1
  Time: 9:03
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<table>
    <tr>
        <td>商品名</td>
        <td>商品详情</td>
        <td>商品价格</td>
        <td>创建日期</td>
    </tr>
    <c:forEach items="${goodsList}" var = "goods">
        <tr>
            <td>${goods.gname}</td>
            <td>${goods.gdescription}</td>
            <td>${goods.gprice}</td>
            <td>${goods.gdate}</td>
        </tr>
    </c:forEach>
</table>
</body>
</html>


11-需要在web.xml文件中部署SpringMVC的核心控制器DispatcherServlet。

<?xml version="1.0" encoding="UTF-8"?>
<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"
         id = "WebApp_ID" version="4.0">
    <!--部署DispatcherServlet-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>WEB-INF/springmvc-servlet.xml</param-value>
        </init-param>
        <!--表示容器启动时加载的servlet-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <!--任意的请求都通过DispatcherServlet-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- 配置 CharacterEncodingFilter解决中文乱码问题-->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

        <!-- 配置编码格式为UTF-8 -->
        <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>


12-测试并发布应用。

工作流程:用户输入链接后,进入数据采集页面addGood.jsp,在信息采集页面输入信息后,点击添加按钮,则将客户端请求提交到总控制器DispatcherServlet,右总控制器根据映射找到对应的controller,在cotroller中注入验证器类,通过验证器判断是否右错误,若有错误,则调用错误信息,返回addGoods.jsp页面,否则将模型信息添加到数据库,返回信息显示页面goodsList,在信息显示页面取出存入模型的数据。

以上是关于SpringMVC的数据验证的主要内容,如果未能解决你的问题,请参考以下文章

springMVC框架中的ajax验证

springmvc 分页查询的简单实现

SpringMVC4+thymeleaf3的一个简单实例(篇四:form表单数据验证)

SpringMVC的JSR303数据验证

SpringMVC之使用Validator接口进行验证

SpringMVC框架中如何去掉登录验证码?