前言:本篇主要介绍SpringMVC的数据绑定流程中数据校验的相关概念与用法。
本篇文章重点关注以下问题:
- JSR303校验框架
- Spring内置的验证约束注解
1. JSR303校验框架
JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在 JavaEE 6.0 中。JSR 303 通过在 Bean 属性上标注类似于 @NotNull、@Max等标准的注解指定校验规则,并通过标准的验证接口对 Bean 进行验证。
JSR303 校验框架注解类:
- @NotNull 注解元素必须是非空
- @Null 注解元素必须是空
- @Digits 验证数字构成是否合法
- @Future 验证是否在当前系统时间之后
- @Past 验证是否在当前系统时间之前
- @Max 验证值是否小于等于最大指定整数值
- @Min 验证值是否大于等于最小指定整数值
- @Pattern 验证字符串是否匹配指定的正则表达式
- @Size 验证元素大小是否在指定范围内
- @DecimalMax 验证值是否小于等于最大指定小数值
- @DecimalMin 验证值是否大于等于最小指定小数值
- @AssertTrue 被注释的元素必须为true
- @AssertFalse 被注释的元素必须为false
Hibernate Validator 是 JSR 303 的一个参考实现,除支持所有标准的校验注解外,它还支持以下的扩展注解
HibernateValidator 扩展
- @Email 被注释的元素必须是电子邮箱地址
- @Length 被注释的字符串的大小必须在指定的范围内
- @NotEmpty 被注释的字符串的必须非空
- @Range 被注释的元素必须在合适的范围内
2. SpringMVC数据校验框架
Spring 4.0 拥有自己独立的数据校验框架,同时支持 JSR303 标准的校验框架。Spring 在进行数据绑定时,可同时调用校验框架完成数据校验工作。在 Spring MVC 中,可直接通过注解驱动的方式进行数据校验。
Spring 本身并没有提供 JSR303 的实现,所以必须将JSR303 的实现者的 jar 包放到类路径下,Hibernate Validator 是经常被使用的JSR303校验框架。
<mvc:annotation-driven/> 会默认装配好一个LocalValidatorFactoryBean,通过在处理方法的入参上标注 @valid 注解即可让 Spring MVC 在完成数据绑定后执行数据校验的工作。在已经标注了 JSR303 注解的表单/命令对象前标注一个@Valid,Spring MVC 框架在将请求参数绑定到该入参对象后,就会调用校验框架根据注解声明的校验规则实施校验。Spring MVC 是通过对处理方法签名的规约来保存校验结果的前一个表单/命令对象的校验结果保存到随后的入参中,这个保存校验结果的入参必须是 BindingResult 或Errors 类型。
需要声明的是,需校验的 Bean 对象和其绑定结果对象或错误对象时成对出现的,它们之间不允许声明其他的入参。

在表单/命令对象类的属性中标注校验注解,在处理方法对应的入参前添加 @Valid,Spring MVC 就会实施校验并将校验结果保存在被校验入参对象之后的 BindingResult 或Errors入参中。
常用的方法有:
- FieldError getFieldError(String field)
- List<FieldError> getFieldErrors()
- Object getFieldValue(String field)
- Int getErrorCount()
补充说明:
Spring MVC 除了会将表单/命令对象的校验结果保存到对应的 BindingResult或 Errors 对象中外,还会将所有校验结果保存到“隐含模型”,即使处理方法的签名中没有对应于表单/命令对象的结果入参,校验结果也会保存在 “隐含对象” 中。隐含模型中的所有数据最终将通过HttpServletRequest的属性列表暴露给JSP 视图对象,因此在 JSP 中可以获取错误信息,在 JSP 页面上可通过 <form:errors path=“userName”> 显示错误消息。
3. 示例演示
在后台接收实体类中进行如下配置,详细代码可见附件:
@NotEmpty
private String username;
@Past
private Date birth;
@Email
private String email;
如果配置了<mvc:annotation-driven/>,会默认支持上述校验注解。用起来比较简单,
测试结果如下:
代码下载来源:http://super-wangj.iteye.com/blog/2388430