您的位置:首页 > 编程语言 > Java开发

spring 3.1 Validator 校验机制解析

2012-01-19 14:09 232 查看
最近在学习Spring3.1,基于注解的MVC, 使用过程中发现,开始的时候很不喜欢那个JSR 303 推荐的校验机制,原因很简单就是要记很多Annotation, 每个校验类型一个annotation,而且也不喜欢那个正则式的校验方式,还是喜欢独立的一个校验方法的方式,像以前的struts里的那个对form的校验,或者spring里的校验接口那种的。但是找了老半天,发现spring3.1没有提供太多的学习资料和使用介绍。

自己在学习API和reference document的基础上,找到了这两种校验方式。在此总结下,供大家参考。

Spring 基于注释的校验机制:

1) 支持Spring框架定义的Validator接口定义的校验。

2)支持JSR303 Bean Validation定义的校验规范。

下面使用一个用户注册的例子来就二者的使用进行讲解。

平台: Spring 3.1.0

用户注册页面: 名称:user.jsp

注册用户包含三项信息: 用户名,密码,邮箱。

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="sf" 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>User Register Page</title>
<style type="text/css">
.error{
color: red;
}
</style>
</head>

<body>
<%--
这里指定页面绑定的对象 modelAttribute. 之前很困惑,
为什么<form>上最重要的 <form action="someAction.do">属性没了呢?
后来发现,其实在controller中的方法以及指定了地址到method的对应关系,
<form>里的action属性就可以退休了。
--%>
<sf:form method="post" modelAttribute="user">
<p>用户注册页面:</p>
<table width="60%" align="center">
<colgroup>
<col width="10%" align="right" />
<col />
</colgroup>
<tr>
<th>用户名:</th>
<td>
<sf:input path="userName" />
<small>length of userName is not more than 20.</small><br />
<%-- 显示关于userName属性相关的错误信息。 --%>
<sf:errors path="userName" cssClass="error"/>
</td>
</tr>
<tr>
<th>密码:</th>
<td>
<sf:password path="password" />
<small>length of password is not less than 6.</small><br />
<sf:errors path="password" cssClass="error" />
</td>
</tr>
<tr>
<th>邮箱:</th>
<td>
<sf:input path="email"/>
<small>format should confirm to general standard.</small><br />
<sf:errors path="email" cssClass="error" />
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="注册" />
</td>
</tr>
</table>
</sf:form>
</body>
</html>
这里没有使用前段的JavaScript校验,目的是为了了解和熟悉使用后台的校验机制。

与前台页面相关联的对象: User, 包含userName, password, email等属性。

public class User {
private String userName;

private String password;

private String email;

public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}

public String toString(){
StringBuilder sb = new StringBuilder();

sb.append(getClass()).append("[")
.append("userName=").append(userName).append(", ")
.append("password=").append(password).append(", ")
.append("email=").append(email).append("]");

return sb.toString();
}

}


本人比较偏好Spring框架的Validator方式校验,所以先说第一种方式。



校验方式一: Spring Validator



1)Validator接口的实现:

Spring框架的Validator接口定义,

package org.springframework.validation;

public interface Validator {

boolean supports(Class<?> clazz);

void validate(Object target, Errors errors);

}


要使用它进行校验必须实现该接口。实现Validator接口的代码如下:

package org.study.validation.validator;

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import org.study.domain.User;

public class UserValidator implements Validator {

@Override
public boolean supports(Class<?> clazz) {
return clazz.equals(User.class);
}

@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, "userName", "user.userName.required", "用户名不能为空");
ValidationUtils.rejectIfEmpty(errors, "password", "user.password.required", "密码不能为空");
ValidationUtils.rejectIfEmpty(errors, "email", "user.email.required", "邮箱不能为空");
User user = (User)target;
int length = user.getUserName().length();
if(length>20){
errors.rejectValue("userName", "user.userName.too_long", "用户名不能超过{20}个字符");
}
length = user.getPassword().length();
if(length <6){
errors.rejectValue("password", "user.password.too_short", "密码太短,不能少于{6}个字符");
}else if(length>20){
errors.rejectValue("password", "user.password.too_long", "密码太长,不能长于{20}个字符");
}
int index = user.getEmail().indexOf("@");
if(index == -1){
errors.rejectValue("email", "user.email.invalid_email", "邮箱格式错误");
}
}

}


2) 设置Validator,并触发校验。

在我们的Controller中需要使用父类已有的方法来为DataBinder对象指定Validator, protected initBinder(WebDataBinder binder); 代码如下:

@InitBinder
protected void initBinder(WebDataBinder binder){
binder.setValidator(new UserValidator());
}


为binder对象指定好Validator校验对象后,下面一步的就是在需要校验的时候触发validate方法,该触发步骤是通过 @Validated 注解(该注解是Spring框架定义的)实现的。

/**
* 处理提交的用户注册信息。
* @param model
* @return
*/
@RequestMapping (method = RequestMethod.POST)
public String doRegister(@Validated User user, BindingResult result){
if(logger.isDebugEnabled()){
logger.debug("process url[/user], method[post] in "+getClass());
}
//校验没有通过
if(result.hasErrors()){
return "user";
}

if(user != null){
userService.saveUser(user);
}

return "user";
}


至此,从页面提交的User对象可以通过我们实现的UserValidator类来校验了,校验的结果信息存入BindingResult result对象中。在前台页面可以使用spring-form的标签<sf:errors path="*" />来显示。

校验方式二: JSR303 Bean Validation

在Spring3.1中增加的了对JSR303 Bean Validation规范的支持,不仅可以对Spring的 MVC进行校验,而且也可以对Hibernate的存储对象进行校验。是一个通用的校验框架。

环境准备:

A) 导入Hibernate-Validator

要使用JSR303 校验框架, 需要加入框架的具体实现Hibernate-Validator, 在soureforge上下载最新的Hibernate-Validator, 当前版本为4.2.0 Final版。

在/WEB-INF/lib中导入 hibernate-validator-4.2.0.Final.jar, hibernate-validator-annotation-processor-4.2.0.Final.jar, 导入它的lib/required目录下内容slf4j-api-1.6.1.jar, validation-api-1.0.0.GA.jar;

B) 配置Spring对JSR 303 的支持。

在你的 <servletName>-servlet.xml配置文件中,使用标签:

<mvc:annotation-driven />
配置对JSR303的支持,包括制动查找Hibernate-Validator的实现等工作。

1) 校验属性的Constraints的设定

该步骤就是对要校验的对象的属性,使用已经定义的Constraints对需要校验的属性进行约束。在JSR303中已经定义的Constraint如下:

表 1. Bean Validation 规范内嵌的约束注解定义
约束注解名称 	约束注解说明
@Null 	        验证对象是否为空
@NotNull 	验证对象是否为非空
@AssertTrue 	验证 Boolean 对象是否为 true
@AssertFalse 	验证 Boolean 对象是否为 false
@Min 	        验证 Number 和 String 对象是否大等于指定的值
@Max 	        验证 Number 和 String 对象是否小等于指定的值
@DecimalMin 	验证 Number 和 String 对象是否大等于指定的值,小数存在精度
@DecimalMax 	验证 Number 和 String 对象是否小等于指定的值,小数存在精度
@Size 	        验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Digits 	验证 Number 和 String 的构成是否合法
@Past 	        验证 Date 和 Calendar 对象是否在当前时间之前
@Future 	验证 Date 和 Calendar 对象是否在当前时间之后
@Pattern 	验证 String 对象是否符合正则表达式的规则


通过上述Constraint约束后的User对象如下:

package org.study.domain;

import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

import org.study.validation.annotation.NotEmpty;

public class User {

@Size (min=3, max=20, message="用户名长度只能在3-20之间")
private String userName;

@Size (min=6, max=20, message="密码长度只能在6-20之间")
private String password;

@Pattern (regexp="[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}", message="邮件格式错误")
private String email;

public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}

public String toString(){
StringBuilder sb = new StringBuilder();

sb.append(getClass()).append("[")
.append("userName=").append(userName).append(", ")
.append("password=").append(password).append(", ")
.append("email=").append(email).append("]");

return sb.toString();
}

}


2) Validate的触发

在需要校验的对象前增加 @Valid 注解 (该注解位于javax.validation包中)来触发校验。示例如下:

/**
* 处理提交的用户注册信息。
* @param model
* @return
*/
@RequestMapping (method = RequestMethod.POST)
public String doRegister(@Valid User user, BindingResult result){
if(logger.isDebugEnabled()){
logger.debug("process url[/user], method[post] in "+getClass());
}
//校验没有通过
if(result.hasErrors()){
return "user";
}

if(user != null){
userService.saveUser(user);
}

return "user";
}


这样就可以完成针对输入数据User对象的校验了, 校验结果任然保存在BindingResult对象中。

注: 想要往页面传数据的时候,不要调用result.getModel().put(key, value); 这样做将不起作用,因为getModel()方法每次都是生成一个新的,保存的东西就会丢失。

最好在响应方法中加一个: Map<String, Object> map来保存数据。


最后对参考文献中作者们的贡献表示感谢。

参考文献:

1、 Bean Validation 技术规范特性概述

2、JSR303 Bean Validation

3、Spring In Action 3th, Spring MVC, chapter 7

4、spring-framework-reference.pdf Validation, Chapter 6

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: