Struts in Action 中文版 Lastest Revised: July 18, 2005
Translated By: Eric Liu(铁手)
shqlau@hotmail.com(MSN) 第 330 页
http://www.blogjava.net/steelhand
12.
用户输入校验
David Winterfeldt 和Ted Husted合著
本章内容
理解校验数据的需要
配置和使用 Commons 校验器
使用多页面和本地化校验
编写自己的校验器
Struts in Action 中文版 Lastest Revised: July 18, 2005
Translated By: Eric Liu(铁手)
shqlau@hotmail.com(MSN) 第 331 页
http://www.blogjava.net/steelhand
Us: Programming today is a race between software engineers
striving to build bigger and better idiot-proof programs, and the
Universe trying to produce bigger and better idiots. So far, the
Universe is winning.
—Rich Cook
Them: I never know how much of what I say is true.
—Bette Midler
12.1. 看到时我就认识它
大多数应用都需要从用户处收集数据。这些输入可能来自于非常灵活的文本字段或者GUI
元素,比如菜单列表,单选按钮,或者复选框。在实践中,用户的输入并不是总是有意义的。
一些菜单选项可能是互斥的。电话号码可能还缺少一位数字。在数字字段中可能输入了字母。
而字母字段中又输入了数字。这是因为数据输入表单并不清楚,或者因为用户并没有注意。
但是,在其发生的很多时候,是具有很大的规律性的。
没有什么比应用输出了莫名其妙的垃圾结果更能令用户丧气,即使是对那些输入了垃圾数据
的用户而言。一个谨慎的应用应该细察所有的输入,防止所有可预知的错误,以及保护用户
自己避免犯错。而且,毕竟, 如果它们确实发生了,我们也还要修正它的。
12.1.1. 不能拒绝的输入
在一个常规应用中,数据输入控件可以简单地拒绝不正确的输入,但是要它们是以模态的方
式进行却显得很奢侈。
定义
当一个用户接口元素收集一个应用的所有输入时,我们称它为模态的。其
它元素在它消失之前不能被访问。为了继续,用户必须完成该对话框,或
者关闭应用。大多数用户接口都是非模态的。
天生就是非模态的Web应用就少有选择。缺省地,浏览器显示的HTML元素将接受输入到它
们之中的任何东西。一个元素没有能力知道在表单输入了什么。我们可以用JavaScript来做
一些技巧性处理,但是并没有谁能保证用户将浏览器的JavaScript支持选项打开。
当然,我们可以在数据达到业务层时校验它们。(关于应用层和业务对象,参见第2章) 许多
业务逻辑对象确实具有一些内置的校验,但是大多数业务对象在接收数据之前并不检查它
们。业务层方法都趋向于信任数据的创建者。它们天真地期望对象能够被提供以合理的数据,
而自己只是做自己被赋予的任务而已。即使业务对象再悲观一些,通常它们能做的所有事情
就是抛出一个异常。对于业务对象来说,显示一个对话框让用户纠正输入错误的数据并不是
它们的职责。
当然,在上下文中校验数据却是业务对象的职责。让我们看看一些例子,例如,输入的用户
名称和密码是否匹配。但是仍然有一些有目的校验规则可以在数据被传输到业务层之前对其
进行校验。在一个分布式应用中,业务对象可能会驻留在远程机器上,这样创建往复的解决
输入错误问题的方式的代价就显得比较高昂。
Struts in Action 中文版 Lastest Revised: July 18, 2005
Translated By: Eric Liu(铁手)
shqlau@hotmail.com(MSN) 第 332 页
http://www.blogjava.net/steelhand
12.1.2. Web层校验
在现实生活中,通常由web应用框架来提供有目的的校验方法,从而窄化模型和视图之前的
距离。在一个非模态的分布式环境中,我们需要能够进行下列事项的校验方法:
要求特定的字段具有值
确认输入的值是否是期望的格式或者出于某个范围之内
一次性检查整个表单并返回一个消息列表
比较字段之间的值
返回原始输入以便纠正
需要时,显示本地化信息
如果JavaScript 被禁止,执行服务器端校验
还有两个其它的重要的特点是,松散耦合和可选的客户端校验。
松散耦合
在实际情况下,输入需要被控制器校验,但是业务校验是紧密结合到业务层的。这意味着校
验规则应该与标记或者Java代码中单独分开存储,以便它们能够在不改变其它源代码的情况
下被重新评审和修改。保证校验规则的松散耦合使得保持校验和业务需求的同步更加容易。
定义
耦合(coupling )程度意味着两个组件之间的连接强度。耦合是内聚的
互补。内聚(cohesion)描述的是一个组件的内部内容彼此之间的相关
强度。我们的目标是要创建具有内部完整性(强内聚)的和与其他组件具有
更小的、直接的,可见的,和灵活的关系(松散耦合)的组件。[McConnell]
某些校验规则可能也需要本地化。当添加了对一个新的场所的支持时,我们应该能够象更新
资源束一样容易地更新校验规则。
虽然校验规则能够为表现层提供方便,但是要认识到它们其实是属于业务层。
校验规则也不应该和表现源代码相混合。
客户端校验
客户端校验天生是不安全的。可以很容易地欺骗一个正在提交的web 页面并且绕过原始页
面中的任何脚本。尽管我们不能完全依赖于客户端 JavaScript 校验,但它还是有用的。 其
优点是对用户的立即反馈,避免了一次服务器往返,节省了时间和带宽。所以,理想情况是,
基于同一套规则产生JavaScript 和 服务器端校验。当JavaScript 激活时,输入可以在提交之
前在得到客户端校验。如果没有激活,输入仍然在服务器端进行校验以确保没有任何错误。
12.1.3. 校验器的地位
使用Jakarta Commons Validator [ASF, Validator] 可以带来以下结果:
校验器是一个符合这些需求---或者更多,的框架组件
校验器通过一个能够产生针对表单字段的校验规则的
XML文件进行配置
规则也是通过XML配置的校验器定义的
针对基本类型,比如日期和整数的校验器,已经内置提供。如果需要,你可以创建
你自己的校验器
正则表达式可以用于基于模式的校验,比如邮政编码和电话号码
支持多页面和本地化校验,所以你可以用任何语言编写wizard。
Struts in Action 中文版 Lastest Revised: July 18, 2005
Translated By: Eric Liu(铁手)
shqlau@hotmail.com(MSN) 第 333 页
http://www.blogjava.net/steelhand
定义
正则表达式(regular expression
)
是一个用来使字符创匹配某个模式的
公司。正则表达式经常用于许多
Unix 命令行和编程工具中。关于正则
表达式的详细信息,参见 Stephen Ramsay 的 “Using Regular
Expressions” web 页面。[Ramsay]
在你的应用中使用Jakarta Commons Validator有诸多好处:
优化资源的使用:当允许时提供 JavaScript 校验,并且服务器端校验也是可以保
证的;
单一维护点:客户端和服务器端校验都来自同一配置产生;
可扩展性:定制校验可以通过正则表达式或者在Java 代码中产生;
可维护性:它和应用之间是松散耦合的,并且可以在不修改任何代码的情况下进行
维护;
本地化:校验可以进在需要时和需要的地方才进行定义;
与Struts的集成,默认情况下,校验会共享Struts消息资源束。本地化文本可以集中
管理并可重用;
服务器端校验的容易部署性:为了使用服务器端 校验,你的Struts ActionForm 可
以简单扩展ValidatorForm 或者ValidatorActionForm 类。剩下的都是自动的。
客户端校验的容易部署性:为了使用客户端校验,你只需要添加一个JSP 标签就可
以产生校验脚本,并且使用该脚本来提交表单;
容易配置:校验器使用
XML 文件来进行配置,就象web 应用部署描述符合Struts
配置一样。
当然,但是,它也有一些缺点:
非模态的客户端校验:产生的JavaScript 是非模态的;直到表单被提交之前它并不
参与;
依赖性:校验和字段和ActionForm 属性是分离的。页面标记,ActionForm,以及
校验器和Struts 配置文件之间必须保持同步;
缺乏数据转换和变换:包并未提供数据转换和变换功能。如需要,转换和变换必须
自己单独编程。
请注意将Jakarta Commons Validator应用在你的应用中并不是万能灵药。某些校验只可能在
服务器断进行。如果失败,错误消息可以根据情况显示与JavaScript 消息不同的内容。接口
的不一致会使用户混淆。
定义
数据转换(Convertion)是将一种数据类型转换为另一种类型,比方说
从 String 到 Integer。数据变换(Transformation)则是数据内部格式的变
化,比如在一个字符串中添加一个标点,或者在其被保存之前去除一个
不想要的标点。本地化需要将数据变换成显示格式。
在这一章,我们将向你展示如何在你的应用中最好地使用Commons Validator框架。我们将
涉及到校验器的总体设计,并给出一个简单的例子。然后我们会随同经常需要的技术逐个审
视校验器的每一个组件,比如覆写缺省消息,取消校验,使用多页面工作流,校验集合,等
等。
Struts in Action 中文版 Lastest Revised: July 18, 2005
Translated By: Eric Liu(铁手)
shqlau@hotmail.com(MSN) 第 334 页
http://www.blogjava.net/steelhand
要强调的是,有目的的,输入输入校验不是一个综合性的方案。不用访问模型层就可以发现
许多种错误。我们可以看看用户名和口令在长度和组成方面是否符合业务需求。但是如果用
户名称和口令是有效的,我们就需要连接到业务层并和数据数据通信。但是,通过在实际请
求之前检查数据是否可能有效,我们可以消除不必要的数据访问事务,这对谁都有好处。
NOTE
你可能想知道 “那我将使用 Struts 框架来构建我的应用还是 Struts 校验
器框架呢?” 实际上,是两者。
大多数应用都使用多个框架组件来构建,包括某些团队自产的框架。Struts
构建在 Sun 的 Java J2SE 框架之上。同时,Struts 校验器构建在 Struts 框
架之上。所以,在你的应用使用多个包中的多个类,它可能也使用了多个
框架。关于使用框架架构的信息,参见第 2 章。
第4章我们讨论了Struts 1.1中校验器的设置。这一章是在应用中具体使用校验器的开发人员
指南。
12.2. Struts 校验器概述
我们来看看Struts 校验器是如何同其他组件交互来根据同一套校验规则来提供服务器端和
客户端校验的。
一旦校验器的各个部分通力合作,你会惊讶校验数据居然是这么的容易。表 12.1 列出了组
成Struts 校验器的各个组成部分。
起初, Commons Validator是作为Struts 框架的一个扩展创建的。但是自从它也被用于框架
之外后,开发者就将它贡献为Jakarta 的另一个子项目Commons下的一个组件。
表格 12.1 主要的 Struts 校验器组件
组件 说明
校验器 处理原生和其它通用类型。基本校验器包括 required,mask (匹
配正则表达式),minLength,maxLength,range,native types,
date,email,和 creditCard。也可以定义定制 (或者插件) 校
验器。
资源束 提供(本地化的)标注和消息。默认与 Struts 共享消息资源。
XML 配置文件 根据需要定义针对字段的表单集和校验。校验器可以在一个单
独的文件中定义。
JSP 标签 对给定的表单或 Action 路径产生 JavaScript 校验器 。