原文: http://www.onjava.com/pub/a/onjava/2002/12/11/jakartastruts.html
譯者: javaduke
Email:javaduke@263.net
QQ:658155
MSN:javaduke@hotmail.com
每個(gè)應(yīng)用程序都有責(zé)任確保它們插入到后臺(tái)資料庫(kù)的數(shù)據(jù)是合法有效的,畢竟,如果這些應(yīng)用程序所依賴(lài)的數(shù)據(jù)一旦遭到了破壞,那將是災(zāi)難性的,那應(yīng)用程序還能拿什么來(lái)使自己正常運(yùn)轉(zhuǎn)呢?比如說(shuō),使用正規(guī)關(guān)系數(shù)據(jù)庫(kù)的一個(gè)應(yīng)用程序,數(shù)據(jù)庫(kù)中的每個(gè)字段都有自己一定的規(guī)則和約束,來(lái)保證存儲(chǔ)在其中的數(shù)據(jù)在一定程度上的正確性。任何要使用后臺(tái)資料庫(kù)數(shù)據(jù)的應(yīng)用程序都有責(zé)任保護(hù)它們提交的數(shù)據(jù)的完整性。
任何試圖插入或更新不符合標(biāo)準(zhǔn)的數(shù)據(jù)的操作都有可能被發(fā)現(xiàn)并拒絕。這種檢測(cè)可能遍布在整個(gè)應(yīng)用程序的每個(gè)角落,在表現(xiàn)層可能進(jìn)行一些驗(yàn)證,在業(yè)務(wù)邏輯層,商業(yè)邏輯對(duì)象一般也有商業(yè)邏輯的驗(yàn)證,還有在后臺(tái)資料庫(kù)也要對(duì)數(shù)據(jù)進(jìn)行檢查。
不幸的是,由于這種驗(yàn)證在應(yīng)用程序中無(wú)處不在,造成了應(yīng)用程序在一定程度上的驗(yàn)證數(shù)據(jù)的代碼冗余。這并不是應(yīng)用程序所希望的,因?yàn)檫@種在多處的重復(fù)勞動(dòng),使得應(yīng)用程序的部署和維護(hù)要花去更多的時(shí)間。如果在整個(gè)應(yīng)用程序中,這些驗(yàn)證規(guī)則可以重復(fù)使用,將使得應(yīng)用程序更加富有彈性,換句話說(shuō)就是,部署更快捷,定制更容易,程序更靈活。
Jakarta Commons 項(xiàng)目Validator框架簡(jiǎn)介
Validator是由David Winterfeldt創(chuàng)建的開(kāi)源項(xiàng)目,它也是Jakarta Commons的一個(gè)子項(xiàng)目。Commons項(xiàng)目主要是提供一些像Validator這樣的一些可重用組件。其他著名的Commons組件還有如BeanUtils,Digester,Logging框架等。Validator 1.0版本發(fā)布于2002年11月初。
使用Validator的好處
.使用Validator框架比一般的在應(yīng)用程序的代碼中定義驗(yàn)證規(guī)則有好多優(yōu)點(diǎn),如:
.可以在一處為應(yīng)用程序定義驗(yàn)證規(guī)則;
.驗(yàn)證規(guī)則和應(yīng)用程序是松耦合的;
.服務(wù)器端和客戶端的驗(yàn)證規(guī)則可以在同一處定義;
.配置新驗(yàn)證規(guī)則或修改已有驗(yàn)證規(guī)則變得更加簡(jiǎn)單;
.支持國(guó)際化;
.支持正則表達(dá)式;
.可以用于Web應(yīng)用程序也可用于標(biāo)準(zhǔn)的Java應(yīng)用程序;
.采用聲明的方法實(shí)現(xiàn)而不是編程實(shí)現(xiàn);
除了之外,Validator最大的特征就是自身支持可插性(pluggability)。在文章的后
面你將會(huì)看到使用Validator框架內(nèi)置的驗(yàn)證規(guī)則來(lái)更好地完成你的工作,而更重要的是,Validator框架允許你自定義驗(yàn)證程序,并插入到框架中。
Struts和Validator的關(guān)系
應(yīng)該指出的是Validator框架本身是因Struts框架而建立的。Validator的創(chuàng)建者David Winterfeldt在使用Struts的過(guò)程中發(fā)現(xiàn),在許多ActionForm類(lèi)中需要反復(fù)使用同一個(gè)驗(yàn)證規(guī)則,這樣造成了大量的代碼冗余。于是他決定創(chuàng)建Validator框架來(lái)消除這種冗余,這樣Validator就誕生了。
盡管Validator架構(gòu)最初是為Struts架構(gòu)而生,但它還是被設(shè)計(jì)和構(gòu)造成了可以獨(dú)立于Struts架構(gòu)而單獨(dú)使用。這一個(gè)特征使得你可以在任何的應(yīng)用程序中使用這個(gè)框架,不必管它是不是Struts架構(gòu)的。并不會(huì)因?yàn)槟悴皇褂肧truts框架而影響Validator架構(gòu)對(duì)你的應(yīng)用程序作用。事實(shí)上,這就是為什么Validator是Jakarta Commons項(xiàng)目的一部分而不直接是Struts項(xiàng)目的一部分。
現(xiàn)在,我們來(lái)將這個(gè)框架整合應(yīng)用到像基于Struts構(gòu)架這樣的Web應(yīng)用程序上。在文章的最后中我們?cè)俳榻B如何把它應(yīng)用到其他類(lèi)型的應(yīng)用程序中,如基于EJB的應(yīng)用程序。
Validator組件概述
Validator架構(gòu)有下面這些組件組成:
Validators;
配置文件;
資源綁定;
JSP自定義標(biāo)簽;
Validator Form類(lèi);
什么是Validators?
一個(gè)Validator就是,執(zhí)行一個(gè)驗(yàn)證規(guī)則時(shí)Validator框架調(diào)用的一個(gè)Java類(lèi)。框架根據(jù)配置文件中定義的方法簽名來(lái)調(diào)用這個(gè)Validaotor類(lèi)。一般情況下,每個(gè)Validator類(lèi)提供一個(gè)單獨(dú)的驗(yàn)證規(guī)則,然后這些規(guī)則可以組合成更復(fù)雜的規(guī)則集。
注意:有時(shí)出于方便,一個(gè)Validator類(lèi)也可以定義多個(gè)驗(yàn)證規(guī)則,而每個(gè)規(guī)則是一個(gè)靜態(tài)方法且并不包含任何客戶端狀態(tài)信息。
框架提供了14種默認(rèn)的驗(yàn)證規(guī)則,有時(shí)候這些規(guī)則也被稱(chēng)為Validator框架的“基本規(guī)則”,這些基本規(guī)則如表一:
名稱(chēng) 描述
byte,short,integer, 檢驗(yàn)值是否能被轉(zhuǎn)換成對(duì)應(yīng)的基本數(shù)據(jù)類(lèi)型
long,float,double
creditCard 檢驗(yàn)輸入域是否是一個(gè)合法的信用卡號(hào)碼
date 檢驗(yàn)輸入域是否是一個(gè)合法日期
email 檢驗(yàn)輸入是否是一個(gè)合法Email地址
mask 檢驗(yàn)輸入域是否能成功匹配一個(gè)正則表達(dá)式
maxLength 檢驗(yàn)值的長(zhǎng)度是否小于等于給定的最大長(zhǎng)度
minLength 檢驗(yàn)值的長(zhǎng)度是否大于等于給定的最小長(zhǎng)度
range 檢驗(yàn)值的范圍是否在最大值和最小值之間
required 檢驗(yàn)輸入域是否為不為空,或不包含空格值的長(zhǎng)度是否大于零
表一
正像你在表一中看到的,Validator框架提供了Web應(yīng)用程序需要的大多數(shù)的驗(yàn)證規(guī)則。你可以使用這些現(xiàn)有的驗(yàn)證規(guī)則來(lái)創(chuàng)建自己驗(yàn)證配置文件。盡管這樣,也正如我們前面提到的,和后面要講到的,你可以根據(jù)你的需要隨意的增加更多的Validator。
現(xiàn)在,讓我們來(lái)討論如何在一個(gè)基于Struts架構(gòu)的應(yīng)用程序中配置使用這些基本的Validator。
使Validator框架具有彈性的原因在于所有的驗(yàn)證規(guī)則和其具體細(xì)節(jié)都是通過(guò)在外部文件中配置聲明實(shí)現(xiàn)的。你的應(yīng)用程序并不必要知道這些具體的驗(yàn)證規(guī)則。這一特征使得規(guī)則集的發(fā)生擴(kuò)展和修改時(shí),你并不用去動(dòng)你應(yīng)用程序的源代碼。這一點(diǎn)對(duì)你要進(jìn)行每次的個(gè)性化安裝或當(dāng)需求發(fā)生變化時(shí)來(lái)說(shuō)是非常重要的。
如果你使用Struts1.1的Validator框架,你會(huì)用到這樣兩個(gè)配置文件,一個(gè)叫validator- rules.xml,另一個(gè)叫validation.xml;其實(shí)你也可以隨意的給他們命名,甚至可以把它們合并成一個(gè)XML文件。但是,你還是最好把它們分開(kāi),因?yàn)樗鼈兏饔懈鞯挠猛尽?BR>
注意:如果你從Jakarta網(wǎng)站上下載Validator,并不包含這兩個(gè)文件。只有在包含的Validator框架的Struts的下載中才可以找到這兩個(gè)文件。
validator-rules.xml文件
validator-rules.xml文件定義應(yīng)用程序可以使用的Validator。validator-rules.xml充當(dāng)模板的作用,定義所有應(yīng)用程序可能要用到的Validator。
注意:這個(gè)xml文件和我們下面要討論的另一個(gè)xml文件都應(yīng)該放到類(lèi)加載器可以找得到的地方。當(dāng)我們?cè)赪eb應(yīng)用程序中使用Validator框架時(shí),正確的位置應(yīng)該是在WEB-INF下。
validator-rules.xml文件服從validator- rules_1_1.dtd的管理,validator- rules_1_1.dtd可以在jakarta.apache.org/struts/dtds/validator- rules_1_1.dtd下載到。我們并不想花太多的時(shí)間放在研究這個(gè)文件的具體細(xì)節(jié)上,我們?cè)谶@兒只作一些基本的介紹。
validator-rules.xml文件中最重要的元素包含在<validator>元素中,例如,例一:
validator-rules.xml :
<form-validation>
<global>
<validator name="required"
classname="org.apache.struts.util.StrutsValidator"
method="validateRequired"
methodparams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionErrors,
javax.servlet.http.HttpServletRequest"
msg="errors.required"/>
<validator name="minlength"
classname="org.apache.struts.util.StrutsValidator"
method="validateMinLength"
methodparams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionErrors,
javax.servlet.http.HttpServletRequest"
depends="required"
msg="errors.minlength"/>
</global>
</form-validation>





org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionErrors,
javax.servlet.http.HttpServletRequest"





org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionErrors,
javax.servlet.http.HttpServletRequest"




應(yīng)用程序使用的每個(gè)Validator對(duì)應(yīng)一個(gè)<validator>元素。在例一中給大家展示了兩個(gè)Validator,一個(gè)是請(qǐng)求Validator,另一個(gè)是最小長(zhǎng)度Validator。<validator>元素支持許多屬性。這些屬性是必要的,用于告知框架這個(gè)Validator應(yīng)當(dāng)調(diào)用哪個(gè)正確的類(lèi)和方法。例如,例一中的請(qǐng)求Validator元素表明這個(gè)Validator將調(diào)用org.apache.struts.util.StrutsValidator類(lèi)的validateRequest()方法。Validator也可能要依賴(lài)另一個(gè)Validator,如例一中的最小長(zhǎng)度的Validator就是這樣一個(gè)例子,它包含一個(gè)depends屬性,用它來(lái)表示這個(gè)Validator將依賴(lài)于請(qǐng)求Validator。msg屬性用一個(gè)鍵值指定一個(gè)資源綁定,框架將用它來(lái)生成正確的錯(cuò)誤信息。資源綁定的使用有益于錯(cuò)誤信息的本地化。
<validator>元素還支持<javascript>子元素,允許你指定一個(gè)客戶端運(yùn)行的JavaScript函數(shù)。這樣服務(wù)器端和客戶端驗(yàn)證可以在同一處指定,這使應(yīng)用程序的維護(hù)變得簡(jiǎn)單。
validation.xml文件
Validator框架的第二個(gè)配置文件就是這個(gè)叫validation.xml的文件。其實(shí)你可以隨意把它命名為你喜歡的任何名字,也可以把它放到validator-rules.xml文件中。
validation.xml用于把你在validator-rules.xml中定義的各個(gè)Validator和你的應(yīng)用程序中的組件映射起來(lái)。由于我們?cè)谶@里討論的是在Struts中使用Validator框架,那么在這里validation.xml就是把這些Validator和Struts的ActionForm類(lèi)建立映射。ActionForm類(lèi)其實(shí)是一個(gè)類(lèi)似JavaBean一樣的類(lèi),在Struts中用于捕捉用戶輸入并幫助傳輸這些輸入到下一級(jí)應(yīng)用程序組件。ActionForm也提供了在用戶輸入被傳到業(yè)務(wù)邏輯層之前驗(yàn)證這些輸入的便利場(chǎng)所。例二是一個(gè)簡(jiǎn)單的validation.xml:
validation.xml:












其實(shí)它還有許多其它作用,如可以在validation.xml中定義常量和全局變量,用于在整個(gè)文件中使用,當(dāng)你想使時(shí)可以方便的反復(fù)使用。對(duì)于validation.xml的元素和屬性更詳細(xì)的解釋?zhuān)梢韵螺djakarta.apache.org/struts/dtds/validation_1_1.dtd參閱。
資源綁定
資源綁定用于幫助消息本地化和一些其它文本信息的本地化處理。由于它減少了應(yīng)用程序的許多冗余的硬編碼,故對(duì)應(yīng)用程序有很大益處。比如,如果你要在JSP頁(yè)面中要使用一個(gè)“Name”標(biāo)簽時(shí),你可以把這個(gè)字符串放到一個(gè)資源綁定中,然后使用資源綁定的一個(gè)邏輯鍵值引用這個(gè)字符串,而不是直接使用這個(gè)字符串,這樣做的好處在于,當(dāng)你想把這個(gè)字符串改為“First Name”時(shí),你只需在資源綁定中修改一處即可,而不必修改整個(gè)應(yīng)用程序的全部代碼。
對(duì)于Validator框架,當(dāng)驗(yàn)證規(guī)則失敗的時(shí)候,可以從資源綁定中創(chuàng)建錯(cuò)誤信息。Validator框架提供幾種默認(rèn)消息,同一般的應(yīng)用程序消息資源放在一起。如下:
application.properties:
#Normal resource bundle messageslabel.firstName=First Name
label.lastName=Last Name
#Error messages used by the Validator
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
.........
label.lastName=Last Name
#Error messages used by the Validator
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
.........
當(dāng)一個(gè)驗(yàn)證規(guī)則失敗時(shí),這個(gè)驗(yàn)證規(guī)則創(chuàng)建一個(gè)錯(cuò)誤信息。框架將自動(dòng)給消息插入?yún)?shù)。比如說(shuō),我們使用例一和例二的驗(yàn)證規(guī)則,當(dāng)checkoutForm的firstName屬性為空時(shí),我們會(huì)看到這樣的錯(cuò)誤信息:
First Name is required.
你也可以修改綁定或配置文件來(lái)顯示你喜歡的消息。
“掛”Validator到Struts上
現(xiàn)在我們已經(jīng)了解了Validator框架,感覺(jué)蠻不錯(cuò)吧!下面我們將快速的講一下我們是如何輕松地在Struts框架中使用Validator框架的。
首先要做的就是讓Struts框架認(rèn)識(shí)Validator框架。你可以使用Struts1.1的Plug-in新特性來(lái)實(shí)現(xiàn)它。只要在Struts配置文件中增加下面代碼即可:
struts-config.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>
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
這樣Struts就可以自動(dòng)識(shí)別Validator框架了。
另外一個(gè)必需的步驟就是創(chuàng)建ActionForm Bean(標(biāo)準(zhǔn)的或是動(dòng)態(tài)的)和確保Validator框架的配置文件是可用的,這樣就搞定了。并不需要作一些調(diào)用驗(yàn)證規(guī)則或做其他具體的事情,Struts框架會(huì)自動(dòng)完成這些工作,這就是所謂的基于聲明的配置。然后當(dāng)驗(yàn)證規(guī)則失敗的時(shí)候,你就可以用JSP標(biāo)簽看到顯示的錯(cuò)誤信息了。
創(chuàng)建自己的Validator
盡管Validator框架已為大家提供了Web應(yīng)用程序需要的大多數(shù)驗(yàn)證規(guī)則,但有時(shí)我們還是需要?jiǎng)?chuàng)建一些自己的驗(yàn)證規(guī)則。幸運(yùn)的,Validator框架的擴(kuò)展性相當(dāng)好,為你提供了這種便利,而這樣做對(duì)程序造成的影響相當(dāng)小的。
創(chuàng)建自己的Validator并不是一件難事,只要?jiǎng)?chuàng)建一個(gè)實(shí)現(xiàn)這個(gè)規(guī)則的Java類(lèi)即可。比如,(在國(guó)外)要去超市買(mǎi)二鍋頭,要驗(yàn)證顧客是否達(dá)到合法飲酒年齡。你可以使用已有的驗(yàn)證規(guī)進(jìn)行驗(yàn)證,但我們覺(jué)得創(chuàng)建一個(gè)驗(yàn)證規(guī)則進(jìn)行驗(yàn)證要更加直截了一些。驗(yàn)證飲酒年齡規(guī)則Validator Java代碼如下:
Validator.Java
import java.io.Serializable;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.GenericValidator;
import org.apache.commons.validator.ValidatorAction;
import org.apache.commons.validator.ValidatorUtil;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.util.StrutsValidatorUtil;





ValidatorAction va,
Field field,
ActionErrors errors,
HttpServletRequest request)

String value = null;
if (isString(bean)) {
value = (String) bean;
} else {
value = ValidatorUtil.getValueAsString(bean, field.getProperty());
}
String sMin = field.getVarValue("drinkingAge");
if (!GenericValidator.isBlankOrNull(value)) {
try {
int iValue = Integer.parseInt(value);
int drinkingAge = Integer.parseInt(sMin);
if ( iValue < drinkingAge ){
errors.add(field.getKey(), StrutsValidatorUtil.getActionError(request, va, field));
return false;
}
} catch (Exception e) {
errors.add(field.getKey(), StrutsValidatorUtil.getActionError(request, va, field));
return false;
}
}
return true;
}
private static boolean isString(Object o) {
if (o == null) {
return (true);
}
return (String.class.isInstance(o));
}
}
在非Struts應(yīng)用程序中使用Validator框架
正像我們?cè)谇懊嬲劦降模琕alidator框架最初是為在Struts框架中使用而設(shè)計(jì)的。可是,Validator框架設(shè)計(jì)的相當(dāng)靈活,并沒(méi)有直接把它耦合在Struts框架中,這樣你就可以在普通的應(yīng)用程序中也可以使用Validator框架來(lái)進(jìn)行驗(yàn)證。但是,你必須執(zhí)行一些必需的步驟。
你可以利用像在Web應(yīng)用程序中一樣使用配置文件。這也是使用Validatoe框架的另一個(gè)優(yōu)點(diǎn)。你可以在Struts框架使用插件的方式來(lái)定位和裝載這些文件。而在非Struts應(yīng)用程序中你必須人為地手動(dòng)的定位和裝載這些配置文件。下面就是應(yīng)用程序在啟動(dòng)時(shí)一般要調(diào)的方法:









