第十四章 数据校验

target

了解数据校验的意义
了解客户端校验(使用 JavaScript 进行客户端验证)
了解ValidationUtils工具类和Validator接口
掌握日期格式的转化
理解数据校验的开发步骤
理解 Hibernate-Validator数据验证

1. 概述

用户的输入一般是随意的,为了保证数据的合法性,数据验证是所有 Web 应用必须处理的问题。

在 Spring MVC框架中有以下两种方法可以验证输入数据:

  • 利用 Spring自带的验证框架。
  • 利用 JSR 303 实现。

数据验证分为客户端验证和服务器端验证,客户端验证主要是过滤正常用户的误操作,通过 JavaScript 代码完成。服务器端验证是整个应用阻止非法数据的最后防线,通过在应用中编程实现。

1.1 客户端验证

在大多数情况下,使用 JavaScript 进行客户端验证的步骤如下:

  • 编写验证函数。
  • 在提交表单的事件中调用验证函数。
  • 根据验证函数来判断是否进行表单提交。

客户端验证可以过滤用户的误操作,是第一道防线,一般使用 JavaScript 代码实现。但仅有客户端验证是不够的,攻击者还可以绕过客户端验证直接进行非法输入,这样可能会引起系统异常,为了确保数据的合法性,防止用户通过非正常手段提交错误信息,必须加上服务器端验证。

1.2 服务端验证

Spring MVC 的 Converter 和 Formatter 在进行类型转换时是将输入数据转换成领域对象的属性值(一种 Java 类型),一旦成功,服务器端验证器就会介入。也就是说,在 Spring MVC 框架中先进行数据类型转换,再进行服务器端验证。

服务器端验证对于系统的安全性、完整性、健壮性起到了至关重要的作用。在 Spring MVC 框架中可以利用 Spring 自带的验证框架验证数据,也可以利用 JSR 303 实现数据验证。

2. SpringMVC校验

创建自定义 Spring验证器时需要实现的 Validator 接口和工具类 ValidationUtils。

2.1 Validator接口

创建自定义 Spring 验证器需要实现 org.springframework.validation.Validator 接口,该接口有两个接口方法:

boolean supports(Class<?> klass)
void validate(Object object,Errors errors)

当 supports 方法返回 true 时,验证器可以处理指定的 Class。validate 方法的功能是验证目标对象 object,并将验证错误消息存入 Errors 对象。

往 Errors 对象存入错误消息的方法是 reject 或 rejectValue,这两个方法的部分重载方法如下:

void reject(String errorCode)
void reject(String errorCode,String defaultMessage)
void rejectValue(String filed,String errorCode)
void rejectValue(String filed,String errorCode,String defaultMessage)

在一般情况下只需要给 reject 或 rejectValue 方法一个错误代码,Spring MVC框架就会在消息属性文件中查找错误代码,获取相应错误消息。具体示例如下:

if(goods.getGprice() > 100 || goods.getGprice() < 0){
    errors.rejectValue("gprice","gprice.invalid");  // gprice.invalid为错误代码
}

2.2 ValidationUtils 类

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

例如:

if(goods.getGname()==null || goods.getGname().isEmpty()) {
    errors.rejectValue("gname","goods.gname.required")
}

再如:

if(goods.getGname() == null || goods.getGname().trim().isEmpty()) {
    errors.rejectValue("gname","goods.gname.required")
}

上述 if 语句可以编写成:

//gname为goods对象的属性
ValidationUtils.rejectIfEmptyOrWhitespace(errors,"gname","goods.gname.required");

2.3 实例

做一个如下的页面进行校验:


编写一个实现 org.springframework.validation.Validator 接口的验证器类 GoodsValidator,验证要求如下:

  • 商品名和商品详情不能为空。
  • 商品价格在 0 到 100。
  • 创建日期不能在系统日期之后。

① 创建实体类

在该类中使用 @DateTimeFormat(pattern="yyyy-MM-dd")格式化创建日期。

package com.lee.springmvc.bean;

public class Goods {
  private String gname;
  private String gdescription;
  private double gprice;
  // 日期格式化(还需要在配置文件中添加"mvc:annotation-driven"这个标签, 否则不生效.)
  @DateTimeFormat(pattern = "yyyy-MM-dd")
  private Date gdate; 

  // getter、setter略
}

② 创建数据输入页面

在 WEB-INF 目录下创建文件夹 views,并在该文件夹中创建数据输入页面 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>
<html>
<head>
<meta charset="UTF-8">
<title>添加商品</title>
</head>
<body>
    <form:form modelAttribute="goods"
        action="${pageContext.request. contextPath }/goods/save" method="post">
        <fieldset>
            <legend> 添加一件商品 </legend>
            <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>

③ 编写验证器类

编写实现 org.springframework.validation.Validator 接口的验证器类 GoodsValidator,使用 @Component 注解将 GoodsValidator 类声明为验证组件。具体代码如下:

package com.lee.springmvc.validator;

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

    @Override
    public void validate(Object object, Errors errors) {
        Goods goods = (Goods) object; // object要验证的对象
        // goods.gname.required是错误消息属性文件中的编码(国际化后对应的是国际化的信息)
        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");
        }
        Date goodsDate = goods.getGdate();
        // 在系统时间之后
        if (goodsDate != null && goodsDate.after(new Date())) {
            errors.rejectValue("gdate", "gdate.invalid");
        }
    }
}

④ 编写错误消息属性文件

在 WEB-INF 目录下创建文件夹 resource,并在该文件夹中编写属性文件 errorMessages.properties。文件内容如下:

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

Unicode 编码(Eclipse 带有将汉字转换成 Unicode 编码的功能)的属性文件内容如下:

goods.gname.required=\u8BF7\u8F93\u5165\u5546\u54C1\u540D\u79F0
goods.gdescription.required=\u8BF7\u8F93\u5165\u5546\u54C1\u8BE6\u60C5
gprice.invalid=\u4EF7\u683C\u4E3A0~100
gdate.invalid=\u521B\u5EFA\u65E5\u671F\u4E0D\u80FD\u5728\u7CFB\u7EDF\u65E5\u671F\u4E4B\u540E

在属性文件创建完成后需要告诉 Spring MVC 从该文件中获取错误消息,则需要在springmvc.xml配置文件中声明一个 messageSource bean,具体代码如下:

<!-- 配置消息属性文件 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="/WEB-INF/resource/errorMessages" />
</bean>

⑤ 编写 Service 层

编写一个 GoodsService 接口。具体代码如下:

package com.lee.springmvc.service;

public interface GoodsService {
    public boolean save(Goods g);
    public ArrayList<Goods> getGoods();
}

GoodsServiceImpl 实现类具体代码如下:

package com.lee.springmvc.service.impl;

@Service
public class GoodsServiceImpl implements GoodsService {
    // 使用静态集合变量goods模拟数据库
    private static ArrayList<Goods> goods = new ArrayList<Goods>();
    @Override
    public boolean save(Goods g) {
        goods.add(g);
        return true;
    }
    @Override
    public ArrayList<Goods> getGoods() {
        return goods;
    }
}

⑥ 编写控制器类

编写控制器类 GoodsController,在该类中使用 @Resource 注解注入自定义验证器。另外,在控制器类中包含两个处理请求的方法,具体代码如下:

package com.lee.springmvc.controller;

@Controller
@RequestMapping("/goods")
public class GoodsController {
    // 得到一个用来记录日志的对象,这样在打印信息的时候能够标记打印的是哪个类的信息
    private static final Log logger = LogFactory.getLog(GoodsController.class);
    @Autowired
    private GoodsService goodsService;
    // 注解验证器相当于"GoodsValidator validator=new GoodsValidator () ; "
    @Resource
    private Validator validator;

    @RequestMapping("/input")
    public String input(Model model) {
        // 如果model中没有goods属性,addGoods.jsp会抛出异常
        // 因为表单标签无法找到modelAttribute属性指定的form backing object
        model.addAttribute("goods", new Goods());
        return "addGoods";
    }

    @RequestMapping("/save")
    public String save(Goods goods, BindingResult result, Model model) {
        this.validator.validate(goods, result); // 添加验证,如果没有这行代码将不会验证
        if (result.hasErrors()) {
            return "addGoods";
        }
        goodsService.save(goods);
        logger.info("添加成功");
        model.addAttribute("goodsList", goodsService.getGoods());
        return "goodsList";
    }

}

⑦ 编写配置文件

在 src 目录下编写配置文件 springmvc.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"
    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-4.3.xsd">

    <context:component-scan base-package="com.lee"></context:component-scan>

    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!-- 配置消息属性文件 -->
    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="/WEB-INF/resource/errorMessages" />
    </bean>
  
  <mvc:annotation-driven></mvc:annotation-driven>
</beans>

⑧ 创建数据显示页面

在 WEB-INF/views 目录下创建数据显示页面 goodsList.jsp。核心代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</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>

⑨ 创建 web.xml 文件

在 WEB-INF 目录下创建 web.xml 文件,在该文件中配置 Spring MVC 的核心控制器 DispatcherServlet 和字符编码过滤器,具体代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>Validator</display-name>
   <!--配置DispatcherServlet-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <!--避免中文乱码-->
    <filter>
        <filter-name>encodingFilter</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>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

⑩ 测试应用

发布 应用并启动 Tomcat 服务器,然后通过地址"http://localhost:8080/SpringMVC-14/goods/input"测试应用。

当表单填写不正确时:


当填写正确时:


2.4 开发经验

① 日期转化

如果有如下需求:

  • 前台输入一个字符串形式的日期
  • 实体类是Date类型
  • 控制器将前台接受到的字符串类型转化为Date类型

方法一:

//1.首先在实体类上加注解
@DateTimeFormat(pattern = "yyyy-MM-dd")
 private Date gdate;

// 2. springmvc配置文件中开启annotation-driven
<mvc:annotation-driven></mvc:annotation-driven>

方法二:

//在控制器里使用@InitBinder格式化
@InitBinder
public void initBinder(WebDataBinder binder) {
  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
  binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); // true:允许输入空值,false:不能为空值
}

② 数据校验步骤

//1. 首先编写校验类(需实现Validator接口),并将该类纳入到IOC容器
@Component
public class GoodsValidator implements Validator
  
//2. 错误信息的配置文件
  goods.gdescription.required=请输入商品详情
    gprice.invalid=价格为0~100
  
//3. 在springmvc配置文件中,将错误信息的配置文件加载
  <!-- 配置消息属性文件 -->
    <bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="/WEB-INF/resource/errorMessages" />
    </bean>
  
//4. 在控制器中开启校验
  @Resource
    private Validator validator;

    this.validator.validate(goods, result); // 添加验证

3. Hibernate-Validator数据验证

对于 JSR 303 验证,目前有两个实现,一个是 Hibernate Validator,一个是 Apache BVal。本教程采用的是 Hibernate Validator,注意它和 Hibernate 无关,只是使用它进行数据验证。

3.1 相关jar

hibernate-validator-4.3.2.Final.jar
jboss-logging-3.1.0.Final.jar
validation-api-1.0.0. GA.jar
classmate-0.8.0.jar

3.2 标注类型

JSR 303 不需要编写验证器,但需要利用它的标注类型在领域模型的属性上嵌入约束。

① 空检查

  • @Null:验证对象是否为 null。
  • @NotNull:验证对象是否不为 null,无法检查长度为 0 的字符串。
  • @NotBlank:检查约束字符串是不是 null,以及被 trim 后的长度是否大于 0,只针对字符串,且会去掉前后空格。
  • @NotEmpty:检查约束元素是否为 null 或者是 empty。

示例如下:

@NotBlank(message="{goods.gname.required}") //goods.gname.required为属性文件的错误代码
private String gname;

② boolean 检查

  • @AssertTrue:验证 boolean 属性是否为 true。
  • @AssertFalse:验证 boolean 属性是否为 false。

示例如下:

@AssertTrue
private boolean isLogin;

③ 长度检查

  • @Size(min=,max=):验证对象(Array、Collection、Map、String)长度是否在给定的范围之内。
  • @Length(min=,max=):验证字符串长度是否在给定的范围之内。

示例如下:

@Length(min=1,max=100)
private String gdescription;

④ 日期检查

  • @Past:验证 Date 和 Callendar 对象是否在当前时间之前。
  • @Future:验证 Date 和 Calendar 对象是否在当前时间之后。
  • @Pattern:验证 String 对象是否符合正则表达式的规则。

示例如下:

@Past(message="{gdate.invalid}")
private Date gdate;

⑤ 数值检查

名称 说明
@Min 验证 Number 和 String 对象是否大于指定的值
@Max 验证 Number 和 String 对象是否小于指定的值
@DecimalMax 被标注的值必须不大于约束中指定的最大值,这个约束的参数是一个通过 BigDecimal 定义的最大值的字符串表示,小数存在精度
@DecimalMin 被标注的值必须不小于约束中指定的最小值,这个约束的参数是一个通过 BigDecimal 定义的最小值的字符串表示,小数存在精度
@Digits 验证 Number 和 String 的构成是否合法
@Digits(integer=,fraction=) 验证字符串是否符合指定格式的数字,integer 指定整数精度,fraction 指定小数精度
@Range(min=,max=) 检查数字是否介于 min 和 max 之间
@Valid 对关联对象进行校验,如果关联对象是个集合或者数组,那么对其中的元素进行校验,如果是一个 map,则对其中的值部分进行校验
@CreditCardNumber 信用卡验证
@Email 验证是否为邮件地址,如果为 null,不进行验证,通过验证

示例如下:

@Range(min=10,max=100,message="{gprice.invalid}")
private double gprice;

⑥ 正则表达式

名称 说明 实例
@Pattern 值必须匹配正则表达式 @Pattern(regext = "\d{3}")

3.3 简单版本实例

  • 直接在实体类上加注解,并且写好message《注意:message内容用双引号引起来》
  • 在控制器中对需要校验的参数前加注解@Valid即可

注意:springmvc配置文件需要有<mvc:annotation-driven>

① 实体类

public class User {

    @NotBlank(message = "用户名不能为空!")
    private String username;
    
    @Range(min = 1,max = 120,message = "年龄必须是1-120之间!")
    private int age;
    
    @NotEmpty(message = "电话号码不能为空!")
    @Pattern(regexp = "/^(13[0-9]|15[0|1|3|6|7|8|9]|18[8|9])\\d{8}$/")
    private String tel;
    
    @Email(message = "不合法的电子邮箱!")
    private String email;
    
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @Past(message = "必须是当前日期之前的一个日期!")
    private Date birthday;
  
}

② 前台表单:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
    <form:form action="${pageContext.servletContext.contextPath }/user/register" method="post" modelAttribute="user">
        <fieldset>
            <legend>请输入注册信息</legend>
            <p>
                <label>用户名</label>
                <form:input path="username" />
            </p>
            <p>
                <label>年龄</label>
                <form:input path="age" />
            </p>
            <p>
                <label>电话号码</label>
                <form:input path="tel" />
            </p>
            <p>
                <label>电子邮箱</label>
                <form:input path="email" />
            </p>
            <p>
                <label>出生日期</label>
                <form:input path="birthday" />
            </p>
            <p>
                <input type="reset"> <input type="submit" value="注册">
            </p>
        </fieldset>
        <!-- 取出所有验证错误 -->
        <form:errors path="*" />
    </form:form>
</body>
</html>

③ 控制器

一定要加@Valid注解,否则不会校验。

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("input")
    public String register(Model model) {
        model.addAttribute("user",new User());
        return "register";
    }
    
    @RequestMapping("register")
    public String save(@Valid User user,BindingResult result) {
        System.out.println(user);
        System.out.println(result);
    
        if (result.hasErrors()) {
            return "register";
        }
        return "success";
        
    }
}

3.4 配置文件版本实例

  • 在实体类属性上加相应注解,message需要写配置文件的key《message内容需要用大括号引起来》
  • 错误消息配置文件
  • 在springmvc配置文件中加载错误消息配置文件
  • 在控制器中使用@Valid对模型对象就行校验

① 实体类

public class User {

    @NotBlank(message = "{user.username.notblank}")
    private String username;
    
    @Range(min = 1,max = 120,message = "{user.age.range}")
    private int age;
    
    @NotEmpty(message = "{user.tel.notblank}")
    @Pattern(regexp = "^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$",message = "{user.tel.notMatch}")
    private String tel;
    
    @Email(message = "{user.email.notMatch}")
    private String email;
    
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @Past(message = "{user.birthday.before}")
    private Date birthday;
}

② 前台表单

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
    <form:form action="${pageContext.servletContext.contextPath }/user/register" method="post" modelAttribute="user">
        <fieldset>
            <legend>请输入注册信息</legend>
            <p>
                <label>用户名</label>
                <form:input path="username" />
            </p>
            <p>
                <label>年龄</label>
                <form:input path="age" />
            </p>
            <p>
                <label>电话号码</label>
                <form:input path="tel" />
            </p>
            <p>
                <label>电子邮箱</label>
                <form:input path="email" />
            </p>
            <p>
                <label>出生日期</label>
                <form:input path="birthday" />
            </p>
            <p>
                <input type="reset"> <input type="submit" value="注册">
            </p>
        </fieldset>
        <!-- 取出所有验证错误 -->
        <form:errors path="*" />
    </form:form>
</body>
</html>

③ 错误消息配置文件

在WEB-INF/resource目录下,新建errorMessages.properties文件:

user.username.notblank=\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A
user.age.range=\u7528\u6237\u5E74\u9F84\u5E94\u8BE5\u57280~120\u4E4B\u95F4
user.tel.notblank=\u7528\u6237\u7535\u8BDD\u4E0D\u80FD\u4E3A\u7A7A
user.tel.notMatch=\u7535\u8BDD\u53F7\u7801\u4E0D\u7B26\u5408\u89C4\u8303
user.email.notMatch=\u975E\u6CD5\u7684\u90AE\u7BB1
user.birthday.before=\u8F93\u5165\u4E00\u4E2A\u6BD4\u5F53\u524D\u65E5\u671F\u5C0F\u7684\u65E5\u671F

④ springmvc加载错误消息配置文件

必须在springmvc的配置文件中将上面配置的文件加载,程序才能读到相关配置:

需要在mvc注解驱动里开启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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
        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-4.3.xsd">


    <!-- 包扫描 -->
    <context:component-scan base-package="com.lee"></context:component-scan>

    <!-- 视图解析器 -->
    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
    
     <!-- 配置消息属性文件 -->
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>/WEB-INF/resource/errorMessages</value>
            </list>
        </property>
         <!-- 资源文件编码格式 -->
        <property name="fileEncodings" value="utf-8" />
        <!-- 对资源文件内容缓存的时间,单位为秒 -->
        <property name="cacheSeconds" value="120" />
    </bean>
    
     <!-- 注册校验器 -->
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <!-- hibernate 校验器 -->
        <property name="providerClass" value="org.hibernate.validator.HibernateValidator" />
        <!-- 指定校验使用的资源文件,在文件中配置校验错误信息,如果不指定则默认使用 classpath下的 VaiidationMessages.properties -->
        <property name="validationMessageSource" ref="messageSource" />
    </bean>
    <!--开启 Spring的 Valid 功能 -->
    <mvc:annotation-driven validator="validator" />
</beans>

⑤ 控制器

控制器里直接对模型对象用@Valid注解校验即可,还需要把校验结果用BindingResult进行绑定:

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("input")
    public String register(Model model) {
        model.addAttribute("user",new User());
        return "register";
    }
    
    @RequestMapping("register")
    public String save(@Valid User user,BindingResult result) {
        System.out.println(user);
        System.out.println(result);
        if (result.hasErrors()) {
            return "register";
        }
        return "success";
        
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容