MVC 表单验证

用户注册页面: 名称: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来保存数据。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值