# 数据校验

# 概述

在 Web 应用程序中,为了防止客户端传来的数据引发程序异常,常常需要对数据进行验证。

数据验证分为:

  • 客户端验证
    • 客户端验证主要通过 JavaScript 脚本进行。
  • 服务端验证
    • 服务端验证主要通过 Java 代码进行验证。

为了保证数据的安全性,客户端和服务端验证都是必须的。

Spring MVC 提供了强大的数据校验功能,其中有两种方法可以验证输入:

  • 利用 Spring 自带的 Validation 校验框架(早于 JSR 303,不建议使用)
  • 利用 JSR 303(Java 校验规范)实现校验功能

JSR 只是一套规范,其具体的实现中 Hibernate Validator 是最常见的实现,它即实现了 JSR 303 的要求,又实现了更新的 JSR 349 的要求)。

WARNING

由于版本原因,使用 hibernate-validator 6.x 版本使用 tomcat 7 插件 只能二选一。

Spring MVC 对 JSR 提供了良好的支持,如果,Spring MVC 的配置文件中配置了 <mvc:annotation-driven />,那么就不再需要其它任何配置了。

以下 所有 注解都有 message 属性用以在验证不通过是显示提示信息。

# JSR 303 的注解

注解 说明
@Null 被注解的元素必须为 null
@NotNull 被注解的元素必须不为 null
@AssertTrue 被注解的元素必须为 true
@AssertFalse 被注解的元素必须为 false
@Min 被注解的元素必须是一个数字,其值必须小于指定值。
@Max 被注解的元素必须是一个数字,其值必须大于指定值。
@DecimalMin 被注解的元素必须是一个数字,其值必须小于指定值。
@DecimalMax 被注解的元素必须是一个数字,其值必须大于指定值。
@Size(min, max) 被注解的数组和集合型元素的长度是必须给定的范围之内
@Digits(integer, fraction) 要求字符串必须是数字型字符串,且整数部分有 interger 位,小数部分有 fraction 位。
@Past 要求必须是一个过去日期。用于 Date 和 Calendar
@Future 要求必须是一个未来日期。用于 Date 和 Calendar
@Pattern(regexp, flag) 要求字符串内容必须符合正则表达式的规则
@Valid 要求递归检查数组和容器中关联对象。

所有的这些注解都有 message 属性,用于设置错误提示信息(如果没有设置,则会有默认的错误提示信息)

# Hibernate Validator 的扩展注解

Hibernate Validator 实现了 JSR 303,它除了支持所有标准的校验注解外,还支持一些『额外』的注解:

注解 说明
@NotBlank 要求字符串必须不为 NULL,且执行 trim() 后必须为非空字符串
@Email 要求字符串内容必须符合邮箱格式。但是 null 会放过
@Length(min, max) 要求字符串的长度必须在指定范围内
@NotEmpty 备注解的字符串必须为非空
@Range(min, max) 检查数字是否介于 min 和 max 之间

# 使用 JSR 303

注意 使用验证框架时,请求处理方法的参数对象必须用 @Valid 注解修饰,并且处理方法要多出一个 BindingResult 参数对象。

@RequestMapping("...")
public ModelAndView demo(@Valid ..., BindingResult result) {
  ...;
}

BindingResult 参数对象中包含了验证结果,及其相关信息。

if (result.hasErrors()) {
	List<FieldError> list = result.getFieldErrors();

	for (FieldError error : list) {
		System.out.println(error.getField() + ", " + error.getDefaultMessage());
	}
}

更优雅的改进方案:结合全局异常处理,当 result.hasErrors() == true 时,在 Controller 中直接抛出异常,由 Controller 的异常处理类来解析 BindingResult 中的异常信息,并返回对应的错误信息给客户端。