SpringMVC的JSR303数据验证
对于JSR303验证,目前有两个实现,一个是Hibernate Valicator,另一个是Apache BVal,本次采用的是Hibernate Validator,注意它和Hibernate无关,只是使用它进行数据验证。
利用JSR303(Java验证规范)对数据进行验证,验证要求如下:
1-商品名和商品详情不能为空
2-商品价格在0到100
3-创建日期不能在系统日期之后
1-在IDEA中创建web应用ch14-2,在该应用的WEB-INF目录下创建目录lib,在lib目录中导入相关jar包,并将lib添加为项目库。jar包主要是SpringMVC相关jar包和Hibernate Validator相关jar包。
2-创建数据输入页面,在WEB-INF目录下创建jsp目录,在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 = "gname"/>
<form:errors path = "gdescription"/>
<form:errors path = "gprice"/>
<form:errors path = "gdate"/>
</form:form>
</body>
</html>
3-在src目录下创建pojo包,在该包中创建Goods类,利用JSR303的标注类型对属性进行验证。
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.Range;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.Past;
import java.util.Date;
/**
* JSR303不需要编写验证器,但是需要利用它的标注类型在领域模型的属性上嵌入约束。
*/
public class Goods {
@NotBlank(message = "{goods.gname.required}")
private String gname ;
@NotBlank(message = "{goods.gdescription.required}")
private String gdescription ;
@Range(min = 0, max = 100, message = "{gprice.invalid}")
private double gprice ;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@Past(message = "{gdate.invalid}")
private Date gdate ;
public Date getGdate() {
return gdate;
}
public void setGdate(Date gdate) {
this.gdate = 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;
}
}
4-在WEB-INF目录下创建文件夹resource,并在该文件夹中编写属性文件error.properties,内容如下:
goods.gname.required=请输入商品名称
goods.gdescription.required=请输入商品详情
gprice.invalid=价格为0-100
gdate.invalid=创建日期不能在系统日期之后
5-编写Service层,在src目录下创建service包,在该包中编写一个接口GoodsService和实现类GoodsServiceImpl
接口GoodsService:
import pojo.Goods;
import java.util.ArrayList;
public interface GoodsService {
boolean save(Goods goods) ;
ArrayList <Goods> getGoods() ;
}
实现类GoodsServiceImpl:
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;
}
}
6-编写控制器类,在src目录下创建controller包,在该包下编写控制器类GoodsController
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import pojo.Goods;
import service.GoodsService;
import javax.validation.Valid;
@Controller
@RequestMapping("/goods")
public class GoodsController {
//得到一个用来记录日志的对象,这样就能标记打印了哪个控制器类的信息
private static final Log logger = LogFactory.getLog(GoodsController.class) ;
@Autowired
private GoodsService goodsService ;
@RequestMapping("/input")
public String input(Model model){
model.addAttribute("goods", new Goods()) ;
return "addGoods" ;
}
@RequestMapping("/save")
public String save(@Valid @ModelAttribute Goods goods, BindingResult result, Model model){
if(result.hasErrors()){
return "addGoods" ;
}
goodsService.save(goods) ;
logger.info("添加成功") ;
model.addAttribute("goodsList" , goodsService.getGoods()) ;
return "goodsList" ;
}
}
7-在web.xml中部署DispatcherServlet,配置 CharacterEncodingFilter解决中文乱码问题。
<?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>
8-在WEB-INF目录下创建springmvc核心配置文件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
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"/>
<mvc:annotation-driven />
<!--注册校验器-->
<bean id = "validator" class = "org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<!--hibernate校验器-->
<property name = "providerClass" value="org.hibernate.validator.HibernateValidator"/>
<!--指定校验使用的资源文件,在文件中配置校验错误信息,如果不指定则默认使用classpath下的ValidationMessages.properties-->
<property name = "validationMessageSource" ref = "messageSource"/>
</bean>
<!--因为使用了日期格式化转换器,所以需要注册日期格式化转换器-->
<bean id = "conversionService" class = "org.springframework.format.support.FormattingConversionServiceFactoryBean">
</bean>
<mvc:annotation-driven conversion-service="conversionService" validator="validator"/>
<!--SpringMVC想从属性文件中获取错误信息,需要配置一个MessageSource Bean-->
<bean id = "messageSource" class = "org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name = "basename" value="/WEB-INF/resource/error"/>
</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>
9-在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/8/12
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>
10-将应用发布到tomcat,在该地址:http://localhost:8080/ch14_2_war_exploded/goods/input下测试。
验证商品名和商品详情为空:
验证商品价格不在0-100之间:
验证创建日期在系统日期之后:
验证全部输入正确: