Web 表单验证是开发 Web 应用程序的一个不可缺少的部分。Apache Software Foundation 开发的 Jakarta 通用验证器(Jakarta Commons Validator)提供了一个分离验证逻辑与应用程序业务逻辑的框架。您可以协同或不协同使用 Struts 与 Commons Validator。Struts 发行版附带的通用验证器(Commons Validator)通常称为 Struts 验证器(Struts Validator)。
Writing a Simple Struts Application using WebSphere Studio V5一文介绍了未使用 Struts 验证器的 Struts 验证。 ActionForm 中的 validate() 方法是通过程序化的验证逻辑实现的。然而,这种方法将验证逻辑与特定的动作表单紧紧地耦合在一起。为了重用其他表单中的验证逻辑,您可能需要进行很多复制和粘贴。
Struts 验证器通过应用基于组件的设计理念解决了这个问题。Struts 验证器使得 ActionForms 能够共享一组验证规则,这组验证规则是 XML 文件的形式保存的。另外,Struts 验证器同时支持客户端和服务器端验证。两种方法共享同一组验证规则。
本文向您展示了如何使用 Struts 验证器。我们假定您具有 Struts 框架方面的基本知识。要了解基本的Struts 框架,请参看上面提到的文章。
启动 IBM? WebSphere? Studio Application Developer Version 5.0(带或不带 V5.01包):
本节将指导您安装一个现有的 Struts 应用程序。
导入 Struts 应用程序 EAR:
StrutsValidator.zip 并解压 DefaultEAR.ear 。
DefaultEAR 作为项目名,然后单击 Finish。 在 WebSphere Test Environment 中运行 Struts 应用程序以确保安装正确:
submitpage.jsp 之后,随便输入点什么,然后单击 Submit看看结果。
验证规则保存在一个名为 validator-rules.xml 的 XML 文件中。Struts提供了包含 14 个基本验证器的 validator-rules.xml 文件。最常用的一些文件列举如下:
| 验证器名称 | 功能 |
| required | 验证一个必须填写的字段是否填写 |
| mask | 通过一个常规的 Jakarta RegExp 表达式检查字段值。要了解更多关于 RegExp 的信息,请参见 Jakarta RegExp 页。例如: ? ^[a-zA-Z]*$ 表示该值必须只包含字母 ? ^\d{5}\d*$ 表示该值必须是五位数字 |
| range | 检查该值是否在指定范围内。 |
| date | 检查该值是否为一个有效值。它还能确保以期望的格式提供该数据,例如 MM/DD/YYYY 或 DD-MM-YYYY。 |
| 验证该值是以有效的电子邮件地址的格式提供。 | |
| creditCard | 确认该值是一个有效的信用卡号码。 |
将 validator-rules.xml 导入 /Web Content/WEB-INF 文件夹。
StrutsValidator.zip
并解压 validator-rules.xml 。
validator-rules.xml 文件。单击 Finish。
/SimpleValidatorWeb/Web Content/WEB-INF 中,双击 validator-rules.xml 以在 XML 编辑器中打开它。
validator-rules.xml 文件的代码如下。验证器规则必须封装在标签 <form-validation> 中。验证器包含验证逻辑。在以下示例中,验证器为 required ,它包含客户端和服务器端验证的验证代码。用黄色显示的代码定义了服务器端验证器类和方法,用绿色显示的代码定义了客户端验证的JavaScript 代码。该文件中的其余验证器采用了相同的结构。
<form-validation>
<global>
<validator name="required"
|
|
|
</validator>
</global>
</form-validation>
|
在大部分情况下,内置的验证器对于一个 Web 应用程序来说就足够了。为了在一个字段中使用验证器,需要在一个 XML 文件中指定验证器和字段之间的映射关系。在我们的示例中,它被命名为 validation.xml 。
validation.xml 作为文件名。单击 Finish。
<form-validation>
<formset>
<form name="submitForm">
<field property="name" depends="required">
<arg0 key="submitForm.name" />
</field>
</form>
</formset>
</form-validation>
|
validation.xml 文件包含表单和每个字段依赖的验证器之间的映射, submitForm 中的字段 name 依赖于 required 验证器。 arg0 是当错误消息产生时传递给验证器的参数。参数的键在资源绑定文件中有一个映射。由于该字段是比需的,所以将会产生一个错误消息(如果这个字段为空的话)。
将错误消息保存在 ApplicationResources.properties 中,它是由WebSphere Studio 创建并由 Struts 框架使用的缺省资源绑定。
用编辑器打开特性文件:
# Optional header and footer for <errors/> tag.
#errors.header=<ul>
#errors.footer=</ul>
# Errors
errors.footer=
errors.header=<h3><font color="red">Validation Error</font></h3>
You must correct the following error(s) before proceeding:
errors.ioException=I/O exception rendering error messages: {0}
error.database.missing=<li>User database is missing, cannot validate logon credentials</li>
errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.
errors.maxlength={0} can not be greater than {1} characters.
errors.invalid={0} is invalid.
errors.byte={0} must be an byte.
errors.short={0} must be an short.
errors.integer={0} must be an integer.
errors.long={0} must be an long.
errors.float={0} must be an float.
errors.double={0} must be an double.
errors.date={0} is not a date.
errors.range={0} is not in the range {1} through {2}.
errors.creditcard={0} is not a valid credit card number.
errors.email={0} is an invalid e-mail address.
submitForm.name = text field label
|
在这个示例中,将会显示错误消息 {0} is required ,其中 {0} 由通过 <arg0 key="submitForm.name" /> 从 validation.xml 传递而来的参数替代。在这个示例中, submitForm.name 映射到(资源束文件resource bundle file)中的 text filed label ,因此,最后的错误消息将会是 text field label is required 。
如果启用了服务器端验证,则错误消息将会在浏览器中作为 HTML 返回。对于客户端验证,错误消息将会作为 JavaScript 弹出窗口返回。
要启用验证器插件,请遵循下列步骤:
</struts-config> 结束标签前并保存修改。以下代码可以启用验证器组件并且指示该插件使用 validator-rules.xml 和 validation.xml 来验证动作表单:
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames" value="/WEB-INF/validator-rules.xml, /WEB-INF/validation.xml"/>
</plug-in>
|
struts-config.xml 编辑器的 Actions页,选择 /submit并在 Input字段中输入 /submitpage.jsp 。保存修改。 下面的步骤 3 和 4 将指导您完成各个必需的过程以启用服务器端验证和客户端验证。
为了使用服务器端验证, Action Form 实现类应该扩展 ValidatorForm 而不是 ActionForm 。当提交表单时,会执行 ValidatorForm 中的 validate() 方法,它将根据 validation-rules.xml 和 validation.xml 文件进行验证。
要在编辑器中打开 SubmitForm 类,请遵循下列步骤。
/SimpleValidatorWeb/Java Source/com.ibm.simplevalidatorweb.forms 内的 SubmitForm.java。
SubmitForm.java 并保存。 package com.ibm.simplevalidatorweb.forms;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.validator.ValidatorForm;
/**
* Form bean for a Struts application.
* Users may access 1 field on this form:
* <ul>
* <li>name - [your comment here]
* </ul>
* @version 1.0
* @author
*/
public class SubmitForm extends
ValidatorForm {
private String name = null;
/**
* Get name
* @return String
*/
public String getName() {
return name;
}
/**
* Set name
* @param <code>String</code>
*/
public void setName(String n) {
name = n;
}
/**
* Constructor
*/
public SubmitForm() {
super();
}
public void reset(ActionMapping mapping, HttpServletRequest request) {
// Reset values are provided as samples only. Change as appropriate.
name = null;
}
public ActionErrors validate(
ActionMapping mapping,
HttpServletRequest request) {
return super.validate(mapping, request);
}
}
|
您需要在 JSP 文件中添加 <html:errors/> 行以使错误显示出来:
submitpage.jsp 并切换到 Source 页。
<html:form> 前)输入行 <html:errors/> 。保存该修改。 要在 WebSphere Test Environment 中运行 submitpage.jsp ,请遵循下列步骤:
当在浏览器中装载 submitpage.jsp 时,单击 Submit,然后您将会接收到一个验证错误,告知 text field label 是必需的。

为了使用客户端验证, Action Form 应该扩展 ValidatorActionForm 而不是 ActionForm 。如前所述,对于服务器端验证, Action Form 扩展的是 ValidatorForm 类。
在编辑器中打开 SubmitForm 类。
/SimpleValidatorWeb/Java Source/com.ibm.simplevalidatorweb.forms 内的 SubmitForm.java。
SubmitForm.java 并保存。 validate() 方法注释掉了。要注释一段代码,可以选中该代码块,然后选择 Source => Comment。 package com.ibm.simplevalidatorweb.forms;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.validator.ValidatorActionForm;
import org.apache.struts.validator.ValidatorForm;
/**
* Form bean for a Struts application.
* Users may access 1 field on this form:
* <ul>
* <li>name - [your comment here]
* </ul>
* @version 1.0
* @author
*/
public class SubmitForm extends
ValidatorActionForm {
private String name = null;
/**
* Get name
* @return String
*/
public String getName() {
return name;
}
/**
* Set name
* @param <code>String</code>
*/
public void setName(String n) {
name = n;
}
/**
* Constructor
*/
public SubmitForm() {
super();
}
public void reset(ActionMapping mapping, HttpServletRequest request) {
// Reset values are provided as samples only. Change as appropriate.
name = null;
}
// public ActionErrors validate(
// ActionMapping mapping,
// HttpServletRequest request) {
// return super.validate(mapping, request);
// }
}
|
修改 submitpage.jsp 以启用服务器端验证:
submitpage.jsp 。
<html:errors /> 在客户端验证时不再需要。 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html:html>
<HEAD>
<%@ page
language="java"
contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"
%>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<META name="GENERATOR" content="IBM WebSphere Studio">
<META http-equiv="Content-Style-Type" content="text/css">
<LINK href="theme/Master.css" rel="stylesheet"
type="text/css">
<TITLE></TITLE>
</HEAD>
<BODY>
<html:form action="/submit"
onsubmit="return validateSubmitForm(this);">
<bean:message key="submitForm.name"/>: <html:text property="name"/>
<html:submit/>
</html:form>
</BODY>
<html:javascript formName="submitForm"/>
</html:html>
|
行 <html:javascript formName="submitForm"/> 中的 formName submitForm 必须与 validation.xml 和 struts-config.xml 文件中的表单名称相匹配。
由于我们对应用程序做了修改,所以我们必须重新启动该 EAR 项目:
在 submitpage.jsp 装载到浏览器中后,单击 Submit,然后您将会看到一个弹出的 JavaScript 消息,告知字段 text field label 是必需的:
有时,业务要求一个字段上有多个验证器。Struts 验证器使得一个字段可以由多个验证器进行验证。
例如,要添加一个电子邮件验证器,可以如下编辑 validation.xml 并保存它:
<form-validation>
<formset>
<form name="submitForm">
<field property="name" depends="required,
email">
<arg0 key="submitForm.name"/>
</field>
</form>
</formset>
</form-validation>
|
重新启动 DefaultEAR 项目并再次运行 submitpage.jsp 。输入一个无效的电子邮件地址并提交,您将会接收到一个错误消息,告知它不是一个有效的电子邮件地址。另外, required 验证器仍将继续工作。
在某些情况下,您可能想提供一个更具体的错误消息而不是在资源束文件中定义的缺省错误消息。例如,如果您有一个 Mask 验证器,缺省错误消息是,该值是无效的,而没有关于无效性的详细情况。您可以用另一个消息覆盖 Mask 验证器的错误消息,方式是将如下一行代码添加到 validator.xml 中: <msg name="mask" key="some.other.error.msg"/> 。
将如下一行代码添加到文件 ApplicationResources.properties 中并保存:
some.other.error.msg = {0} is not a 5-digit number
|
如下编辑 validation.xml 并保存:
<form-validation>
<formset>
<form name="submitForm">
<field property="name" depends="required,
mask">
<msg name="mask" key="some.other.error.msg"/>
<arg0 key="submitForm.name"/>
<var>
<var-name>mask</var-name>
<var-value>^\d{5}\d*$</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
|
重新启动 DefaultEAR 项目并再次运行 submitpage.jsp 。一个更具体的错误消息将会显示出来。

如前所述,随 Struts 一起发布大约有 14 种基本的 Struts 验证器。每个验证器都可能要求不同的参数,而您必须提供正确的参数以使用它们。在本节中,您将在一个更为复杂的 Struts 应用程序中看到更多正在使用的验证器。
将 StrutsValidation.war 文件导入 DefaultEAR :
StrutsValidator.zip 并解压 StrutsValidation.war 。
StrutsValidationWeb 作为该 Web 项目名。
DefaultEAR 。
重新启动服务器并在 StrutsValidationWeb 中运行 submitpage.jsp 。
让我们来分析一下 validation.xml 。在编辑器中打开 validation.xml 。它在 /StrutsValidationWeb/Web Content/WEB-INF 中。
<form-validation>
<global>
<constant>
<constant-name>phone</constant-name>
<constant-value>^\(?(\d{3})\)?[-| ]?(\d{3})[-| ]?(\d{4})$</constant-value>
</constant>
<constant>
<constant-name>zip</constant-name>
<constant-value>^\d{5}\d*$</constant-value>
</constant>
</global>
<formset>
<constant>
<constant-name>zip</constant-name>
<constant-value>^\d{5}(-\d{4})?$</constant-value>
</constant>
<form name="submitForm">
<field property="customer.firstName"
depends="required,mask,minlength">
<arg0 key="submitForm.customer.firstname"/>
<arg1 name="minlength" key="${var:minlength}" resource="false"/>
<var>
<var-name>mask</var-name>
<var-value>^\w+$</var-value>
</var>
<var>
<var-name>minlength</var-name>
<var-value>5</var-value> </var>
</field>
<field property="customer.lastName"
depends="required,mask,maxlength">
<msg name="mask" key="submitForm.lastname.maskmsg"/>
<arg0 key="submitForm.customer.lastname"/>
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>mask</var-name>
<var-value>^[a-zA-Z]*$</var-value>
</var>
<var>
<var-name>maxlength</var-name>
<var-value>10</var-value>
</var>
</field>
<field property="customer.address"
depends="required">
<arg0 key="submitForm.customer.address"/>
</field>
<field property="customer.city"
depends="required,mask">
<arg0 key="submitForm.customer.city"/>
<var>
<var-name>mask</var-name>
<var-value>^[a-zA-Z]*$</var-value>
</var>
</field>
<field property="customer.state"
depends="required,mask">
<arg0 key="submitForm.customer.state"/>
<var>
<var-name>mask</var-name>
<var-value>^[a-zA-Z]*$</var-value>
</var>
</field>
<field property="customer.zip"
depends="required,mask">
<arg0 key="submitForm.customer.zip"/>
<var>
<var-name>mask</var-name>
<var-value>${zip}</var-value>
</var>
</field>
<field property="customer.phone"
depends="mask">
<arg0 key="s
ubmitForm.customer.phone"/>
<var>
<var-name>mask</var-name>
<var-value>${phone}</var-value>
</var>
</field>
<field property="customer.email"
depends="required,email">
<arg0 key="submitForm.customer.email"/>
</field>
<field property="creditcard.date"
depends="required,date">
<arg0 key="submitForm.creditcard.date"/>
<var>
<var-name>datePatternStrict</var-name>
<var-value>MM-dd-yyyy</var-value>
</var>
</field>
<field property="creditcard.number"
depends="required,creditCard">
<arg0 key="submitForm.creditcard.number"/>
</field>
</form>
</formset>
</form-validation>
|
下面是 Last Name 字段的代码。它依赖于 3 个验证器: required、mask 和 maxlength 。 required 验证器,如前所述,确保填写了该字段。 mask 验证器在这个示例中检查是否所有的值都是字母。 mask 验证器的 RegExp 表达式检查字母是否是 ^[a-zA-Z]*$ 。 maxlength 验证器确保这个示例中的字段的长度小于或等于 10。
示例 1. Last Name 字段的验证器映射
<field property="customer.lastName"
depends="required,mask,maxlength">
<msg name="mask" key="submitForm.lastname.maskmsg"/>
<arg0 key="submitForm.customer.lastname"/>
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>mask</var-name>
<var-value>^[a-zA-Z]*$</var-value>
</var>
<var>
<var-name>maxlength</var-name>
<var-value>10</var-value>
</var>
</field>
|
下面的示例是使用 mask 验证器的一个小小的变种。这段代码是为 Phone 字段而写的。 mask 验证器包含参数 ${phone} ,它是在 validation.xml 文件的开头定义的一个常量(请参见示例3)。
示例 2. Phone 字段的验证器映射
<field property="customer.phone"
depends="mask">
<arg0 key="submitForm.customer.phone"/>
<var>
<var-name>mask</var-name>
<var-value>${phone}</var-value>
</var>
</field>
|
示例 3.phone 常量
<constant>
<constant-name>phone</constant-name>
<constant-value>^\(?(\d{3})\)?[-| ]?(\d{3})[-| ]?(\d{4})$</constant-value>
</constant>
|
下面的代码是为 Date 字段而写的。您可以在 date 验证器上使用它本身,如示例 4所示--它根据地区验证日期的格式。您也可以指定一个日期模式,如示例 5 所示:
示例 4.Date 验证器
<field property="creditcard.date"
depends="required,date">
<arg0 key="submitForm.creditcard.date"/>
</field>
|
示例 5. 带 datePatternStrict 的 Date 验证器
<field property="creditcard.date"
depends="required,date">
<arg0 key="submitForm.creditcard.date"/>
<var>
<var-name>datePatternStrict</var-name>
<var-value>MM-dd-yyyy</var-value>
</var>
</field>
|
这个示例也适用于 email 和 creditCard 验证器。由于这两个验证器都很简单,所以您可以自己去分析它们。
Struts 验证器框架使您能够使用服务器端和客户端验证。您可以在大多数 Web应用程序中不加修改地使用内置的规则集。出于性能方面的考虑,客户端验证通常是更好的选择。
Struts 框架通过应用模型-视图-控制器(Model-View-Controller)范式解耦 Web 组件。Struts Tiles框架将页面布局与表示层分离开来,而 Struts 验证器框架将验证逻辑和业务逻辑分离开来。使用 Struts 与 Struts 的相关框架可以使您的Web 应用程序具有更好的可维护性和可重用性。