例四向你展示如何使用已初始化的ValidatorResources對(duì)象來(lái)驗(yàn)證一個(gè)Person Bean。








正如你看到的一樣,在非Struts應(yīng)用程序中使用Validator框架顯得有點(diǎn)不自動(dòng)化,但是它還是提供了比較靈活的解決方案。使用Validator框架的另一個(gè)好處就是把驗(yàn)證從源代碼中分離到外部的配置文件中。這使我們可以把更多的時(shí)間放在我們的業(yè)務(wù)邏輯開(kāi)發(fā)上。
客戶端VS服務(wù)器端Validator
最后我們簡(jiǎn)單的闡述一下Validator框架對(duì)JavaScript的支持。因?yàn)橛行?yīng)用程序需要執(zhí)行一些客戶端驗(yàn)證,在某些時(shí)候使用JavaScript進(jìn)行一些客戶端的驗(yàn)證是很有必要的。這里的客戶端我們一般特指Web瀏覽器。
Validator框架提供使用配置文件中的規(guī)則動(dòng)態(tài)和自動(dòng)生成JavaScript驗(yàn)證規(guī)則的支持。對(duì)于每個(gè)<validator>元素,它可以有一個(gè)<javascript>子元素和包含一些JavaScript代碼。當(dāng)包含一些自定義標(biāo)簽的JSP頁(yè)面被解釋時(shí),JavaScript也被解釋?zhuān)?dāng)表單提交時(shí)執(zhí)行這些驗(yàn)證規(guī)則。這些叫JavaScriptValidatorTag的標(biāo)簽被包含在Struts的標(biāo)簽集中。這些標(biāo)簽可以像這樣進(jìn)行使用:
<html:javascript formName="checkoutForm"/>
筆者認(rèn)為在需要時(shí)使用一定的JavaScript是可以接受的。當(dāng)你需要執(zhí)行一些客戶端的驗(yàn)證時(shí),使用Validator框架標(biāo)簽是也是一種不錯(cuò)的選擇,而且支持根據(jù)用戶的區(qū)域進(jìn)行本地化。
結(jié)束語(yǔ)
到此為止,我給大家簡(jiǎn)單地介紹了Validator框架,這些其實(shí)是框架的一些表面的東西。這個(gè)框架的內(nèi)容深不可測(cè),僅正則表達(dá)式就可以寫(xiě)一本小冊(cè)子。
像任何一個(gè)框架一樣,Validator框架為大家提供的是一個(gè)基礎(chǔ)的架構(gòu),你可以根據(jù)你的需求對(duì)其進(jìn)行擴(kuò)展和個(gè)性化。使用像Validator的框架的最重要的一點(diǎn)就是它們是經(jīng)過(guò)千錘百煉,是技術(shù)的精華。。你并不需重蹈前人失敗的覆轍,你可以節(jié)省下時(shí)間把更多的精力集中在對(duì)業(yè)務(wù)邏輯的開(kāi)發(fā)上。
作者簡(jiǎn)介:
Chuck Cavaness:畢業(yè)于Georgia Tech,獲計(jì)算機(jī)工程與科學(xué)學(xué)位,在醫(yī)療,銀行和B2B領(lǐng)域創(chuàng)建了許多Java企業(yè)系統(tǒng),同時(shí)也是O'Reilly的Programming Jakarta Struts 和 Jakarta Struts Pocket Reference兩本書(shū)的作者。