技术开发 频道

Spring MVC的表单控制器

表单数据校验

    当UserRegisterController调用BbtForum#registerUser()方法注册用户时,确保User对象数据的合法性是非常重要的,你不希望用户的Email地址是非法的,用户名不应和已经用户名相同。

    org.springframework.validation.Validator接口为Spring MVC提供了数据合法性校验功能,该接口有两个方法,说明如下: boolean supports(Class clazz):判断校验器是否支持指定的目标对象,每一个校验器负责对一个表单类的对象进行检验;
void validate(Object target, Errors errors):对target对象进行合法性校验,通过Errors返回校验错误的结果。

    下面,我们编写一个负责对User对象进行数据合法性校验的校验器,请看以下的代码:
代码清单 4 UserValidator:校验User对象值合法性

package com.baobaotao.domain.UserValidator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
public class UserValidator implements Validator {
private static final Pattern EMAIL_PATTERN = Pattern ①合法Email正则表达式
.compile("(?:\\w[-._\\w]*\\w@\\w[-._\\w]*\\w\\.\\w{2,3}$)");
public boolean supports(Class clazz) { ②该校验器支持的目标类
return clazz.equals(User.class);
}
public void validate(Object target, Errors errors) { ③对目标类对象进行校验,错误记录在errors中
User user = (User) target; ③-1 造型为User对象
③-2 通过Spring提供的校验工具类进行简单的规则校验
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName",
"required.username", "用户名必须填写");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password",
"required.password", "密码不能为空");
validateEmail(user.getEmail(), errors); ③-3 校验Email格式
}

private void validateEmail(String email, Errors errors) {④Email合法性校验
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email",
"required.email", "Email不能为空");
Matcher m = EMAIL_PATTERN.matcher(email); ④-1 通过正则表达式校验Email格式
if (!m.matches()) {
errors.rejectValue("email", "invalid.email", "Email格式非法");
}
}
}

    在②处,我们声明该校验器支持的表单对象为User类,如果错误地将UserValidator用于其它对象校验,Spring MVC就会根据supports()方法驳回操作。

    对于一般的空值校验来说,直接使用Spring提供的ValidationUtils校验工具类是最简单的办法(如③-2所示)。ValidationUtils的rejectIfEmptyOrWhitespace()、rejectIfEmpty()以及Errors的reject()、rejectValue()方法都拥有多个用于描述错误的入参,通过下图进行说明:
 

                                                                 图 2 检验工具方法入参

1)对应字段:表示该错误是对应表单对象的哪一个字段,Spring MVC的错误标签可以通过path属性访问该字段错误消息;

2)错误代码:表示该错误对应资源文件中的键名,Spring MVC的错误标签可以据此获取资源文件中的对应消息。如果希望实现错误消息的国际化,你就必须通过错误代码指定错误消息;

3)默认消息:当资源文件没有对应的错误代码时,使用默认消息作为错误消息。
我们“惊讶地”发现入参列表并没有包括需要校验的目标表单对象,那如何对目标表单对象实施校验呢?原来目标对象已经包含在errors对象中,在校验方法内部会从errors中取得目标方法并施加校验。

在④处,我们通过正则表达式对Email格式进行校验。我们直接使用JDK 1.4 java.util.regex包中提供的正则表达式工具类完成校验的工作。由于Email模式是固定的,为了提高性能,我们在①处用final static的方式定义了一个Email合法模式的Pattern对象。
编写好UserValidator,我们需要将其装配到UserRegisterController控制器中,其配置如下所示:

<bean name="/registerUser.html" class="com.baobaotao.web.user.UserRegisterController">
<property name="bbtForum" ref="bbtForum" />
<property name="formView" value="register" />
<property name="successView" value="registerSuccess" />
<property name="validator"> ①装配校验器
<bean class="com.baobaotao.domain.UserValidator" />
</property>
</bean> 

    在①处我们通过validator指定了一个对User表单对象进行校验的校验器,如果你有多个校验器类(很少见),可以通过validators属性进行指定。

    我们通过UserValidator可以很好地完成User对象属性值的格式检查,可是仔细想想是否还存在遗漏呢?也许你已经指出:userName不能和数据库中已有用户名重复!你当然可以在UserValidator中通过注入业务对象完成userName重复性的校验,但对于这种需要通过业务对象完成的校验操作,一种更好的方法是通过覆盖控制器的onBindAndValidate()方法,直接在控制器中提供检验。这带来了一个好处,UserValidator无需和业务对象打交道,而UserRegisterController本身已经拥有了业务对象的引用,所以调用业务对象执行校验非常方便。下面的代码展示了UserRegisterController中onBindAndValidate()的内容:
代码清单 5 UserRegisterController#onBindAndValidate()通过业务对象完成校验

package com.baobaotao.web.user;

public class UserRegisterController extends SimpleFormController {

@Override
protected void onBindAndValidate(HttpServletRequest request,
Object command, BindException errors) throws Exception {
User user = (User) command;
if (bbtForum.isExsitUserName(user.getUserName())) {①通过业务对象完成检验
errors.rejectValue("userName", "exists.userName", "用户名已经存在");
}
}
}

    我们在UserRegisterController覆盖了父类的onBindAndValidate()方法,通过BbtForum业务对象的方法判断userName是否已经被占用,如果已经被占用,将相应错误添加到errors对象中。

0
相关文章