分享

Spring输入验证与数据绑定

 BlazerOfIT 2012-03-09

Spring输入验证与数据绑定     

输入验证与数据绑定

 

实例目标:实现用户注册功能。

流程:

1. 提供一个界面供用户输入注册信息,下面是一个简化的注册界面,仅提供了用

户名和密码的设置

<!--[if !vml]--><!--[endif]-->

2. 如果用户注册信息有误,显示错误界面,要求用户检查输入后重新注册。

<!--[if !vml]--><!--[endif]-->

3. 注册成功,显示操作成功提示。

<!--[if !vml]--><!--[endif]-->

实例内容

<!--[if !supportLists]-->a)    <!--[endif]-->配置文件

首先,web.xml文件配置分发器如下:

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.4" xmlns="http://java./xml/ns/j2ee"

    xmlns:xsi="http://www./2001/XMLSchema-instance"

    xsi:schemaLocation="http://java./xml/ns/j2ee

    http://java./xml/ns/j2ee/web-app_2_4.xsd">

 

    <servlet>

       <servlet-name>Dispatcher</servlet-name>

       <servlet-class>

           org.springframework.web.servlet.DispatcherServlet

       </servlet-class>

       <init-param>

           <param-name>contextConfigLocation</param-name>

           <param-value>/WEB-INF/Config.xml</param-value>

       </init-param>

    </servlet>

    <servlet-mapping>

       <servlet-name>Dispatcher</servlet-name>

       <url-pattern>*.do</url-pattern>

    </servlet-mapping>

 

    <error-page>

       <exception-type>java.lang.Throwable</exception-type>

       <location>/WEB-INF/jsp/errorpage.jsp</location>

    </error-page>

 

    <error-page>

       <exception-type>500</exception-type>

       <location>/WEB-INF/jsp/errorpage.jsp</location>

    </error-page>

 

</web-app>

在这个实例中,我们选用JSTLView作为我们的表现层实现。对应的配置文件如下。

Config.xml:

<beans>

<bean id="viewResolver"

class="org.springframework.web.servlet.view.InternalRes

ourceViewResolver">

<property name="viewClass">

<value>

org.springframework.web.servlet.view.JstlView

</value>

</property>

<property name="prefix">

<value>/WEB-INF/view/</value>

</property>

<property name="suffix">

<value>.jsp</value>

</property>

</bean>

<bean id="RegisterValidator"

class="net.xiaxin.validator.RegisterValidator"/>

<bean id="RegisterAction"

class="net.xiaxin.action.RegisterAction">

<property name="commandClass">

<value>net.xiaxin.reqbean.RegisterInfo</value>

</property>

<property name="validator">

<ref local="RegisterValidator"/>

</property>

<property name="formView">

<value>register</value>

</property>

<property name="successView">

<value>RegisterSuccess</value>

</property>

</bean>

<!--Request Mapping -->

<bean id="urlMapping"

class="org.springframework.web.servlet.handler.SimpleUr

lHandlerMapping">

<property name="mappings">

<props>

<prop key="/register.do">RegisterAction</prop>

</props>

</property>

</bean>

</beans>

这个配置文件与篇首MVC介绍中所用实例大同小异。不同之处在于我们在这里引入了数

据验证配置节点:

配置了一个数据验证Bean: RegisterValidator

net.xiaxin.validator.RegisterValidator

为逻辑处理单元RegisterAction定义输入数据校验Bean

这里通过一个Bean引用,将RegisterValidator配置为本Action的数据校验

类。

指定本处理单元的显示界面。

formViewRegisterAction的父类SimpleFormController中定义的属

性,指定了本处理单元的显示界面。

这里即用户访问register.do时将显示的注册界面。

要注意的是,完成此界面后,我们必须通过“/register.do”访问注册界面,

而不是“/register.jsp”,因为我们必须首先借助Spring完成一系列初始

化工作(如创建对应的状态对象并与之关联)之后,register.jsp才能顺利执

行,否则我们会得到一个应用服务器内部错误。

指定成功返回界面。

successView同样是RegisterAction的父类SimpleFormController中定

义的属性,它指向成功返回界面。

b) 数据验证类

Spring中,所有的数据验证类都必须实现接口:

org.springframework.validation.Validator

Validator接口定义了两个方法:

boolean supports(Class clazz);

用于检查当前输入的数据类型是否符合本类的检验范围。Spring调用

Validator实现类时,首先会通过这个方法检查数据类型是_____否与此Validator

相匹配。

void validate(Object obj, Errors errors);

数据校验方法。Validator实现类通过实现这个方法,完成具体的数据校验逻辑。

RegisterValidator.java

public class RegisterValidator implements Validator {

public boolean supports(Class clazz) {

return RegisterInfo.class.isAssignableFrom(clazz);

}

public void validate(Object obj, Errors errors) {

RegisterInfo regInfo = (RegisterInfo) obj;

//检查注册用户名是否合法

if (regInfo.getUsername().length() < 4) {

errors.rejectValue("username",

"less4chars",

null,

"用户名长度必须大于等于4个字母!");

}

/*检查用户名是否已经存在

if (UserDAO.getUser(regInfo.getUsername()) != null) {

errors.rejectValue("username",

"existed",

null,

"用户已存在!");

}

*/

if (regInfo.getPassword1().length() < 6) {

errors.rejectValue("password1",

"less6chars",

null,

"密码长度必须大于等于6个字母");

}

if (!regInfo.getPassword2().equals(regInfo.getPassword1()))

{

errors.rejectValue("password2",

"notsame",

null,

"两次输入的密码不一致!");

}

}

}

RegisterInfo.class.isAssignableFrom方法用于判定参数类别,当传入

Class对象与当前类类别相同,或是当前类的父类(或当前类实现的接口)时返回真。这

里我们将其用于对校验对象的数据类型进行判定(这里的判定条件为:校验对象必须是

RegisterInfo类的实例)。

RegisterInfo regInfo = (RegisterInfo) obj;

将输入的数据对象转换为我们预定的数据类型。

通过rejectValue方法将错误信息加入Error列表,此错误信息将被页面捕获并

显示在错误提示界面上。

rejectVlaue方法有4个参数:

1Error Code

显示错误时,将根据错误代码识别错误信息类型。

2Message Key

上 面关于ApplicationContext 的国际化支持时, 我们曾经谈及

MessageSource的使用,这里我们可以通过引入MessageSource实现提示信息

的参数化,此时,本参数将用作.properties文件中的消息索引。

3Error Argument

如果提示信息中需要包含动态信息,则可通过此参数传递需要的动态信息对象。具

体参见ApplicationContext中关于国际化实现的描述。

4Default Message

如果在当前MessageSource中没有发现Message Key对应的信息数据,则以此

默认值返回。

这里我们暂时尚未考虑国际化支持,所有的信息都将通过Default Message

回。关于国际化支持请参见稍后章节。

另外rejectValue还有另外几个简化版本,可根据情况选用。

其中RegisterInfo类定义如下:

public class RegisterInfo {

    private String username;

    private String password1;

    private String password2;

 

    public String getPassword1() {

       return password1;

    }

 

    public void setPassword1(String password1) {

       this.password1 = password1;

    }

 

    public String getPassword2() {

       return password2;

    }

 

    public void setPassword2(String password2) {

       this.password2 = password2;

    }

 

    public String getUsername() {

       return username;

    }

 

    public void setUsername(String username) {

       this.username = username;

    }

}

c) 注册界面

register.jsp提供了注册操作界面。它同时提供了最初的注册界面,当输入参数非

法时,同时也会显示错误信息,提示用户检查输入。

register.jsp:

<!-- 页面中使用了JSTL Core taglib Spring lib-->

<%@ taglib prefix="c" uri="http://java./jstl/core_rt" %>

<%@ taglib prefix="spring" uri="http://www./tags" %>

<!-- 设定页面编译时采用gb2312编码,同时指定浏览器显示时采取gb2312解码-->

<%@ page pageEncoding="gb2312"

contentType="text/html;charset=gb2312"%>

<html>

<head>

<title>用户注册</title>

</head>

<body style="text-align: center">

<form method="POST" action="/register.do">

<spring:bind path="command.*">

<font color="#FF0000">

<c:forEach

items="${status.errorMessages}"

var="error">

错误: <c:out value="${error}"/><br>

</c:forEach>

</font>

</spring:bind>

<table border="0" width="450" height="101"

cellspacing="0" cellpadding="0" >

<tr>

<td height="27" width="408" colspan="2">

<p align="center"><b>用户注册</b></td>

</tr>

<tr>

<td height="23" width="104">用户名:</td>

<td height="23" width="450">

<spring:bind path="command.username">

<input

type="text"

value="<c:out value="${status.value}"/>"

name="<c:out value="${status.expression}"/>"

> 

(必须大于等于4个字符)

<br>

<c:if test="${status.error}">

<font color="#FF0000">

错误:

<c:forEach

items="${status.errorMessages}"

var="error">

<c:out value="${error}"/>

</c:forEach>

</font>

</c:if>

</spring:bind>

</td>

</td>

</tr>

<tr>

<td height="23" width="104">密码:</td>

<td height="23" width="450">

<spring:bind path="command.password1">

<input

type="password"

value="<c:out value="${status.value}"/>"

name="<c:out value="${status.expression}"/>"

> 

(必须大于等于6个字符)

<br>

<c:if test="${status.error}">

