主題: 1(2005-8-19 周五) |
作者: kingapex |
| 鏈接地址: |
1111111111111 |
留言 (0 留言) |
主題: Struts Validator驗(yàn)證器使用指南(2005-8-18 周四) |
作者: heweiya |
| 鏈接地址:Struts Validator驗(yàn)證器使用指南 |
Struts Validator驗(yàn)證器使用指南
(根據(jù)Struts Validator Guide)
作者:
David Winterfeldt大衛(wèi)
James Turner詹姆斯
Rob Leland羅伯特
翻譯:
侯思超 驗(yàn)證器:
從0.5版,驗(yàn)證器在一些form中就已經(jīng)實(shí)現(xiàn)了,他最初包含在開發(fā)人員包中,后來核心代碼挪到Jakarta Commons包中和Struts特別擴(kuò)展中作為 Struts 1.1的一部分。許多開發(fā)者為方便一直使用struts驗(yàn)證器,這篇文檔首先概述驗(yàn)證器的核心功能性,然后大概介紹在 struts1.1中的變化和新增功能。
如果你配置好驗(yàn)證器插件,你應(yīng)該擴(kuò)展ValidatorForm而不是ActionForm,以便它能加載你的Validator資源。他根據(jù)struts-config.xml文件中的action的name屬性為當(dāng)前form的調(diào)用相應(yīng)的驗(yàn)證器,因此在validator-rules.xml中的form元素的名稱屬性應(yīng)該與action的name屬性值相匹配。
另外一種選擇是擴(kuò)展ValidatorActionForm 而不是ValidatorForm,ValidatorActionForm使用struts-config.xml中action的path屬性,所以path屬性的值相應(yīng)的應(yīng)該與validator-rules.xml中的Form的name屬性匹配。
一個(gè)分離的action可以定義給多頁form的每個(gè)頁面,而且驗(yàn)證規(guī)則可以與action關(guān)聯(lián)而不是與頁碼,就像驗(yàn)證范例中的多頁form范例那樣。 國際化
在validator-rules.xml 文件中form的驗(yàn)證規(guī)則可以組織為FormSet。FormSet 有與java.util.Locale 類相應(yīng)的屬性:如語言, 國家以及變量型屬性,如果他們未定義,F(xiàn)ormSet 將把它設(shè)置為默認(rèn)值。一個(gè)FormSet 也可以有關(guān)聯(lián)的常量。另外還可以定義與FormSet 同一級別的全局global元素,他與FormSet同樣也有常量。
注意:你必須在國際化的FormSet前聲明一個(gè)沒有國際化的默認(rèn)FormSet。這樣如果Validator沒有找到locale時(shí)可以有一個(gè)默認(rèn)版本。
可插入驗(yàn)證器的默認(rèn)錯(cuò)誤信息值可以被msg元素覆蓋。所以為mask驗(yàn)證器生成錯(cuò)誤信息的替代方法就是使用msg屬性,如果字段的name屬性與驗(yàn)證器的name屬性匹配,那末將使用字段的msg屬性。
error messages的可以設(shè)置arg0-arg3 等參數(shù)元素。如果沒有設(shè)置arg0-arg3的name屬性, error messages將使用他們作為默認(rèn)的構(gòu)建參數(shù)值。如果設(shè)置了name屬性,你就可以把參數(shù)指定給一特定的可插入驗(yàn)證器,然后這些參數(shù)將在構(gòu)造錯(cuò)誤信息時(shí)被使用。
<field
property="lastName"
depends="required,mask">
<msg
name="mask"
key="registrationForm.lastname.maskmsg"/>
<arg0 key="registrationForm.lastname.displayname"/>
<var>
<var-name>mask</var-name>
<var-value>^[a-zA-Z]*$</var-value>
</var>
</field>
默認(rèn)的arg0-arg3元素將在消息資源中查找相應(yīng)的key,如果資源屬性設(shè)為false,她將把值直接傳進(jìn)去,而不從消息資源中查找。注意1.1版本中,你必須為每個(gè)模塊中明確地定義在驗(yàn)證中用到的消息資源,否則將使用top-level資源。
<field
property="integer"
depends="required,integer,intRange">
<arg0 key="typeForm.integer.displayname"/>
<arg1
name="range"
key="${var:min}"
resource="false"/>
<arg2
name="range"
key="${var:max}"
resource="false"/>
<var>
<var-name>min</var-name>
<var-value>10</var-value>
</var>
<var>
<var-name>max</var-name>
<var-value>20</var-value>
</var>
</field> 常量/變量
全局的常量可以在全局標(biāo)簽中定義,F(xiàn)ormSet/本地常量能在formset 標(biāo)簽中創(chuàng)建。常量當(dāng)前僅僅是代替字段的property屬性,字段的var 元素的 value屬性,字段的msg 元素的 key屬性,字段的arg0-arg3 元素的 key屬性。字段的變量也可以在arg0-arg3 元素中被代替(例如:${var:min}))。替換的順序是FormSet/Locale常量第一,全局的常量第二,
arg elements 變量最后。
<global>
<constant>
<constant-name>zip</constant-name>
<constant-value>^\d{5}(-\d{4})?$</constant-value>
</constant>
</global>
<field
property="zip"
depends="required,mask">
<arg0 key="registrationForm.zippostal.displayname"/>
<var>
<var-name>mask</var-name>
<var-value>${zip}</var-value>
</var>
</field>
驗(yàn)證器可以使用字段下面的變量部分來存儲(chǔ)變量,這些變量通過字段的getVar((String key)方法取得。
<field
property="integer"
depends="required,integer,intRange">
<arg0 key="typeForm.integer.displayname"/>
<arg1
name="range"
key="${var:min}" resource="false"/>
<arg2
name="range"
key="${var:max}" resource="false"/>
<var>
<var-name>min</var-name>
<var-value>10</var-value>
</var>
<var>
<var-name>max</var-name>
<var-value>20</var-value>
</var>
</field> 使用validwhen設(shè)計(jì)復(fù)雜的驗(yàn)證
使用validwhen來設(shè)計(jì)復(fù)雜驗(yàn)證的一個(gè)經(jīng)常的要求就是根據(jù)一個(gè)字段驗(yàn)證另外一個(gè)字段(比如, 如果你要用戶兩次輸入口令來確認(rèn)值口令一致),另外一個(gè)就是表單中的一個(gè)字段只有另外一個(gè)字段有確定值的時(shí)候才是必須輸入的。新的validwhen驗(yàn)證規(guī)則將很快被包含在1.1后的STRUTS版本中,她就是用來處理這種情況的。
validwhen 規(guī)則處理單個(gè)的變量字段,叫測試。這變量的值是一個(gè)布爾的表達(dá)式,如果驗(yàn)證有效則它必須為真。可以包含這種變量的表達(dá)式有:
u 單引號(hào)或雙引號(hào)字符串literals,
u 十進(jìn)制、十六進(jìn)制、八進(jìn)制的Integer literals,
u null與null和空字符串匹配,
u 其它可以用屬性名引用的form字段,例如customerAge,
u 可以在外部因用得索引字段, 例如childLastName[2],
u 可以默認(rèn)implicit因用得索引字段, 例如childLastName[], 她將作為被索引的字段使用同樣的索引到數(shù)組中,
The literal *這里指它包含當(dāng)前測試字段的值,
作為例子,考慮一個(gè)包含通訊地址和郵箱字段的form。如果通訊地址不為空則郵箱字段是必須的required。你能這樣定義validwhen 規(guī)則:
<field property="emailAddress" depends="validwhen">
<arg0 key="userinfo.emailAddress.label"/>
<var>
<var-name>test</var-name>
<var-value>((sendNewsletter == null) or (*this* != null))</var-value>
</var>
</field>
上面定義的意思是:如果通訊地址是空或不空時(shí)這個(gè)字段時(shí)有效的。
這里有個(gè)稍微復(fù)雜的例子,它使用了索引字段。假定有一個(gè)表單,允許用戶輸入他們希望定購的部件號(hào)和數(shù)量。類orderLine 的bean的一數(shù)組被用來在稱為orderLines 的一屬性保持輸入項(xiàng)。
If you wished to verify that every line with part number also had a quantity entered, you could do it with:
如果你希望校驗(yàn)訂單中有數(shù)量輸入得每一行,你可以這樣:
<field
property="quantity"
indexedListProperty="orderLines"
depends="validwhen">
<arg0 key="orderform.quantity.label"/>
<var>
<var-name>test</var-name>
<var-value>((orderLines[].partNumber == null) or (*this* != null))</var-value>
</var>
</field>
這里的意思是:如果相應(yīng)的partNumber 字段是空, 或這字段是不空的,則這字段是有效的。
最后一個(gè)例子,想象一表單,用戶必須輸入他們的以英寸為單位的高度,如果他們在高度在60英寸以下,則出一錯(cuò)誤。(it is an error to have checked off nbaPointGuard as a career.)
<field property="nbaPointGuard" depends="validwhen">
<arg0 key="careers.nbaPointGuard.label"/>
<var>
<var-name>test</var-name>
<var-value>((heightInInches >= 60) or (*this* == null))</var-value>
</var>
</field>
給程序員的簡單說明:
所有的比較關(guān)系必須在parens 封裝。All comparisons must be enclosed in parens.
只有兩個(gè)itme時(shí)可以and或or鏈接。
如果比較的兩item都可以轉(zhuǎn)為整數(shù),則使用numeric比較,否則使用字符串比較。 可插入驗(yàn)證器
驗(yàn)證是從validation.xml 文件中加載的,默認(rèn)的驗(yàn)證規(guī)則定義在validation.xml 文件中,默認(rèn)定義了required, mask ,byte, short, int, long, float, double, date (沒有本地支持), and a numeric range。
" mask "方式依賴于默認(rèn)值安裝要求,那意味著"required "可以完成,在"‘mask "將運(yùn)行以前"required "和" mask "方式被默認(rèn)包含進(jìn)框架中了。任何字段如果不是"required "而且是空或有零長度將跳過其他驗(yàn)證。
如果使用了Javascript 標(biāo)簽,客戶端javascript在validator‘s javascript 屬性中查找值而且產(chǎn)生一個(gè)有驗(yàn)證form方法的對象,要得到更多的關(guān)于Javascript Validator 標(biāo)簽工作細(xì)節(jié)的詳細(xì)的解釋,參閱html標(biāo)簽API參考。
"‘mask‘ "方式讓你用一正則表達(dá)式掩碼驗(yàn)證字段,它使用jakarta的正規(guī)表達(dá)式包,所有的有效性規(guī)則存儲(chǔ)在validator-rules.xml 文件,使用的主類是org.apache.regexp.RE。
validation.xml文件中的驗(yàn)證器配置范例:
<validator name="required"
classname="org.apache.struts.validator.FieldChecks"
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="mask"
classname="org.apache.struts.validator.FieldChecks"
method="validateMask"
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.invalid">
定義可插入驗(yàn)證器
方法的參數(shù)是用逗號(hào)分隔的一些類名稱列表,方法屬性需要有一個(gè)符合上面的列表的簽名。列表由以下組合而成:
java.lang.Object – 要驗(yàn)證的Bean。
org.apache.commons.validator.ValidatorAction – 當(dāng)前ValidatorAction。
org.apache.commons.validator.Field – 要驗(yàn)證的字段
org.apache.struts.action.ActionErrors – 如果驗(yàn)證錯(cuò)誤將加入ActionError的錯(cuò)誤對象javax.servlet.http.HttpServletRequest –當(dāng)前request 對象。
javax.servlet.ServletContext – 應(yīng)用的ServletContext。
org.apache.commons.validator.Validator–當(dāng)前的org.apache.commons.validator.Validator實(shí)例。
java.util.Locale – 當(dāng)前用戶的Locale。 多頁面form
字段部分有一可選的頁面屬性,它可以被設(shè)為整數(shù),頁上字段的所有驗(yàn)證小于或等于服務(wù)器端驗(yàn)證的當(dāng)前頁,頁上字段的所有驗(yàn)證小于或等于客戶端頁上所有字段的驗(yàn)證小于或等于服務(wù)器端驗(yàn)證的當(dāng)前頁驗(yàn)證的當(dāng)前頁。一個(gè)mutli-part表單需要定義頁面屬性:
<html:hidden property="page" value="1"/>。 比較兩個(gè)字段
這是一個(gè)展示你怎樣才能比較兩個(gè)字段是否有一樣的值的例子。比如“用戶改變他們的口令“一般會(huì)有口令字段和一確認(rèn)字段。
<validator name="twofields"
classname="com.mysite.StrutsValidator"
method="validateTwoFields"
msg="errors.twofields"/>
<field property="password" depends="required,twofields">
<arg0 key="typeForm.password.displayname"/>
<var>
<var-name>secondProperty</var-name>
<var-value>password2</var-value>
</var>
</field>
public static boolean validateTwoFields(
Object bean, ValidatorAction va,
Field field, ActionErrors errors, HttpServletRequest request,
ServletContext application) {
String value = ValidatorUtils.getValueAsString( bean, field.getProperty());
String sProperty2 = field.getVarValue("secondProperty");
String value2 = ValidatorUtils.getValueAsString( bean, sProperty2);
if (!GenericValidator.isBlankOrNull(value)) {
try {
if (!value.equals(value2)) {
errors.add(field.getKey(),
Resources.getActionError( application, request, va, field));
return false;
}
} catch (Exception e) {
errors.add(field.getKey(), Resources.getActionError( application, request, va, field));
return false;
}
}
} 已知的bug
Struts Validator依賴于Commons Validator包,所以問題報(bào)告和增強(qiáng)需求可能在兩個(gè)產(chǎn)品中列出。
· Struts Validator Bugzilla Reports
· Commons Validator Bugzilla Reports 變更和deprecations
新建的標(biāo)記屬性。
<html:javascript>標(biāo)記有新的屬性定義.
使用commons-validator.jar中的DTD驗(yàn)證。
當(dāng)前使用的驗(yàn)證XML文件是根據(jù)commons-validator.jar中的DTD。Struts不在為validator-rules.xml and validator.xml.單獨(dú)維護(hù)一個(gè)分離的DTD,另外,commons-validator 現(xiàn)在維護(hù)一個(gè)統(tǒng)一的validator.dtd。修改所有validator.xml文件的DTD引用為
<!DOCTYPE form-validation PUBLIC
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN"
"http://jakarta./commons/dtds/validator_1_0.dtd">
空字段。
當(dāng)前默認(rèn)在所有得基礎(chǔ)驗(yàn)證類型中忽略空白的字段,如果你要求一個(gè)字段必須輸入,那末在你的應(yīng)用的validator.xml 文件相應(yīng)的字段定義的depends屬性中添加 " required "。
新建的范圍RANGE方法.
JavaScript 和JAVA中都添加了intRange & floatRange 方法。
有條件地REQUIRED字段.
最大的修改是添加了基于其她字段的值的有條件地require驗(yàn)證的能力。它允許你定義邏輯如:“只有X字段非空的時(shí)候Y字段為’male’才有效”,這是實(shí)現(xiàn)上述邏輯的推薦方法,這種方法在1.1版后的第一版將實(shí)現(xiàn)。在1.1版中添加的Requiredif驗(yàn)證規(guī)則,將在新版中去掉。不過,如果你正準(zhǔn)備使用requiredif,這里有一個(gè)簡短的教程。
讓我們假定你有一個(gè)有3個(gè)字段的醫(yī)藥的信息表單,性別sex,懷孕測試pregnancyTest,測試結(jié)果testResult,如果性別為‘f‘ or ‘F‘,則懷孕測試pregnancyTest是required,如果pregnancyTest不是空,測試結(jié)果testResult是required。
你的validation.xml 文件的輸入項(xiàng)應(yīng)該是這樣的:
<form name="medicalStatusForm">
<field property="pregnancyTest" depends="requiredif">
<arg0 key="medicalStatusForm.pregnancyTest.label"/>
<var>
<var-name>field[0]</var-name>
<var-value>sex</var-value>
</var>
<var>
<var-name>fieldTest[0]</var-name>
<var-value>EQUAL</var-value>
</var>
<var>
<var-name>fieldValue[0]</var-name>
<var-value>F</var-value>
</var>
<var>
<var-name>field[1]</var-name>
<var-value>sex</var-value>
</var>
<var>
<var-name>fieldTest[1]</var-name>
<var-value>EQUAL</var-value>
</var>
<var>
<var-name>fieldValue[1]</var-name>
<var-value>f</var-value>
</var>
<var>
<var-name>fieldJoin</var-name>
<var-value>OR</var-value>
</var>
</field>
<field property="testResult" depends="requiredif">
<arg0 key="medicalStatusForm.testResult.label"/>
<var>
<var-name>field[0]</var-name>
<var-value>pregnancyTest</var-value>
</var>
<var>
<var-name>fieldTest[0]</var-name>
<var-value>NOTNULL</var-value>
</var>
</field>
</form>
這里有一個(gè)使用索引的屬性更復(fù)雜的例子,如果你的struts-config.xml 有這下面:
<form-bean name="dependentlistForm"
type="org.apache.struts.webapp.validator.forms.ValidatorForm">
<form-property
name="dependents"
type="org.apache.struts.webapp.validator.Dependent[]" size="10"/>
<form-property name="insureDependents" type="java.lang.Boolean" initial="false"/>
</form-bean>
這里dependentlistForm bean有l(wèi)astName,firstName,dob,coverageType四個(gè)屬性,你可以這樣定義一驗(yàn)證規(guī)則:
<form name="dependentlistForm">
<field
property="firstName" indexedListProperty="dependents" depends="requiredif">
<arg0 key="dependentlistForm.firstName.label"/>
<var>
<var-name>field[0]</var-name>
<var-value>lastName</var-value>
</var>
<var>
<var-name>fieldIndexed[0]</var-name>
<var-value>true</var-value>
</var>
<var>
<var-name>fieldTest[0]</var-name>
<var-value>NOTNULL</var-value>
</var>
</field>
<field
property="dob" indexedListProperty="dependents" depends="requiredif,date">
<arg0 key="dependentlistForm.dob.label"/>
<var>
<var-name>field[0]</var-name>
<var-value>lastName</var-value>
</var>
<var>
<var-name>fieldIndexed[0]</var-name>
<var-value>true</var-value>
</var>
<var>
<var-name>fieldTest[0]</var-name>
<var-value>NOTNULL</var-value>
</var>
</field>
<field
property="coverageType" indexedListProperty="dependents" depends="requiredif">
<arg0 key="dependentlistForm.coverageType.label"/>
<var>
<var-name>field[0]</var-name>
<var-value>lastName</var-value>
</var>
<var>
<var-name>fieldIndexed[0]</var-name>
<var-value>true</var-value>
</var>
<var>
<var-name>fieldTest[0]</var-name>
<var-value>NOTNULL</var-value>
</var>
<var>
<var-name>field[1]</var-name>
<var-value>insureDependents</var-value>
</var>
<var>
<var-name>fieldTest[1]</var-name>
<var-value>EQUAL</var-value>
</var>
<var>
<var-name>fieldValue[1]</var-name>
<var-value>true</var-value>
</var>
<var>
<var-name>fieldJoin</var-name>
<var-value>AND</var-value>
</var>
</field>
</form>
這里的意思是:
如果lastName 字段是非空的,firstName 字段required。因?yàn)樽侄蜪ndexed 為真,這它意味著lastName的indexed 必須與firstName 的索引的一樣,dob同理,除非date不為空。
如果lastName 用樣索引時(shí)的值不空, 而且非索引字段insureDependents為真,則coverageType 是only require。
你可以對字段在[n]中使用任意數(shù)字,唯一的限制是他們必須都是AND或OR,你無法混合使用。
Deprecation:
u JavaScript 和Java的range方法.
u StrutsValidator &StrutsValidatorUtil 類中的Deprecation方法 驗(yàn)證器api指南
一個(gè)簡明的Struts驗(yàn)證器API指南 可以幫助你開始。 驗(yàn)證器資源
Struts Validator: Validating Two Fields Match 作者M(jìn)att Raible。(兩個(gè)字段匹配驗(yàn)證)關(guān)于使用方法的文章。(范例部分為翻譯此文內(nèi)容)
DynaForms and the Validator 作者James Turner and Kevin Bedell。Struts Kickstart的其中一章(動(dòng)態(tài)form和驗(yàn)證器),可以自由下載PDF).
Validating user input 作者 David Winterfeldt and Ted Husted。Struts in Action的其中一章,可以自由下載(PDF)。
使用方法
作者:
丑陋 && Snowtears:經(jīng)過2周的不懈努力,閱讀了大量的資料,終于對Validator有了個(gè)初步的認(rèn)識(shí),整理了一下,淺淺的談了談寫法,希望能有一定的幫助,其中肯定有許多說的不對不準(zhǔn)確的地方,還請多指教 real_herozx@163.net
王藝:
根據(jù)以上兩位的文章正理而成 配置ruts-config.xml: 1、 添加ApplicationResources配置文件。
如:
<!-- ========== Message Resources Definitions =========================== -->
<message-resources parameter="com.dc.sibss.om.struts.ApplicationResources" />
其中com.sibss.om.struts.ApplicationResources"的部分是資源文件的路徑,此文件的作用是提供錯(cuò)誤信息的非編程定制化和多語言支持。如果我們使用中文平臺(tái)操作系統(tǒng),則默認(rèn)情況下將首先查找ApplicationResource_zh_CN.properties文件,然后是ApplicationResources_zh.properties,如果前兩個(gè)文件沒有被找到則將查找ApplicationResources.properties文件。
為了能夠在頁面上顯示錯(cuò)誤提示信息,我們還需要將以下內(nèi)容添加到ApplicationResources.properties文件的末尾:
errors.required={0} is required.
errors.minlength={0} cannot be less than {1} characters.
errors.maxlength={0} cannot be greater than {2} 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.
以上僅是struts現(xiàn)在支持的錯(cuò)誤類型的錯(cuò)誤提示信息,如果你自定義了新類型的錯(cuò)誤驗(yàn)證,則還需要在此加上你自己的內(nèi)容。
以上內(nèi)容中的{0}指的是錯(cuò)誤提交的參數(shù)。比如:當(dāng)你需要頁面上的“用戶名”不能為空時(shí)(也就是上面的errors.required),這個(gè){0}就代表“用戶名”,所以如果你沒有填寫用戶名將拋出如下錯(cuò)誤:
用戶名 is required.(你可以根據(jù)需要修改稱中文)
我們可能已經(jīng)注意到了,既然錯(cuò)誤提示信息需要配置,那么上例中“用戶名”系統(tǒng)是如何得到的呢?沒錯(cuò)!也是通過修改此配置文件,內(nèi)容如下:
visitCust.error.name.required=<br>用戶名
這樣當(dāng)“用戶名”為空時(shí),struts后臺(tái)程序?qū)⒙?lián)合以上兩處定義顯示錯(cuò)誤信息。
另外,上面的“visitCust.error.name.required”是在Validation.xml配置驗(yàn)證內(nèi)容時(shí)指定的。具體見以下介紹。
注意:一般情況下,你的系統(tǒng)只需要一個(gè)ApplicationResources文件,所以開發(fā)組的成員不要添加自己的resource文件。只有在你的項(xiàng)目分組開發(fā)時(shí)才需要使用多個(gè)ApplicationResources文件,但是,同時(shí)你的struts-config.xml文件也會(huì)有相同的數(shù)量對應(yīng)。 2、 在struts-config.xml文件中加入validator插件:
加入這個(gè)插件后你的應(yīng)用就具備使用Validator的環(huán)境,如:
<!-- ========== Plug Ins Configuration ================================== -->
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml" property="pathnames" />
</plug-in>
這里如果是想使用多個(gè)***.xml文件的話,value部分寫法如下value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml, /WEB-INF/validation1.xml , /WEB-INF/validation2.xml "
在<action-mappings>里,定義需要驗(yàn)證的畫面對應(yīng)的Action的時(shí)候要加上validate="true" 四種使用方法 1、 用Javascript在客戶端進(jìn)行驗(yàn)證
配置:在需要驗(yàn)證的JSP文件中寫入
<html:form action="/XXX" onsubmit="return validateXXXX(this);">
這里的XXX 是與要進(jìn)行驗(yàn)證的 forward name,validateXXXX (this);里面的XXXX是需要進(jìn)行驗(yàn)證的ActionForm名。
<html:javascript formName="mytestForm"/>
在validation.xml文件中寫入驗(yàn)證代碼就可以進(jìn)行基本的驗(yàn)證了。這種方法是在客戶端進(jìn)行驗(yàn)證,客戶端可以看到JAVASCRIPT部分的全代碼。安全性不高 2、 ValidatorForm的validate方法
1、validate()方法:使自己的ActionForm繼承ValidatorForm類,在里面編寫自己的方法:
public ActionErrors validate (ActionMapping mapping,HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
。。。。。。
if ( mytext.equals("aaa") ) {
//my exampleerrors.add("mytext",new ActionError("mytext.error"));
}
。。。。。。
return errors;
}
此時(shí),如果寫了這個(gè)方法,就會(huì)屏蔽掉在Validation.xml中定義的驗(yàn)證部分,換句話說就是系統(tǒng)運(yùn)行時(shí),Validation.xml里對應(yīng)此ActionForm的定義的錯(cuò)誤驗(yàn)證部分不實(shí)行,如果不寫這個(gè)方法的話,系統(tǒng)運(yùn)行時(shí)會(huì)進(jìn)行Validation.xml里對應(yīng)此ActionForm的定義的錯(cuò)誤驗(yàn)證部分的操作。此類方法是在服務(wù)器端進(jìn)行驗(yàn)證,驗(yàn)證部分代碼客戶端不可見。
2、創(chuàng)建你的ActionForm并讓它繼承org.apache.struts.validator.ValidatorForm類。創(chuàng)建你的Action實(shí)現(xiàn),并和上面定義的ActionForm關(guān)聯(lián)。這里需要注意的是,在定義此Action時(shí)一定將validate屬性設(shè)置為true,并且在你定義的ActionForm中不要實(shí)現(xiàn)它的validate方法――這就意味著你將使用ValidatorForm的validate方法,這樣才能保證你的錯(cuò)誤驗(yàn)證正常進(jìn)行。配置validation.xml文件。基本內(nèi)容如下:
<form-validation>
<!-- ========== Default Language Form Definitions ===================== -->
<formset>
<form name="custGNewForm">需要驗(yàn)證頁面上form的名字
<field property="certifiCode"需要校驗(yàn)的屬性
depends="required,maxlength">校驗(yàn)內(nèi)容
<arg0 key="prompt.certifiCode"/>ApplicationResource文件中對應(yīng)
<arg1 key="${var:maxlength}" name="maxlength" resouce="false"/>
<var>確定最長限制的長度
<var-name>maxlength</var-name>
<var-value>20</var-value>
</var>
</field>
注意:此處的arg0和arg1就代表了ApplicationResources文件中使用“{}”括起來的參數(shù)。比如:
errors.range={0} is not in the range {1} through {2}.
定義了三個(gè)參數(shù),所以你這里也要定義<arg0>、<arg1>、<arg2>三個(gè)參數(shù)才能完整的顯示錯(cuò)誤信息。
errors.maxlength={0} cannot be greater than {2} characters.
定義了0、2兩個(gè)參數(shù),所以你就需要定義<arg0>和<arg2>兩個(gè)參數(shù)。
<field property="userName"
depends="required,maxlength">
<arg0 key="prompt.userName"/>
<arg2 key="${var:maxlength}" name="maxlength" resouce="false"/>
<var>
<var-name>maxlength</var-name>
<var-value>80</var-value>
</var>
</field>
<field property="email"
depends="email">
<arg0 key="prompt.email"/>
</field>
</form>
<form name="custGNewCheckForm">
<field property="certifiCode"
depends="required">
<arg0 key="prompt.certifiCode"/>
</field>
</form>
</formset>
</form-validation>
在校驗(yàn)頁面的<body>前添加如下內(nèi)容:<html:errors/> 3、 DynaValidatorForm
不需要再寫對應(yīng)的ActionForm,只需在struts-config.xml里把自己的ActionForm進(jìn)行配置:
<form-bean name="testForm" type="org.apache.struts.validator. DynaValidatorForm">
<form-property name="mytext" type="java.lang.String"/>
<form-property name="mytextarea" type="java.lang.String"/>
<form-property name="mydatetext" type="java.lang.String"/>
</form-bean>
在form-property里設(shè)置相應(yīng)的項(xiàng)目,比如說mytext,mytextarea什么的,執(zhí)行的時(shí)候會(huì)動(dòng)態(tài)生成ActionForm,再在validation.xml里寫入所希望的驗(yàn)證代碼,就可以了。JSP文件里不需要寫入任何東西,驗(yàn)證也是在服務(wù)器端進(jìn)行,驗(yàn)證部分代碼在JSP中不可見。 4、 組合驗(yàn)證
如果使用動(dòng)態(tài)驗(yàn)證DynaValidatorForm的話,不許編寫自己的對應(yīng)的ActionForm,相應(yīng)的特殊驗(yàn)證會(huì)受到相當(dāng)程度的限制。這個(gè)時(shí)候,需要將特殊驗(yàn)證部分寫入對應(yīng)的Action,
if(mytext.equals("aaa")){//My Example
ActionErrors errors = new ActionErrors();
errors.add("***",new ActionError("***.error"));
saveErrors(request,errors);
return (mapping.findForward("false"));
}
就可以實(shí)現(xiàn)特殊驗(yàn)證了。
實(shí)際上你的FORM還可以繼承ValidatorActionForm和DynaValidatorActionForm,這兩種與他們對應(yīng)的ValidatorForm和DynaValidatorForm的唯一區(qū)別正如開篇就講到的:在struts-config.xml中查找對應(yīng)的FORM類時(shí),前者根據(jù)ACTION的PATH值,而后者使用NAME值。 范例:
Struts 驗(yàn)證器:驗(yàn)證兩個(gè)字段匹配
在使用指南中,有一節(jié)講述怎樣創(chuàng)建驗(yàn)證器來驗(yàn)證兩個(gè)字段匹配,我用這個(gè)服務(wù)器端驗(yàn)證器(象例子中顯示的那樣)做口令,確定口令驗(yàn)證。這個(gè)已經(jīng)可以正常工作了;但我還想用客戶端的javascript驗(yàn)證器來試一試。我寫了自己的程序來比較兩個(gè)字段,但他們和推薦給你的那個(gè)不同(from validator-rules.xml)。所以昨天,我補(bǔ)充了怎樣添加JavaScript方法到validator-rules.xml。 這里就是怎樣配置的的整個(gè)過程(大部分在使用指南中已經(jīng)包含了,保存JavaScript)。
怎樣添加兩個(gè)字段的驗(yàn)證器
Step 1: 生成一個(gè)包含validateTwoFields方法的類。在我的代碼重,我的類定義為ValidationUtil,他有下列方法:
public static boolean validateTwoFields(
Object bean,
ValidatorAction va,
Field field,
ActionErrors errors,
HttpServletRequest request) {
String value = ValidatorUtil.getValueAsString(bean, field.getProperty());
String sProperty2 = field.getVarValue("secondProperty");
String value2 = ValidatorUtil.getValueAsString(bean, sProperty2);
if (!GenericValidator.isBlankOrNull(value)) {
try {
if (!value.equals(value2)) {
errors.add(field.getKey(),
Resources.getActionError(request, va, field));
return false;
}
} catch (Exception e) {
errors.add(field.getKey(),
Resources.getActionError(request, va, field));
return false;
}
}
return true;
}
Step 2: 編輯 validator-rules.xml ,加入"twofields" 規(guī)則。
<validator name="twofields" classname="org.appfuse.webapp.util.ValidationUtil"
method="validateTwoFields"
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.twofields">
<javascript><![CDATA[
function validateTwoFields(form) {
var bValid = true;
var focusField = null;
var i = 0;
var fields = new Array();
oTwoFields = new twofields();
for (x in oTwoFields) {
var field = form[oTwoFields[x][0]];
var secondField = form[oTwoFields[x][2]("secondProperty")];
if (field.type == ‘text‘ ||
field.type == ‘textarea‘ ||
field.type == ‘select-one‘ ||
field.type == ‘radio‘ ||
field.type == ‘password‘) {
var value;
var secondValue;
// get field‘s value
if (field.type == "select-one") {
var si = field.selectedIndex;
value = field.options[si].value;
secondValue = secondField.options[si].value;
} else {
value = field.value;
secondValue = secondField.value;
}
if (value != secondValue) {
if (i == 0) {
focusField = field;
}
fields[i++] = oTwoFields[x][1];
bValid = false;
}
}
}
if (fields.length > 0) {
focusField.focus();
alert(fields.join(‘\n‘));
}
return bValid;
}]]></javascript>
</validator>
Step 3: 在validation.xml中為你的表單配置驗(yàn)證:
<field property="password" depends="required,twofields">
<msg name="required" key="errors.required"/>
<msg name="twofields" key="errors.twofields"/>
<arg0 key="userForm.password"/>
<arg1 key="userForm.confirmPassword"/>
<var>
<var-name>secondProperty</var-name>
<var-value>confirmPassword</var-value>
</var>
</field>
這里errors.twofields的字段 ‘{0}‘必須與字段‘{1}‘ 的值相同。第三步的一個(gè)可選的工作就時(shí)使用 XDoclet 來生成validation.xml。requires (1) 配置XDoclet (當(dāng)然)和(2) 在你的表單中添加添加一些@struts 標(biāo)簽setPassword方法。
/**
* Returns the password.
* @return String
*
* @struts.validator type="required" msgkey="errors.required"
* @struts.validator type="twofields" msgkey="errors.twofields"
* @struts.validator-args arg1resource="userForm.password"
* @struts.validator-args arg1resource="userForm.confirmPassword"
* @struts.validator-var name="secondProperty" value="confirmPassword"
*/
public String setPassword() {
return password;
}
我昨天已經(jīng)把這個(gè)作為建議發(fā)送給struts-dev郵件列表, 但還沒有收到任何消息。 |
留言 (0 留言) |
主題: 工作的規(guī)范(2005-8-17 周三) |
作者: scud |
| 鏈接地址:當(dāng)老板喜歡研發(fā)過程規(guī)范化,該怎么辦 |
| 工作的規(guī)范 |
留言 (0 留言) |
主題: http://forum./viewtopic.php?t=15346&highlight=(2005-8-16 周二) |
作者: xiaoyu |
| 鏈接地址: |
| http://forum./viewtopic.php?t=15346&highlight= |
留言 (0 留言) |
主題: 開源實(shí)現(xiàn)將為我淘得第一桶金。(2005-8-16 周二) |
作者: heweiya |
| 鏈接地址: |
冥冥中有一種感覺,呵呵,還是呀:天行鍵,君子以自強(qiáng)不息@ Lucane Groupware是一個(gè)用Java編寫的免費(fèi)的群件,設(shè)計(jì)具有高度的可擴(kuò)展性。綁定的應(yīng)用程序有即時(shí)消息,文件共享,聊天,論壇,個(gè)人注釋,共享的日歷...這個(gè)平臺(tái)是開發(fā)網(wǎng)絡(luò)應(yīng)用程序的一種簡單方法。 這兩天用了一次lucane這個(gè)協(xié)同管理軟件,感覺很不錯(cuò),應(yīng)該在項(xiàng)目管理當(dāng)中是一個(gè)很值得推薦的實(shí)現(xiàn)方案,因?yàn)樗侵С植寮降拈_發(fā),我想假如把CITIA、PTC等3D制造軟件的控件也加入,肯定是一個(gè)很好用的協(xié)同制造平臺(tái)。
世界之大,我還需要拼命的學(xué)習(xí)多種東西才能夠達(dá)到自己想要的高峰。 |
留言 (0 留言) |
主題: 我的收藏夾(J2EE部分)(2005-8-16 周二) |
作者: ben_nb |
| 鏈接地址:我的收藏夾(J2EE部分) |
| 我的收藏夾(J2EE部分) |
留言 (0 留言) |
主題: spring 的第一個(gè)例子,運(yùn)行成功(2005-8-15 周一) |
作者: zouhongwu |
| 鏈接地址: |
加油 |
留言 (0 留言) |
主題: 一些常用的Eclipse 3.0的插件(2005-8-15 周一) |
作者: sctom123 |
| 鏈接地址: |
一些常用的Eclipse 3.0的插件 1. 2.Properties Editor 編輯java的屬性文件,并可以自動(dòng)存盤為Unicode格式 http://propedit./index_en.html
3.Colorer Take 為上百種類型的文件按語法著色 http://colorer./
4.XMLBuddy 編輯xml文件 www.
5.Code Folding 加入多種代碼折疊功能(比eclipse自帶的更多) http://www./servlet/PlatformSupport
6.Easy Explorer 從eclipse中訪問選定文件、目錄所在的文件夾 http://easystruts./
7.Fat Jar 打包插件,可以方便的完成各種打包任務(wù),可以包含外部的包等 http://fjep./
8.RegEx Test 測試正則表達(dá)式 http:///stephan/archives/000028.php
9.JasperAssistant 報(bào)表插件(強(qiáng),要錢的) http://www./
10.Jigloo GUI Builder JAVA的GUI編輯插件 http:///jigloo/
11.Profiler 性能跟蹤、測量工具,能跟蹤、測量BS程序 http:///projects/eclipsecolorer/
12.AdvanQas 提供對if/else等條件語句的提示和快捷幫助(自動(dòng)更改結(jié)構(gòu)等) http://eclipsecolorer./advanqas/index.html
13.Log4j Log4j插件,提供各種和Log4j相關(guān)的任務(wù),如為方法、類添加一個(gè)logger等 http://log4e./index.php/Main_Page
14.VSSPlugin VSS插件 http:///projects/vssplugin
15.Implementors 提供跳轉(zhuǎn)到一個(gè)方法的實(shí)現(xiàn)類,而不是接中的功能(實(shí)用!) http://eclipse-tools./implementors/
16.Call Hierarchy 顯示一個(gè)方法的調(diào)用層次(被哪些方法調(diào),調(diào)了哪些方法) http://eclipse-tools./call-hierarchy/index.html
17.EclipseTidy 檢查和格式化HTML/XML文件 http://eclipsetidy./
18.Checkclipse 檢查代碼的風(fēng)格、寫法是否符合規(guī)范 http://www./content/plugins/checkclipse/checkclipse.htm
19.Hibernate Synchronizer Hibernate插件,自動(dòng)映射等 http://www./hibernatesync/
20.VeloEclipse Velocity插件 http://propsorter./
21.EditorList 方便的列出所有打開的Editor http://editorlist./
22.MemoryManager 內(nèi)存占用率的監(jiān)視 http:///memorymanager/
補(bǔ)充: 1. Easy Struts支持Struts的插件 (0.64版只支持Eclipse2.X) 是開放源代碼組織上的一個(gè)項(xiàng)目,目前最新的版本是0.64,
http:///project/showfiles.php?group_id=54542&package_id=49230 http://easystruts./
2.TomcatPlugin 支持Tomcat插件 http://www./eclipse/tomcatPlugin.html
本文引用通告地址: http://blog.csdn.net/edusaj/services/trackbacks/451183.aspx |
留言 (0 留言) |
主題: 最漂亮的XML輸出(2005-8-15 周一) |
作者: 凝血神抓 |
| 鏈接地址:最漂亮的XML輸出 |
XMLOutputter類比org.jdom.output工具包里的其他類更為復(fù)雜。僅output()這個(gè)方法就有18個(gè)不同的簽名存在。這個(gè)類里的絕大多數(shù)方法是為了使得輸出更為漂亮。 public XMLOutputter() public XMLOutputter(String indent) public XMLOutputter(String indent,boolean newlines) public XMLOutputter(String indent,boolean newlines,String encoding) public XMLOutputter(XMLOutputter referenceOutputter) 使用3個(gè)參數(shù)的構(gòu)造函數(shù)方法public XMLOutputter(String indent,boolean newlines,String encoding)可以縮排String。通常這僅僅是一些空格。默認(rèn)的構(gòu)造方法里是2個(gè)空格。第二個(gè)參數(shù)指示是否將打印新的一行。在默認(rèn)的構(gòu)造方法中是false。最后一個(gè)參數(shù)是設(shè)置編碼方式。 通過實(shí)踐設(shè)置,發(fā)現(xiàn)最漂亮的XML輸出設(shè)置是: XMLOutputter xmlOutputter=new XMLOutputter(" ",true); xmlOutputter.setTextNormalize(true); //剝離任何不需要的空格。如果不佳這句,xml文件輸出行間距離大概有兩行,非常難看 xmlOutputter.oupput(document,new FileWriter("xxx.xml"); |
留言 (0 留言) |
主題: 已經(jīng)很長時(shí)間沒有寫B(tài)LOG了(2005-8-15 周一) |
作者: heweiya |
| 鏈接地址: |
已經(jīng)有很長時(shí)間沒有寫B(tài)LOG了。只是因?yàn)檫@一段時(shí)間在寫文檔。 BLOG,感覺和自己的日記一樣,只是和日記有一個(gè)不一樣的地方,就是要改變自己成為一個(gè)開放的心態(tài)。 現(xiàn)在這一段時(shí)間可能又要開始做技術(shù)方面的開發(fā)的探索??赡蹷LOG也會(huì)多起來。但愿自己成為一個(gè)技術(shù)上的領(lǐng)袖,因?yàn)槲矣X得管理太空洞,好象是一個(gè)騙人的把戲。管理者是一個(gè)虛榮的職位,而只有掌握了技術(shù),自己才可能腳踏實(shí)地的出來自己做事。 |
留言 (0 留言) |
主題: 論面向組合子程序設(shè)計(jì)方法 之 monad(2005-8-13 周六) |
作者: ajoo |
| 鏈接地址:論面向組合子程序設(shè)計(jì)方法 之 monad |
仍然是先用oo把輪廓?jiǎng)澇鰜?,我們需要建模一個(gè)接口來圍繞它進(jìn)行組合。
因?yàn)楸疚氖顷P(guān)于co的論述,那么這個(gè)接口怎樣分析出來的就暫時(shí)忽略掉了:
| java代碼: |
|
interface Dependency{ Object getArgument(int i, Class type); Class verifyArgument(int i, Class type); Object getProperty(Object key, Class type); Class verifyProperty(Object key, Class type); }
|
這個(gè)Dependency接口由每個(gè)不同的組件調(diào)用,來解決依賴。如果解析失敗,則拋出異常。此處,我們暫時(shí)忽略異常這個(gè)細(xì)節(jié)。
getArgument負(fù)責(zé)解析一個(gè)函數(shù)參數(shù),組件告訴Dependency對象,我需要給第3個(gè)參數(shù),類型為String的解析依賴。于是就調(diào)用 getArgument(2, String.class)。
getProperty負(fù)責(zé)解析一個(gè)用某個(gè)key來標(biāo)識(shí)的屬性。比如一個(gè)javabean的property。
那兩個(gè)verify是只取得解析到的那個(gè)符合要求的組件類型,但是并不實(shí)際創(chuàng)建對象。
然后是Component接口。這里,為了名字簡短,我們不用ComponentAdapter這么惡長的名字,直接就是Component好了。
| java代碼: |
|
interface Component{ Class getType(); Object create(Dependency dep); Class verify(Dependency dep); }
|
getType()用來返回這個(gè)Component生成的對象的類型。 create用來創(chuàng)建這個(gè)對象。 verify用來保證這個(gè)對象可以被創(chuàng)建。
至于容器接口,再簡單不過了。我們都知道pico不過是個(gè)hash table,yan的容器也差不多,雖然多幾個(gè)getComponentOfType()的方法,但是大體上就是一個(gè)hash table。
| java代碼: |
|
interface Container{ Component getComponent(Object key); Component getComponentOfType(Class type); }
|
好了。oo完畢。下面來co。
首先,最簡單的Component是什么?什么也不干,直接返回一個(gè)值。
| java代碼: |
|
class ValueComponent implements Component{ private final Object v; public Class getType(){ return v==null?null:v.getClass(); } public Object create(Dependency dep){ return v; } public Class verify(Dependency dep){ return getType(); } }
|
稍微難啃點(diǎn)的,是構(gòu)造函數(shù)和工廠方法。這兩個(gè)都會(huì)調(diào)用Dependency的getArgument()來取得自己需要的參數(shù)實(shí)例。 實(shí)際上,java的reflection api里面的Method和Constructor還是有很多相似點(diǎn)的。 為了抽取共性,我們定義一個(gè)新的接口,叫做Function:
| java代碼: |
|
interface Function{ Class getReturnType(); Class[] getParameterTypes(); Object call(Object[] args); }
|
這里,我就不展現(xiàn)把Method和Constructor匹配為Function的代碼了,因?yàn)閼?yīng)該一目了然。 我們只要知道我們現(xiàn)在可以有三個(gè)函數(shù)產(chǎn)生Function對象:
| java代碼: |
|
class Functions{ static Function ctor(Constructor ctor); static Function method(Object obj, Method mtd); static Function static_method(Class type, Method mtd); }
|
當(dāng)然,還有一些輔助函數(shù), 比如:
| java代碼: |
|
static Function ctor(Class type);
|
然后是FunctionComponent。
| java代碼: |
|
class FunctionComponent implements Component{ private final Function f; public Class getType(){ return f.getReturnType(); } public Object create(Dependency dep){ final Class[] types = f.getParameterTypes(); final Object[] args = new Object[types.length]; foreach(t:types){ args[i] = dep.getArgument(i, t); } return f.call(args); } public Class verify(Dependency dep){ final Class[] types = f.getParameterTypes(); foreach(t:types){ Class arg_type = dep.verifyArgument(i, t); checkTypeMatch(types[i], arg_type); } return f.getReturnType(); } }
|
然后一個(gè)基本的component應(yīng)該是java bean的setter了,對應(yīng)pico的SetterInjectionComponentAdapter,也對應(yīng)spring的bean。
| java代碼: |
|
class BeanComponent implements Component{ private final Class type; public Class getType(){ return type; } public Object create(Dependency dep){ Object r = createInstance(); setJavaBeans(r,dep); } public Class verify(Dependency dep){ ... } }
|
具體的實(shí)現(xiàn)我省略了很多。因?yàn)闀?huì)調(diào)用java.beans的api,并且會(huì)有一些caching優(yōu)化的考慮,但是思路上很清楚,就是對每個(gè)property調(diào)用getProperty()就是了。
好,最基本的就這么幾個(gè)了(其實(shí),bean component并不是最基本的,后面我們會(huì)看到)。
下面看看都有些什么組合規(guī)則。
1。手工指定某個(gè)參數(shù)。
| java代碼: |
|
class WithArgument implements Component{ private final Component parent; private final int pos; private final Component arg; public Class getType(){ return parent.getType(); } public Object create(Dependency dep){ return parent.create(withArg(dep)); } public Class verify(Dependency dep){ return parent.verify(withArg(dep)); } private Dependency withArg(final Dependency dep){ return new Dependency(){ public Object getArgument(int i, Class type){ if(i==pos){ checkTypeMatch(type, arg); return arg.create(dep); } else return dep.getArgument(i, type); } } ... } }
|
好,通過decorate這個(gè)Dependency對象,我們得到了手工制定某個(gè)參數(shù)的能力。 這里,我們對參數(shù)仍然用Component,而不是一個(gè)簡單的Object作為這個(gè)參數(shù)的值,是因?yàn)閰?shù)本身也可能需要?jiǎng)?chuàng)建,它的依賴關(guān)系也可能需要在Dependency對象中解析。如果參數(shù)不需要?jiǎng)?chuàng)建,那么,你盡可以用ValueComponent來包裝一下。
2。手工指定property的值。跟上面的代碼非常類似,就是重載了getProperty()和verifyProperty()。
| java代碼: |
|
class WithProperty implements Component{ private final Component parent; private final Object key; private final Component prop; public Class getType(){ return parent.getType(); } public Object create(Dependency dep){ return parent.create(withProp(dep)); } public Class verify(Dependency dep){ return parent.verify(withProp(dep)); } private Dependency withProp(final Dependency dep){ return new Dependency(){ public Object getProperty(Object k, Class type){ if(k.equals(key)){ checkTypeMatch(type, prop); return prop.create(dep); } else return dep.getProperty(k, type); } } ... } }
|
3。和很多組合子一樣,map是一個(gè)相當(dāng)有用的組合規(guī)則。它負(fù)責(zé)把一個(gè)Component返回的對象作一下額外的處理,transform成另外一個(gè)對象。
| java代碼: |
|
interface Map{ Object map(Object obj); }
|
| java代碼: |
|
class MapComponent implements Component{ private final Component c; private final Map map; public Class getType(){ return null; } public Object create(Dependency dep){ return map.map(c.create(dep)); } public Class verify(Dependency dep){ c.verify(dep); return Object.class; } ... }
|
注意,這里,因?yàn)槲覀儫o法預(yù)先知道Map這個(gè)接口返回的對象會(huì)是什么類型,所以,我們讓getType()返回null來標(biāo)示這是一個(gè)動(dòng)態(tài)決定的組件類型。
4。比map更一般化一點(diǎn)的,是bind動(dòng)作。所謂bind,也是根據(jù)一個(gè)Component創(chuàng)建的對象來決定接下來返回什么動(dòng)作。不同的是,它用這個(gè)對象來產(chǎn)生另外一個(gè)Component,讓這個(gè)Component來生成一個(gè)新對象。多說無益,讓我們看代碼:
| java代碼: |
|
interface Binder{ Component bind(Object obj); }
|
| java代碼: |
|
class BoundComponent implements Component{ private final Component c; private final Binder binder; public Class getType(){ return null; } public Object create(Dependency dep){ return binder.bind(c.create(dep)).create(dep); } public Class verify(Dependency dep){ c.verify(dep); return Object.class; } ... }
|
這個(gè)Binder接口看似簡單,但是它的存在對整個(gè)co都是生死攸關(guān)的大事??梢哉f,如果沒有這個(gè)Binder, co就基本可以不存在了。 為什么這么說呢?因?yàn)檫@個(gè)binder再加上前面的那個(gè)ValueComponent代表了一種非常一般性的計(jì)算模型:monad。有一個(gè)專門的數(shù)學(xué)分支:組論,就是研究monad的。 它雖然不是放之四海皆準(zhǔn)的計(jì)算模型,比如,有比它更為一般性的Arrow模型。但是,用它幾乎可以描述我們一般所遇到的大量問題。
除了前面的幾個(gè)基本組合子之外,幾乎所有的組合子,如果我們愿意,都可以從這個(gè)bind推衍出來。比如上面的map,如果用簡潔點(diǎn)的函數(shù)式語法來表述的話(原諒我還是忍不住用函數(shù)式,java的語法就象一砣一砣屎一樣壓得我喘不過氣來)
| java代碼: |
|
map(a, f) = bind (a, \x->value(f(x)));
|
這個(gè)代碼的意思是說,你可以很輕易地把一個(gè)Map對象adapt到Binder對象,只要在bind函數(shù)里面調(diào)用:
| java代碼: |
|
return new ValueComponent(map.map(v));
|
就行了。
后面的很多組合子,比如對一個(gè)組件生成的對象調(diào)用某個(gè)方法,設(shè)置一些java bean setter,都是從這個(gè)bind組合子衍生出來的。
好了,今天時(shí)間緊迫,到此告一段落吧。 |
留言 (0 留言) |
主題: maven資料收集(2005-8-12 周五) |
作者: monkeyhero |
| 鏈接地址: |
1、執(zhí)行時(shí)提示為???的問題 這個(gè)問題其實(shí)也就是中文問題,在Maven 1.0中其實(shí)已經(jīng)將黃東的漢化版融入進(jìn)去了,只是在融入中文的時(shí)候有一個(gè)小的失誤。大家到%HAVEN_HOME%\lib目錄下著到maven.jar文件,在這個(gè)壓縮文件中的“org\apache\maven\messages”下有一個(gè)messages_zh_CN.properties中文消息文件,解壓出來,用java自帶的工具native2ascii messages_zh_CN.properties messages_zh_CN1.properties轉(zhuǎn)化編碼,再將新的文件放回原處。
2、關(guān)于無法連接到遠(yuǎn)程repository庫進(jìn)行下載和編譯速度慢的問題。 在默認(rèn)的情況下Maven的遠(yuǎn)程庫為ibibio這個(gè)網(wǎng)站,不知道為什么這個(gè)網(wǎng)站在中國被封掉了!所有無法下載,不過我們可以通過修改每個(gè)項(xiàng)目中的project.properties文件,在其中加入這樣一行maven.repo.remote = http://public./pub/maven,這樣就代表這個(gè)項(xiàng)目中的遠(yuǎn)程庫可以到public./pub/maven這個(gè)地方下載。當(dāng)然如果我們不想每個(gè)項(xiàng)目都更改的話,可以直接修改maven.jar中的defaults.properties文件,將其修改為上面這樣。 同時(shí)對于在一個(gè)公司內(nèi)的開發(fā),我們沒有必要每個(gè)開發(fā)人員都到外網(wǎng)上下載,我們建立一個(gè)repository遠(yuǎn)程庫網(wǎng)站就可以了,比如如果我們用Window IIS的話,我們只需要在我們的將建立一個(gè)web目錄,將我們下載好的Repository文件夾下的所有的目錄拷貝到這個(gè)web目錄就好了。如我們建立的這個(gè)web目錄對應(yīng)的IIS虛擬目錄為http://192.168.1.1/Maven/Reppository,那么我們只需要將開發(fā)人員的maven.repo.remote設(shè)置為http://192.168.1.1/Maven/Reppository就好了,這樣我們一來是統(tǒng)一了我們的jar版本,二來我們開發(fā)人員在下載所需要的文件也就快多了。 同時(shí)對應(yīng)在編譯速度慢還有一個(gè)原因是,在第一次編譯時(shí)需要下載,同時(shí),我們在編譯的過程中需要檢查jar的版本,對于下載jar,這個(gè)動(dòng)作只是在第一次的時(shí)候會(huì)執(zhí)行,在后面的時(shí)候Maven只會(huì)檢查是否有最新版本的jar,如果有才會(huì)下載。我想檢查jar版本對于一個(gè)團(tuán)隊(duì)的開發(fā)是必要的吧! |
留言 (0 留言) |
主題: JNDI命名和目錄服務(wù)器(2005-8-12 周五) |
作者: Tracylau |
| 鏈接地址: |
命名服務(wù)器,它把名稱和對象關(guān)聯(lián)(綁定)起來;它提供根據(jù)一個(gè)命名查找對象的工具。 目錄服務(wù)器,是擴(kuò)展和提高的命名服務(wù)器;它為使用屬性提供了目錄對象的操作。 JNDI由兩部分組成:客戶端API和服務(wù)技術(shù)接口(Service Provider Interfae SPI)??蛻舳薃PI允許JAVA代碼執(zhí)行目錄操作;SPI是一個(gè)命名和目錄服務(wù)器供應(yīng)商能夠插入插件的接口。
JNDI的命名類型:1,原子命名,"/etc/fstab",etc和fstab是原子命名。 2,復(fù)合命名,"etc/fstab"就是一個(gè)復(fù)合命名。 |
留言 (0 留言) |
主題: 論面向組合子程序設(shè)計(jì)方法 之 重構(gòu)(2005-8-12 周五) |
作者: ajoo |
| 鏈接地址:論面向組合子程序設(shè)計(jì)方法 之 重構(gòu) |
迄今,發(fā)現(xiàn)典型的幾種疑問是: 1。組合子的設(shè)計(jì)要求正交,要求最基本,這是不是太難達(dá)到呢? 2。面對一些現(xiàn)實(shí)中更復(fù)雜的需求,組合子怎樣scale up呢?
其實(shí),這兩者都指向一個(gè)答案:重構(gòu)。
要設(shè)計(jì)一個(gè)完全正交,原子到不可再分的組合子,也許不是總是那么容易。但是,我們并不需要一開始就設(shè)計(jì)出來完美的組合子設(shè)計(jì)。
比如,我前面的logging例子,TimestampLogger負(fù)責(zé)給在一行的開頭打印當(dāng)前時(shí)間。 然后readonly提出了一個(gè)新的需要:打印調(diào)用這個(gè)logger的那個(gè)java文件的類名字和行號(hào)。
分析這個(gè)需求,可以發(fā)現(xiàn),兩者都要求在一行的開始打印一些東西。似乎有些共性. 這個(gè)"在行首打印一些前綴"就成了一個(gè)可以抽象出來的共性.于是重構(gòu):
| java代碼: |
|
interface Factory{ String create(); } class PrefixLogger implements Logger{ private final Logger logger; private final Factory factory; private boolean freshline = true;
private void prefix(int lvl){ if(freshline){ Object r = factory.create(); if(r!=null) logger.print(lvl, r); freshline = false; } } public void print(int lvl, String s){ prefix(lvl); logger.print(lvl, s); } public void println(int lvl, String s){ prefix(lvl); logger.println(lvl, s); freshline = true; } public void printException(int lvl, Throwable e){ prefix(lvl); logger.printException(lvl, e); freshline = true; } }
|
這里,F(xiàn)actory接口用來抽象往行首打印的前綴。這個(gè)地方之所以不是一個(gè)String,是因?yàn)榭紤]到生成這個(gè)前綴可能是比較昂貴的(比如打印行號(hào),這需要?jiǎng)?chuàng)建一個(gè)臨時(shí)異常對象)
另外,真正的Logger接口,會(huì)負(fù)責(zé)打印所有的原始類型和Object類型,例子中我們簡化了這個(gè)接口,為了演示方便。
然后,先重構(gòu)timestamp:
| java代碼: |
|
class TimestampFactory implements Factory{ private final DateFormat fmt; public String create(){ return fmt.format(new Date()); } }
|
這樣,就把timestamp和“行首打印”解耦了出來。
下面添加TraceBackFactory,負(fù)責(zé)打印當(dāng)前行號(hào)等源代碼相關(guān)信息。
| java代碼: |
|
interface SourceLocationFormat{ String format(StackTraceElement frame); } class TraceBackFactory implements Factory{ private final SourceLocationFormat fmt; public String create(){ final StackTraceElement frame = getNearestUserFrame(); if(frame!=null) return fmt.format(frame); else return null; } private StackTraceElement getNearestUserFrame(){ final StackTraceElement[] frames = new Throwable().getStackTrace(); foreach(frame: frames){ if(!frame.getClassName().startsWith("org.mylogging")){ //user frame return frame; } } return null; } }
|
具體的SourceLocationFormat的實(shí)現(xiàn)我就不寫了。
注意,到現(xiàn)在為止,這個(gè)重構(gòu)都是經(jīng)典的oo的思路,劃分責(zé)任,按照責(zé)任定義Factory, SourceLocationFormat等等接口,依賴注入等。完全沒有co的影子。
這也說明,在co里面,我們不是不能采用oo,就象在oo里面,我們也可以圍繞某個(gè)接口按照co來提供一整套的實(shí)現(xiàn)一樣,就象在oo里面,我們也可以在函數(shù)內(nèi)部用po的方法來實(shí)現(xiàn)某個(gè)具體功能一樣。
下面開始對factory做一些co的勾當(dāng): 先是最簡單的:
| java代碼: |
|
class ReturnFactory implements Factory{ private final String s; public String create(){return s;} }
|
然后是兩個(gè)factory的串聯(lián),
| java代碼: |
|
class ConcatFactory implements Factory{ private final Factory[] fs; public String create(){ StringBuffer buf = new StringBuffer(); foreach(f: fs){ buf.append(f.create()); } return buf.toString(); } }
|
最后,我們把這幾個(gè)零件組合在一起:
| java代碼: |
|
Logger myprefix(Logger l){ Factory timestamp = new TimestampFactory(some_date_format); Factory traceback = new TraceBackFactory(some_location_format); Factory both = new ConcatFactory( timestamp, new ReturnFactory(" - "), traceback, new ReturnFactory(" : ") ); return new PrefixLogger(both, l); }
|
如此,基本上,在行首添加?xùn)|西的需求就差不多了,我們甚至也可以在行尾添加?xùn)|西,還可以重用這些factory的組合子。
另一點(diǎn)我想說明的是:這種重構(gòu)是相當(dāng)局部的,僅僅影響幾個(gè)組合子,而并不影響整個(gè)組合子框架。
真正影響組合子框架的,是Logger接口本身的變化。假設(shè),readonly提出了一個(gè)非常好的意見:printException應(yīng)該也接受level,因?yàn)槲覀儜?yīng)該也可以選擇一個(gè)exception的重要程度。
那么,如果需要做這個(gè)變化,很不幸的是,所有的實(shí)現(xiàn)這個(gè)接口的類都要改變。
這是不是co的一個(gè)缺陷呢?
我說不是。 即使是oo,如果你需要改動(dòng)接口,所有的實(shí)現(xiàn)類也都要改動(dòng)。co對這種情況,其實(shí)還是做了很大的貢獻(xiàn)來避免的: 只有原子組合子需要實(shí)現(xiàn)這個(gè)接口,而派生的組合子和客戶代碼,根本就不會(huì)被波及到。 而co相比于oo,同樣面對相同復(fù)雜的需求,往往原子組合子的數(shù)目遠(yuǎn)遠(yuǎn)小于實(shí)際上要實(shí)現(xiàn)的語義數(shù),大量的需求要求的語義,被通過組合基本粒子來實(shí)現(xiàn)。也因此會(huì)減少直接實(shí)現(xiàn)這個(gè)接口的類的數(shù)目,降低了接口變化的波及范圍。
那么,這個(gè)Logger接口是怎么來的呢?
它的形成來自兩方面:
1。需求。通過oo的手段分配責(zé)任,最后分析出來的一個(gè)接口。這個(gè)接口不一定是最簡化的,因?yàn)樗耆峭獠啃枨篁?qū)動(dòng)的。
2。組合子自身接口簡單性和完備性的需要。有些時(shí)候,我們發(fā)現(xiàn),一個(gè)組合子里面如果沒有某個(gè)方法,或者某個(gè)方法如果沒有某個(gè)參數(shù),一些組合就無法成立。這很可能說明我們的接口不是完備的。(比如那個(gè)print函數(shù))。 此時(shí),就需要改動(dòng)接口,并且修改原子組合子的實(shí)現(xiàn)。 因?yàn)檫@個(gè)變化完全是基于組合需求的完備性的,所以是co方法本身帶來的問題,而不能推諉于oo設(shè)計(jì)出來的接口。 也因?yàn)槿绱?,基本組合子個(gè)數(shù)的盡量精簡就是一個(gè)目標(biāo)。能夠通過基本組合子組合而成的,就可以考慮不要直接實(shí)現(xiàn)這個(gè)接口。 當(dāng)然,這里面仍然有個(gè)權(quán)衡: 通過組合出來的不如直接實(shí)現(xiàn)的直接,可理解性,甚至可調(diào)試性,性能都會(huì)有所下降。 而如果選擇直接實(shí)現(xiàn)接口,那么就要做好接口一旦變化,就多出一個(gè)類要改動(dòng)這個(gè)類的心理準(zhǔn)備。
如何抉擇,沒有一定之規(guī)。
而因?yàn)?和2的目標(biāo)并不完全一致,很多時(shí)候,我們還需要在1和2之間架一個(gè)adapter以避免兩個(gè)目標(biāo)的沖突。
比如說,實(shí)際使用中,我可能希望Logger接口提供不要求level的println函數(shù),讓它的缺省值取INFO就好了。
但是,這對組合子的實(shí)現(xiàn)來說卻是不利的。這時(shí),我們也許就要把這個(gè)實(shí)現(xiàn)要求的Logger接口和組合子的Logger接口分離開來。(比如把組合子單獨(dú)挪到一個(gè)package中)。
Logger這個(gè)例子是非常簡單的,它雖然來自于實(shí)際項(xiàng)目,但是項(xiàng)目對logging的需求并不是太多,所以一些朋友提出了一些基于實(shí)際使用的一些問題,我只能給一個(gè)怎么做的大致輪廓,手邊卻沒有可以運(yùn)行的程序。
那么,下面一個(gè)例子,我們來看看一個(gè)我經(jīng)過了很多思考比較完善了的ioc容器的設(shè)計(jì)。這個(gè)設(shè)計(jì)來源于yan container。
先說一下ioc容器的背景知識(shí)。
所謂ioc容器,是一種用來組裝用ioc模式(或者叫依賴注射)設(shè)計(jì)出來的類的工具。 一個(gè)用ioc設(shè)計(jì)出來的類,本身對ioc容器是一無所知的。使用它的時(shí)候,可以根據(jù)實(shí)際情況選擇直接new,直接調(diào)用setter等等比較直接的方法,但是,當(dāng)這樣的組件非常非常多的時(shí)候,用一個(gè)ioc容器來統(tǒng)一管理這些對象的組裝就可以被考慮。
拿pico作為例子,對應(yīng)這樣一個(gè)類:
| java代碼: |
|
class Boy{ private final Girl girl; public Boy(Girl g){ this.girl = g; } ... }
|
我們自然可以new Boy(new Girl());
沒什么不好的。
但是,如果這種需要組裝的類太多,那么這個(gè)組裝就變成一件累人的活了。
于是,pico container提供了一個(gè)統(tǒng)一管理組建的方法:
| java代碼: |
|
picocontainer container = new DefaultContainer(); container.registerComponentImplementation(Boy.class); container.registerComponentImplementation(Girl.class);
|
這個(gè)代碼,很可能不是直接寫在程序里面,而是先讀取配置文件或者什么東西,然后動(dòng)態(tài)地調(diào)用這段代碼。
最后,使用下面的方法來取得對象:
| java代碼: |
|
Object obj = container.getComponentInstance(Boy.class);
|
注意,這個(gè)container.getXXX,本身是違反ioc的設(shè)計(jì)模式的,它主動(dòng)地去尋找某個(gè)組件了。所以,組件本身是忌諱調(diào)用這種api的。如果你在組件級別的代碼直接依賴ioc容器的api,那么,恭喜你,你終于成功地化神奇為腐朽了。
這段代碼,實(shí)際上應(yīng)該出現(xiàn)在系統(tǒng)的最外圍的組裝程序中。
當(dāng)然,這是題外話。
那么,我們來評估一下pico先,
1。讓容器自動(dòng)尋找符合某個(gè)類型的組件,叫做auto-wiring。這個(gè)功能方便,但是不能scale up。一旦系統(tǒng)復(fù)雜起來,就會(huì)造成一團(tuán)亂麻,尤其是有兩個(gè)組件都符合這個(gè)要求的時(shí)候,就會(huì)出現(xiàn)二義性。所以,必須提供讓配置者或者程序員顯示指定使用哪個(gè)組件的能力。所謂manual-wire。 當(dāng)然,pico實(shí)際上是提供了這個(gè)能力的,它允許你使用組件key或者組件類型來顯示地給某個(gè)組件的某個(gè)參數(shù)或者某個(gè)property指定它的那個(gè)girl。
但是,pico的靈活性就到這里了,它要求你的這個(gè)girl必須被直接登記在這個(gè)容器中,占用一個(gè)寶貴的全局key,即使這個(gè)girl只是專門為這個(gè)body臨時(shí)制造的夏娃。
在java中,遇到這種情況:
| java代碼: |
|
void A createA(){ B b = new B(); return new A(b,b); }
|
我們只需要把b作為一個(gè)局部變量,構(gòu)造完A,b就扔掉了。然而,pico里面這不成,b必須被登記在這個(gè)容器中。這就相當(dāng)于你必須要把b定義成一個(gè)全局變量一樣。 pico的對應(yīng)代碼:
| java代碼: |
|
container.registerComponent("b" new CachingComponentAdapter(new ConstructorInjectionComponentAdapter(B.class))); container.registerComponent("a", new ConstructorInjectionComponentAdapter(A.class));
|
這里,為了對應(yīng)上面java代碼中的兩個(gè)參數(shù)公用一個(gè)b的實(shí)例的要求,必須把a(bǔ)登記成一個(gè)singleton。CachingComponentAdapter負(fù)責(zé)singleton化某個(gè)組件,而ConstructorInjectionComponentAdapter就是一個(gè)調(diào)用構(gòu)造函數(shù)的組建匹配器。
當(dāng)然,這樣做其實(shí)還是有麻煩的,當(dāng)container不把a(bǔ)登記成singleton的時(shí)候(pico缺省都登記成singleton,但是你可以換缺省不用singleton的container。),麻煩就來了。
大家可以看到,上面的createA()函數(shù)如果調(diào)用兩次,會(huì)創(chuàng)建兩個(gè)A對象,兩個(gè)B對象,而用這段pico代碼,調(diào)用兩次getComponentInstance("a"),會(huì)生成兩個(gè)A對象,但是卻只有一個(gè)B對象!因?yàn)閎被被迫登記為singleton了。
2。pico除了支持constructor injection,也支持setter injection甚至factory method injection。(對最后一點(diǎn)我有點(diǎn)含糊,不過就假設(shè)它支持)。所以,跟spring對比,除了沒有一個(gè)配置文件,life-cycle不太優(yōu)雅之外,什么都有了。
但是,這就夠了嗎?如果我們把上面的那個(gè)createA函數(shù)稍微變一下:
| java代碼: |
|
A createA(){ B b = new B(); return new A(b, b.createC(x_component)); }
|
現(xiàn)在,我們要在b組件上面調(diào)用createC()來生成一個(gè)C對象。完了,我們要的既不是構(gòu)造函數(shù),也不是工廠方法,而是在某個(gè)臨時(shí)組件的基礎(chǔ)上調(diào)用一個(gè)函數(shù)。
缺省提供的幾個(gè)ComponentAdapter這時(shí)就不夠用了,我們被告知要自己實(shí)現(xiàn)ComponentAdapter。
實(shí)際上,pico對很多靈活性的要求的回答都是:自己實(shí)現(xiàn)ComponentAdapter。
這是可行的。沒什么是ComponentAdapter干不了的,如果不計(jì)工作量的話。
一個(gè)麻煩是:我們要直接調(diào)用pico的api來自己解析依賴了。我們要自己知道是調(diào)用container.getComponentInstance("x_component")還是container.getComponentInstance(X.class)。 第二個(gè)麻煩是:降低了代碼重用。自己實(shí)現(xiàn)ComponentAdapter就得自己老老實(shí)實(shí)地寫,如果自己的component adapter也要?jiǎng)討B(tài)設(shè)置java bean setter的話,甭想直接用SetterInjectionComponentAdapter,好好看java bean的api吧。
其實(shí),我們可以看出,pico的各種ComponentAdapter正是正宗的decorator pattern。什么CachingComponentAdapter,什么SynchronizedComponentAdapter,都是decorator。
但是,這也就是decorator而已了。因?yàn)闆]有圍繞組合子的思路開展設(shè)計(jì),這些decorator顯得非常隨意,沒有什么章法,沒辦法支撐起整個(gè)的ComponentAdapter的架構(gòu)。
下一章,我們會(huì)介紹yan container對上面提出的問題以及很多其他問題的解決方法。
yan container的口號(hào)是:只要你直接組裝能夠做到的,容器就能做到。 不管你是不是用構(gòu)造函數(shù),靜態(tài)方法,java bean,構(gòu)造函數(shù)然后再調(diào)用某個(gè)方法,等等等等。 而且yan container的目標(biāo)是,你幾乎不用自己實(shí)現(xiàn)component adapter,所有的需求,都通過組合各種已經(jīng)存在的組合子來完成。
對我們前面那個(gè)很不厚道地用來刁難pico的例子,yan的解決方法是:
| java代碼: |
|
b_component = Components.ctor(B.class).singleton(); a_component = Components.ctor(A.class) .withArgument(0, b_component) .withArgument(1, b_component.method("createC"));
|
b_component不需要登記在容器中,它作為局部component存在。 是不是非常declarative呢?
下一節(jié),你會(huì)發(fā)現(xiàn),用面向組合子的方法,ioc容器這種東西真的不難。我們不需要仔細(xì)分析各種需求,精心分配責(zé)任。讓我們再次體驗(yàn)一下吊兒郎當(dāng)不知不覺間就天下大治的感覺吧。
待續(xù)。 |
留言 (0 留言) |
主題: 通過XML描述下拉框的級連選擇處理(2005-8-11 周四) |
作者: dingyd |
| 鏈接地址: |
| java代碼: |
|
<xs:element name="onchange" minOccurs="0"> <xs:complexType> <xs:sequence> <xs:element name="onchange-func" type="xs:string"/> <xs:element name="onchange-process" type="xs:string"/> <xs:element name="param-name" type="xs:string"/> <xs:element name="dest-name" type="xs:string"/> <xs:element name="dest-desc" type="xs:string"/> <xs:element name="dest-value" type="xs:string"/> <xs:element name="delete-name" type="xs:string" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element>
|
onchange-func: 要觸發(fā)的JS函數(shù) onchange-process: 通過XMLHTTP調(diào)用的ACTION param-name: 調(diào)用ACTION要用到的參數(shù)(目前只用一個(gè)) dest-name: 目的選擇框名稱 dest-desc: 目的下拉框的描述 dest-value: 目的下拉框的值 delete-name: 對應(yīng)該CHANGE事件要?jiǎng)h除的其他相關(guān)下拉框的內(nèi)容.
呵呵: 好久沒更新了,今天把以往做的不好的級連下拉框處理做的優(yōu)化,深感一個(gè)人的力量太小,找個(gè)時(shí)間把代碼整理后開源出來,也算是對自己的一個(gè)交代. |
留言 (0 留言) |
主題: DBCP連接池測試用例(8月修正版)(2005-8-11 周四) |
作者: cnsdl |
| 鏈接地址: |
[color=red系統(tǒng):[/color] WIN2000>>APACHE TOMCAT5.0.28(要求5.0及以上版本)>>SQL SERVER 2000 系統(tǒng)用的是SQL SERVER 庫中的Northwind。采用第四類驅(qū)動(dòng),驅(qū)動(dòng)類放到D:\testpool\WEB-INF\lib中。 保證TOMCAT和SQL SERVER正常運(yùn)行。 [1]在%TOMCAT_HOME%\conf\Catalina\localhost\目錄下建一個(gè)testPool.xml文件: <?xml version=‘1.0‘ encoding=‘utf-8‘?> <Context docBase="D:/testpool" path="/testpool" privileged="true" workDir="work\Catalina\localhost\testpool"> <Resource type="javax.sql.DataSource" auth="Container" name="jdbc/northwind"/> <ResourceParams name="jdbc/northwind"> <parameter> <name>maxWait</name> <value>5000</value> </parameter> <parameter> <name>maxActive</name> <value>4</value> </parameter> <parameter> <name>password</name> <value>12345</value> </parameter> <parameter> <name>url</name> <value>jdbc:microsoft:sqlserver://10.0.0.168:1433;databaseName=Northwind</value> </parameter> <parameter> <name>driverClassName</name> <value>com.microsoft.jdbc.sqlserver.SQLServerDriver</value> </parameter> <parameter> <name>maxIdle</name> <value>2</value> </parameter> <parameter> <name>username</name> <value>sa</value> </parameter> </ResourceParams> </Context> [2]在D:\testpool\WEB-INF\下面建立一個(gè)web.xml文件: <?xml version="1.0" encoding="ISO-8859-1"?>
<web-app 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" version="2.4"> <!--ConnectionPool--> <resource-ref> <res-ref-name>jdbc/northwind</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </web-app> [3]在D:\testpool\下面建立測試文件index.jsp <%@ page contentType="text/html;charset=GB2312"%> <%@ page import="java.sql.*"%> <%@ page import="javax.sql.*"%> <%@ page import="javax.naming.*"%> <%@ page session="false" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <title>tetst connection pool</title> <% out.println("我的測試開始"); DataSource ds = null;
try{ InitialContext ctx=new InitialContext(); ds=(DataSource)ctx.lookup("java:comp/env/jdbc/northwind"); Connection conn = ds.getConnection(); Statement stmt = conn.createStatement();
String strSql = " select * from Categories"; ResultSet rs = stmt.executeQuery(strSql); while(rs.next()){ out.println(rs.getString(1)); } out.println("我的測試結(jié)束"); } catch(Exception ex){ out.print("出現(xiàn)例外,信息是:"+ex.getMessage()); ex.printStackTrace(); } %> </head> <body> </body> </html> [4]補(bǔ)充:做配置時(shí)大體要搞清楚類似的幾個(gè)問題,就是考慮WWW原則,要建或改什么文件(WHO),在那里做(WHERE),做什么(WHAT).與之對應(yīng)的是: WHO WHERE WHAT testPool.xml %TOMCAT_HOME%\conf\Catalina\localhost\ 見第一步 web.xml(名字固定) D:\testpool\WEB-INF\web.xml 見第二步 index.jsp D:\testpool\index.jsp 見第三步 [5]如果使用hibernate,除作上面的外還需要更改hibernate.cfg.xml文件: <?xml version=‘1.0‘ encoding=‘UTF-8‘?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 2.0//EN" "http://hibernate./hibernate-configuration-2.0.dtd">
<!-- DO NOT EDIT: This is a generated file that is synchronized --> <!-- by MyEclipse Hibernate tool integration. --> <hibernate-configuration>
<session-factory> <!-- properties <property name="connection.username">sa</property> <property name="connection.url"> jdbc:microsoft:sqlserver://10.0.0.168:1433;DataBaseName=cw_scene </property> <property name="dialect"> net.sf.hibernate.dialect.SQLServerDialect </property> <property name="connection.password">12345</property> <property name="connection.driver_class"> com.microsoft.jdbc.sqlserver.SQLServerDriver </property> <property name="hibernate.jdbc.fetch_size">50</property> <property name="hibernate.jdbc.batch_size">25</property> --> <!-- properties -->
<property name="connection.datasource"> java:comp/env/jdbc/testpool </property> <property name="dialect"> net.sf.hibernate.dialect.SQLServerDialect </property> <property name="hibernate.connection.provider_class"> net.sf.hibernate.connection.DatasourceConnectionProvider </property> <property name="hibernate.jdbc.fetch_size">50</property> <property name="hibernate.jdbc.batch_size">25</property>
<!-- mapping files --> <mapping resource="com/scenechina/table/Imgpos.hbm.xml" />
</session-factory>
</hibernate-configuration> |
留言 (0 留言) |
主題: 序列化(2005-8-10 周三) |
作者: Tracylau |
| 鏈接地址: |
序列化是將一個(gè)JAVA對象轉(zhuǎn)化為一個(gè)描述該對象的位塊(bit-blob);對象一旦變成了bit-blob后,就可以發(fā)送到任何硬盤/網(wǎng)絡(luò)上;準(zhǔn)備再使用該對象時(shí),要將bit-blob解序列化為JAVA對象方可使用。 變?yōu)榭尚蛄谢?,只要?shí)現(xiàn)java.lang.Serializable接口。 用靜態(tài)關(guān)鍵字標(biāo)識(shí)的對象不能序列化,并且在解序列是無效的。
tracylau 2005.8.10 |
留言 (0 留言) |
主題: RMI值傳遞(2005-8-10 周三) |
作者: Tracylau |
| 鏈接地址: |
用RMI請求一個(gè)方法時(shí),傳遞遠(yuǎn)程對象的所有參數(shù)是通過值傳遞的。當(dāng)調(diào)用目標(biāo)方法時(shí),將所有參數(shù)從一臺(tái)機(jī)器傳到另一臺(tái)機(jī)器。 如果要將對象在網(wǎng)絡(luò)上傳遞的話,則要將對象序列化。 see next==>
tracylau 2005.8.10 |
留言 (0 留言) |
主題: 開頭之二(2005-8-10 周三) |
作者: floating |
| 鏈接地址: |
誰說誰是誰的魚 誰說把秘密藏在天空里 有沒有前提 有沒有意義 失眠會(huì)不會(huì)弄丟了記憶 會(huì)不會(huì)想起 會(huì)不會(huì)涕泣
從熒幕上看著巨大的飛機(jī) 從左邊看著你右邊的鼻息 從腦海里看著對你微弱的回憶 從鏡子里看著自己
35mm的攝像頭 35cm的距離 三分鐘的休息 夾雜著所謂從前的痕跡 |
留言 (0 留言) |
主題: 論面向組合子程序設(shè)計(jì)方法 之 oracle(2005-8-10 周三) |
作者: ajoo |
| 鏈接地址:論面向組合子程序設(shè)計(jì)方法 之 oracle |
不少朋友說我的闡述很蒼白無力。這讓我很苦惱。我確實(shí)是拚了命地想把問題說清楚,我也有實(shí)際non-trivial的項(xiàng)目經(jīng)驗(yàn),怎么就說不明白呢?哎!
所以,還是不能不多羅嗦一下,希望能夠再闡述得明白一點(diǎn)。
其實(shí),所謂co,有心的朋友也許能夠感覺到,它很象是設(shè)計(jì)一門語言。 它有順序/分支,有函數(shù)調(diào)用,異常處理,基本上一個(gè)程序設(shè)計(jì)語言有的東西它都有了。這些順序/分支作為語言的基礎(chǔ)設(shè)施,而一些應(yīng)對具體需求的原子操作,(比如WriterLogger,比如NeptuneExceptionLogger)則可以看作是語言的擴(kuò)展或者庫。
只不過,c/c++/java是有編譯器來把源代碼轉(zhuǎn)化成目標(biāo)代碼。而co的組合子則是利用了宿主語言(比如java)本身的能力來實(shí)現(xiàn)各個(gè)組合子的語義??梢哉f,co是在設(shè)計(jì)一門語言中的語言。
最近這段時(shí)間,流行過一陣LOP(language oriented programming),就是用domain-specific-language來處理一些特定的domain需求。 為什么會(huì)有這種說法呢?還是因?yàn)閐omain的需求多變靈活,不容易琢磨,所以人們發(fā)現(xiàn)用一個(gè)靈活的語言比用一些功能相對死板的庫更容易對付。 但是dsl的實(shí)現(xiàn)不是那么容易的。而co是不是可以說給我們提供了一個(gè)相對廉價(jià)的創(chuàng)建自己的domain specific language的途徑呢? 我們雖然不能說
| java代碼: |
|
if level > 1 then logger1 else logger2
|
至少可以退而求其次,寫出
| java代碼: |
|
ignore(1, logger1, logger2);
|
當(dāng)然,這種子語言相比于宿主語言,缺乏調(diào)試器的幫助,缺乏編譯器的優(yōu)化,缺乏各種ide的支持,可用性程度是大大不如的。
但是,它也有它的好處,那就是,不用額外進(jìn)行一次編譯;寫出來的東西和宿主語言無縫集成;可以自動(dòng)利用宿主語言里面的一切設(shè)施。等等。
那么如果把co作為一個(gè)語言來考慮,是不是會(huì)給我們一些別的啟示呢?
oz曾經(jīng)質(zhì)疑,所謂的co,怎樣決定基本的組合子?怎么樣才知道組合子夠用了?
那么,設(shè)計(jì)語言的時(shí)候,怎么設(shè)計(jì)基本的語言設(shè)施?怎么樣知道這個(gè)設(shè)施是不足,還是太多呢? 這是個(gè)大話題,語言設(shè)計(jì)非常有爭議性和主觀性。但是,也仍然是有些共性的。比如,幾乎所有的語言都支持順序,if/else,遞歸/循環(huán),函數(shù)定義等。相當(dāng)多我們熟悉的語言還支持異常處理,字符串,整數(shù)等。
我們難道不能從這里借鑒一些東西?如果我們把基本的nop, 順序,分支作為啟動(dòng)co的基本要求,這算不算是一個(gè)可以遵循的guidline呢?
另外,不同的語言,根據(jù)它所面向的領(lǐng)域,還有一些不同的內(nèi)建操作,比如perl,面向文本處理,所以內(nèi)建了regexp,而c/c++因?yàn)橹苯用鎸C(jī)器硬件模型,所以提供了指針。 那么,根據(jù)我們的組合子所要面對的應(yīng)用類型,我們也可以預(yù)先定義一些內(nèi)建的原始組合子,比如那個(gè)WriterLogger。
一般來說,對general purpose的語言,設(shè)計(jì)的基礎(chǔ)設(shè)施都是非常”基礎(chǔ)“的,基礎(chǔ)到幾乎不會(huì)有什么設(shè)施是多余的。同時(shí),也基礎(chǔ)到一般人都可以沒有什么困難地掌握基本的語法語義。 那么這些語言用這么有限的聊聊幾個(gè)設(shè)施怎么對應(yīng)它不可能預(yù)見的各種現(xiàn)實(shí)中的需求呢?
我們平時(shí)對可以用簡單的if-else,順序,循環(huán)就可以做幾乎任何我們能想到的事情感到驚訝了嗎?對某個(gè)語言能否處理復(fù)雜的需求擔(dān)憂了嗎?
為什么沒有呢?就在于”組合“的威力。就是那么幾個(gè)簡單的設(shè)施,組合起來卻可以具有巨大的力量。
同樣,在設(shè)計(jì)組合子的時(shí)候,如果我們遵循這些共性,同時(shí)在和具體需求磨合的時(shí)候積極改進(jìn)組合子本身,應(yīng)該就可以達(dá)到一個(gè)可以滿意的組合子系統(tǒng)。
說到這里,可能有人問:你不是說組合子系統(tǒng)是脫離需求自己發(fā)展的嗎?
這個(gè),怎么說呢?還是說語言。設(shè)計(jì)一個(gè)語言,原則上是設(shè)計(jì)一些和具體需求沒有耦合的基礎(chǔ)設(shè)施,然后讓寫具體應(yīng)用的人組合這些基礎(chǔ)設(shè)施達(dá)到我們語言設(shè)計(jì)者不可能都預(yù)見到的某些具體效果。 但是,在語言設(shè)計(jì)和逐漸發(fā)展過程中,仍然會(huì)從用戶(就是程序員)那里得到反饋,什么樣的需求是他們需要的,什么樣的設(shè)施不好用,然后設(shè)計(jì)者再進(jìn)行改進(jìn)。
一個(gè)語言,一般不會(huì)是某個(gè)具體需求通過劃分責(zé)任,自頂向下的設(shè)計(jì),最后作為這個(gè)需求的附屬模塊被開發(fā)出來。更多的情況,是語言的設(shè)計(jì)者對可能面對的需求有一個(gè)大致了解,并且知道這種可能的需求是變化的,不確定的,于是才會(huì)從基本設(shè)施開始設(shè)計(jì)這個(gè)語言,最后交付給開發(fā)具體應(yīng)用的人來使用。
組合子系統(tǒng)也遵循一樣的規(guī)律。組合子的設(shè)計(jì)需要來自具體需求的靈感和糾正。但是,基本組合子本身卻不能耦合于這些具體需求。 組合子的設(shè)計(jì)者應(yīng)該對可能面對的需求有大致的了解,但是并不需要完整地預(yù)測這種多變的需求。
當(dāng)然,組合子這種語言中的語言,還有不容易理解的弱點(diǎn)。當(dāng)組合層次增多,邏輯變得復(fù)雜,這個(gè)復(fù)雜的組合子可不象寫在一般的程序設(shè)計(jì)語言里面的代碼那樣簡明,java繁瑣的語法讓這種語言中的語言對一些程序員也許就象是神廟里面的神諭一樣難以理解,甚至讓人望而生畏。
這一半是因?yàn)閖ava本身沒有提供對這種高階邏輯的直接支持,組合的語法相對繁瑣。如果用haskell,使用語言提供的do-notation,形式上的復(fù)雜程度就沒了。
另一方面,高階邏輯都是有這種弱點(diǎn)的。 其實(shí),就算是oo,相比于po,它的多態(tài)也是降低可理解性的。
因此,就象我們也不能在oo中到處override虛函數(shù)一樣,組合子的使用也要有一定的度,過猶不及。
好了,沒有實(shí)際例子的論述已經(jīng)太長了??隙ㄒ呀?jīng)有人昏昏欲睡了。
做個(gè)調(diào)查,我下面的例子有幾個(gè)選擇:
1。簡單的predicate。就是一個(gè)具有bool is(Object v);方法的接口。 2。ant的FileSelector。一個(gè)predicate的變體。 3。swing提到的jdbc的action。負(fù)責(zé)數(shù)據(jù)庫操作的組合子。 4。yan container的component。負(fù)責(zé)從任意的構(gòu)造函數(shù),工廠方法,java bean以及它們的任意組合來產(chǎn)生和注射組件。比pico/spring靈活很多。 5。neptune的command,負(fù)責(zé)調(diào)用任何ant task以及其它的可能返回一個(gè)java對象的函數(shù)。是一個(gè)一般化了的ant task。
這些東西都是基于組合子的。大家覺得對哪一個(gè)更有興趣呢?我有些拿不定主意哪個(gè)更合適。 |
留言 (0 留言) |
主題: 用Java程序獲取絕對路徑(2005-8-09 周二) |
作者: 凝血神抓 |
| 鏈接地址:用Java程序獲取絕對路徑 |
| http://www./html/200409/2004092114331500000778.html |
留言 (0 留言) |
主題: 路徑相關(guān)(2005-8-09 周二) |
作者: 凝血神抓 |
| 鏈接地址:路徑相關(guān) |
| http://www./article/showarticle.jsp?column=2&thread=7499 |
留言 (0 留言) |
主題: 在JSP中處理虛擬路徑(2005-8-09 周二) |
作者: 凝血神抓 |
| 鏈接地址:在JSP中處理虛擬路徑 |
| http://www./article/showarticle.asp?id=1083 |
留言 (0 留言) |
主題: 防止ACCESS數(shù)據(jù)庫被下載的9種方法 [整理版](2005-8-09 周二) |
作者: 凝血神抓 |
| 鏈接地址:防止ACCESS數(shù)據(jù)庫被下載的9種方法 [整理版] |
| http://oldblog.blogchina.com/article_47389.178225.html |
留言 (0 留言) |
主題: veloeclipse(2005-8-09 周二) |
作者: chjdxiao |
| 鏈接地址:veloeclipse |
| veloeclipseveloeclipse |
留言 (0 留言) |