<font color="#FF0000">

错误:

<c:forEach

items="${status.errorMessages}"

var="error">

<c:out value="${error}"/>

</c:forEach>

</font>

</c:if>

</spring:bind>

</td>

</tr>

<tr>

<td height="23" width="104">重复密码:</td>

<td height="23" width="450">

<spring:bind path="command.password2">

<input

type="password"

value="<c:out value="${status.value}"/>"

name="<c:out value="${status.expression}"/>"

> 

<br>

<c:if test="${status.error}">

<font color="#FF0000">

错误:

<c:forEach

items="${status.errorMessages}"

var="error">

<c:out value="${error}"/>

</c:forEach>

</font>

</c:if>

</spring:bind>

</td>

</tr>

</table>

<p>

<input type="submit" value="提交" name="B1">

<input type="reset" value="重置" name="B2">

</p>

</form>

</body>

</html>

页面起始部分指定了页面中引入的taglib和页面编码方式,实际开发时应该将其独立到一个单

独的jsp文件中,并在各个jsp文件中include便于统一维护。

页面中关键所在,也就是<spring:bind> 标记的使用:

<spring:bind path="command.*">

<font color="#FF0000">

<c:forEach

items="${status.errorMessages}"

var="error">

错误: <c:out value="${error}"/><br>

</c:forEach>

</font>

</spring:bind>

spring.bind标记通过path参数与CommandClass对象相绑定。之后我们就可以对绑定的

CommandClass对象的状态信息进行访问。上面的片断中,我们通过通配符“*”将当前

spring.bind语义与command对象的所有属性相绑定,用于集中的错误信息显示,对应最终提

示界面中的(蓝框标注部分):

<!--[if !vml]--><!--[endif]-->

而在下面每个输入框下方,我们也提供了对应的错误提示,此时我们绑定到了特定的command

属性,如"command.username"

这里的"command"Spring中的默认CommandClass名称,用于引用当前页面对应的

CommandClass实例(当前语境下,也就是net.xiaxin.reqbean.RegisterInfo)。我们

也可以配置CommandClass引用名称,在Config.xmlRegisterAction配置中增加

CommandName配置,如下:

<bean id="RegisterAction"

class="net.xiaxin.action.RegisterAction">

<property name="commandName">

<value>RegisterInfo</value>

</property>

………

</bean>

之后我们就可以在页面中使用“RegisterInfo”替代现在的“command”对数据对象进

行引用。

(为了保持前后一致,下面我们仍旧以“command”为例)

绑定到username属性的<spring:bind>标记:

<spring:bind path="command.username">

<input

type="text"

value="<c:out value="${status.value}"/>"

name="<c:out value="${status.expression}"/>"

> 

(必须大于等于4个字符)

<br>

<c:if test="${status.error}">

<font color="#FF0000">

错误:

<c:forEach

items="${status.errorMessages}"

var="error">

<c:out value="${error}"/>

</c:forEach>

</font>

</c:if>

</spring:bind>

可以看到,<spring:bind>语义内,可以通过${status.*}访问对应的状态属性。

${status.*} 对应的实际是类

org.springframework.web.servlet.support.BindStatus

BindStatus类提供了与当前CommandClass对象绑定的状态信息,如:

${status.errorMessages}对应绑定对象属性的错误信息。

${status.expression}对应绑定对象属性的名称。

${status.value}对应绑定对象属性当前值。

具体描述可参见BindStatus类的Java Doc 文档。

下面是RegisterAction.java和成功返回界面RegisterSuccess.jsp,出于演示目的,这

两个文件都非常简单:

RegisterAction.java:

public class RegisterAction extends SimpleFormController {

protected ModelAndView onSubmit(Object cmd, BindException ex)

throws Exception {

Map rsMap = new HashMap();

rsMap.put("logininfo",cmd);

return new ModelAndView(this.getSuccessView(),rsMap);

}

}

RegisterSuccess.jsp:

<%@ taglib prefix="c" uri="http://java./jstl/core_rt" %>

<%@ page pageEncoding="gb2312"

contentType="text/html;charset=gb2312"%>

<html>

<body>

<p align="center">

<c:out value="${logininfo.username}"/> 注册成功!

</p>

</body>

</html>

可以看到,结合JSTL Core TaglibSpring Taglib,我们实现了一个拥有数据校验

功能的注册界面。界面显示、数据校验、逻辑处理三大模块被清晰隔离互不干扰,相对传统的

jsp解决方案。系统的可维护性得到了大大提升。

不过,我们还必须注意到,spring:bind标记对界面代码的侵入性较大,可以看到页面中

混杂了大量的Tag调用,这将对界面的修改和维护带来一定的困难。相对WebWork2而言,

Spring在这方面还是显得有些繁琐。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多