<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    snowolf

    這樣的一種生活
    posts - 23, comments - 5, trackbacks - 0, articles - 11

    使用 Struts Validator

    Posted on 2006-03-20 10:59 snowolf 閱讀(851) 評論(0)  編輯  收藏 所屬分類: 學習

    構建帶有驗證的 “防彈” 應用程序

    驗證的重要性

    偉大的籃球隊經常因為他們有穩定的控球、精彩的傳球、擋不住的投籃而受到贊揚。偉大的音樂家要反復地練習,而且會在一兩個音階或小節上花費數小時的時間。偉大的汽車有許多額外的特性,但是跑得更遠,引擎問題更少,而比它們弱小的競爭對手更可靠。所有這些例子都表明,偉大的執行者 “做小事”。這些小事可能不明顯,但是會帶來一致而積極的結果。

    對于應用程序編程,花里胡哨的用戶界面和沒有必要的復雜的線程,在保證用戶數據正確方面,可不如對用戶的沖擊那樣大。沒有什么比在 Web 表單中輸入錯誤的電子郵件地址、電話號碼,還要讓應用程序傻乎乎地繼續執行更糟的了。在這類情況下,真正能夠有幫助的小事就是驗證

    簡而言之,驗證就是確保數據正確。這聽起來有點傻,但是正確 可能有各種不同的含義,這也正是驗證發揮威力的地方。一個正確的電子郵件地址可能只是擁有至少一個 @ 符號,在 @ 符號后有一個句點(.)。但是,更復雜的應用程序可能還要求電子郵件地址是指定長度、來自少數特定域。在任何一種情況下,代碼都必須保證輸入的數據是可以接受的;否則,就會產生各種可能的錯誤情況:

    • 可能把錯誤的數據傳遞到另一個方法,后一個方法不得不執行額外的錯誤檢查,從而降低應用程序的速度。

    • 可能把錯誤的數據傳遞給一個 執行錯誤檢測的方法,從而造成應用程序崩潰。

    • 可能把錯誤的數據插入數據庫,從而造成下次(可能是 5 分鐘或者 5 天以后)讀取數據時的錯誤。

    在所有這些情況中,都將給用戶帶來損害,并給他們提供了轉到競爭對手 Web 站點或產品的好理由。

    本教程的主題是驗證。保證不是什么令人興奮的、迷人的主題,但是它是可以讓好應用程序變成優秀的那些 “小事” 中的一件。

    從服務器端驗證開始

    在 Struts 這樣的服務器端編程環境中,最容易的(在某種程度上,也是最自然的)驗證方式就是在 Java 代碼中放幾個檢測。具體來說,用于從表單接收數據的 Struts Action 似乎是放置驗證代碼的好地方。可以從 servlet 請求中提取值,并檢查電子郵件或電話號碼的格式、名稱的長度或者郵編的合法性。然后,如果有問題,可以再次向用戶顯示提交表單,可能還帶有錯誤消息,指出發生的問題。

    雖然這可能現在聽起來不錯,但是執行服務器端驗證是獲得良好用戶體驗的最糟方式之一。當用戶在 Web 表單上點擊 SubmitSaveEnter ,并且頁面閃爍時(表明服務器上正在發生什么),他們可不想再次回到原來的提交頁面,還帶著錯誤消息。如果需要花很長時間來處理請求,那么這個問題就是復雜的:用戶必須等待,然后應用程序返回一組錯誤消息。Web 是種步伐很快的媒體,用戶期望最小延遲、響應快的應用程序以及動態的用戶界面。

    如果不在服務器上處理錯誤,則應當試著把驗證移到客戶機。客戶端驗證可以防止用戶提交包含錯誤數據的表單。因為沒有通信的延遲,所以它也更快。現在,好的應用程序中幾乎或多或少都有一些客戶端驗證。

    但是,也有些時候服務器端驗證 —— 或者至少某種形式的服務器端驗證 —— 是有意義的。有時驗證包含格式、長度和其他細小問題的檢查(想想電話號碼、郵編、區號和其他數據);其他時候,驗證要調用更復雜的計算。比如,可能需要確保某本書可以運送到某個郵編的地區。在這些情況下,可能不得不允許服務器請求,因為可能需要數據庫和其他復雜處理才能保證正確的響應。但是,用戶一般能夠理解這些是更復雜的請求,所以一般會耐心等待響應。實際上,這類計算很少被當作驗證,而是和應用程序服務的通用業務混在一起。同樣,除了這些最復雜的情況之外,只要有可能,都應當把驗證移到客戶機。

    移到 JavaScript 進行驗證

    客戶端驗證最明顯的選擇就是 JavaScript。這個流行的腳本語言易于學習、靈活,而且在每個現代 Web 瀏覽器中都可用(雖然會有所差別)。對于許多應用程序來說,JavaScript 足夠好了。但是,仍然有些不足。

    首先,JavaScript 仍然是代碼,所以就像其他代碼一樣,必須編寫、測試、調試和部署 JavaScript。如果從 5 位郵編轉到 9 位郵編,那么驗證代碼就要改變,而且需要在它們影響的所有頁面上測試修改。雖然這項工作對于得到清爽的、讓用戶高興的結果來說很值得,但卻是一項時間密集型工作。

    在使用 JavaScript 時,也會非常麻煩 —— 可以容易地把 scriplet 放進 HTML 頁面,但是會給維護帶來惡夢。雖然進行限制并不太難,但是有種誘惑就是只對頁面內的腳本做 “一次快速修正”,卻從來不刪除這段腳本并重寫 JavaScript 庫中的代碼。

    最后,可能必須要一個項目一個項目都帶著 JavaScript 庫。這也不算什么大麻煩,但是個問題 —— 對于部署代碼的每個平臺都要測試該代碼。

    請不要誤解我 —— JavaScript 是驗證的優秀解決方案,但是如果用 Struts,那么還會有第三個 —— 甚至更好的選項。

    了解 Struts Validator

    Struts 提供了一個名為 Validator 的優秀組件。Validator 可以插入 Struts 應用程序(將在 安裝 Validator 框架 中介紹),甚至直接和最新的 Struts 發行版綁定在一起。只要幾個 JAR 文件就可以了。但是 Validator 強在什么地方呢?為什么要用它代替 JavaScript 呢?

    而且,您應當認識到,Validator 的大部分執行都使用 JavaScript。所以實際上并沒有離開 JavaScript,而且得到的客戶端驗證也是 JavaScript 擅長的內容。但是,Validator 消除了 JavaScript 的許多問題。首先,它是由成千上萬的 Struts 開發人員和用戶編碼、測試和調試過的,因此降低了您需要進行的測試數量。(我絕對不是 暗示您不要測試;Validator 只是降低了測試負擔,但并沒有完全消除它。)另外,Validator 提供了大量常用驗證函數,所以您不必為電子郵件地址、電話號碼、郵編以及其他常用數據編寫驗證器。這棒不棒?

    而最重要的,可能是 Struts Validator 主要通過配置文件工作,而不用內聯的 HTML 代碼。通過簡單的 XML 文件,可以指示要驗證哪個字段,要執行哪類驗證。Struts 和 Validator 負責把配置變成工作的 JavaScript 代碼,您這一邊不需要做任何額外工作!雖然偶爾也要為特定于應用程序的數據添加新的驗證函數,但是在 HTML 中使用這些函數的工作由 Struts 處理 —— 不需要手工過程。這就是 Validator 真正勝出而珍貴的地方。被說服了么?現在來看它。

    設置示例應用程序

    從 struts-blank WAR 開始

    在介紹如何使用 Validator 之前,需要利用一個示例應用程序。如果用二進制發行版安裝了 Struts(細節請參閱 附錄),那么就有了一個好的起點。請確保 Tomcat 正在運行,并導航到 http://localhost:8080/struts-blank。應當看到像圖 1 所示的內容:


    圖 1. struts-blank 應用程序提供了新應用程序的模板
    ?struts-blank.jpg

    這頁上的文本明確地說明了需要做的事情:

    1. 找到磁盤上的 struts-blank.war 文件。(在我的機器上,是 /usr/local/jakarta-tomcat-5.5.9/webapps/struts-blank.war。)
    2. 把這個文件拷貝到可以處理它的地方,或者在開發目錄中,或者在桌面上。
    3. 把 test-validation.war 文件改名。這個文件將是在這篇文章中要開發的驗證應用程序的基礎。

    現在需要把 WAR 文件展開到一組目錄中,這樣可以方便地處理。請創建一個在其中操作的目錄; 我通常給它起名為 staging 或類似的名稱。創建了目錄之后,請用 jar 命令,使用 xvf 選項把這個文件展開到新建的目錄中,如清單 1 所示:


    清單 1. WAR 文件目錄

    												
    														
    [bmclaugh:/usr/local/java]$ ls jakarta-struts-1.2.4 src xalan-j_2_6_0 jakarta-tomcat-5.5.9 test-validation.war [bmclaugh:/usr/local/java]$ mkdir staging [bmclaugh:/usr/local/java]$ cd staging [bmclaugh:/usr/local/java/staging]$ jar xvf ../test-validation.war created: META-INF/ inflated: META-INF/MANIFEST.MF created: WEB-INF/ created: WEB-INF/classes/ created: WEB-INF/classes/resources/ created: WEB-INF/lib/ created: WEB-INF/src/ created: WEB-INF/src/java/ created: WEB-INF/src/java/resources/ created: pages/ inflated: WEB-INF/classes/MessageResources.properties inflated: WEB-INF/classes/resources/MessageResources.properties inflated: WEB-INF/lib/commons-beanutils.jar inflated: WEB-INF/lib/commons-collections.jar inflated: WEB-INF/lib/commons-digester.jar inflated: WEB-INF/lib/commons-fileupload.jar inflated: WEB-INF/lib/commons-logging.jar inflated: WEB-INF/lib/commons-validator.jar inflated: WEB-INF/lib/jakarta-oro.jar inflated: WEB-INF/lib/struts.jar inflated: WEB-INF/src/README.txt inflated: WEB-INF/src/build.xml inflated: WEB-INF/src/java/resources/application.properties inflated: WEB-INF/struts-bean.tld inflated: WEB-INF/struts-config.xml inflated: WEB-INF/struts-html.tld inflated: WEB-INF/struts-logic.tld inflated: WEB-INF/struts-nested.tld inflated: WEB-INF/struts-tiles.tld inflated: WEB-INF/tiles-defs.xml inflated: WEB-INF/validation.xml inflated: WEB-INF/validator-rules.xml inflated: WEB-INF/web.xml inflated: index.jsp inflated: pages/Welcome.jsp

    可以對這些文件做修改,根據個人需要定制應用程序。這種方法的好處是所有的設置文件都有了,不用考慮要下載所有正確的 WAR 文件。有哪個開發人員不喜歡這么好的方便呢?

    ?

    改變歡迎頁面

    首先,需要在主頁面上添加鏈接;這個鏈接將把用戶帶到一個簡單的表單,在這個表單上演示一些驗證規則。如果訪問示例應用程序,可以迅速地看到顯示的默認頁面是保存在應用程序結構的頁面目錄中的 Welcome.jsp。請在文本處理器或 IDE 中打開這個文件。

    struts-blank WAR 提供的版本是個好的開始;要改變顯示的文本,甚至不需要觸動這個文件以及保存在 MessageResources 文件中的文本(我稍后就會介紹)。所有需要做的,只是添加一個簡單的鏈接。請把清單 2 中的粗體行添加到 Welcome.jsp 文件:


    清單 2. Welcome.jsp 文件

    												
    														<%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib uri="/tags/struts-bean" prefix="bean" %>
    <%@ taglib uri="/tags/struts-html" prefix="html" %>
    <%@ taglib uri="/tags/struts-logic" prefix="logic" %>
    
    <html:html locale="true">
    <head>
    <title><bean:message key="welcome.title"/></title>
    <html:base/>
    </head>
    <body bgcolor="white">
    
    <logic:notPresent name="org.apache.struts.action.MESSAGE" scope="application">
      <font color="red">
        ERROR:  Application resources not loaded -- check servlet container
        logs for error messages.
      </font>
    </logic:notPresent>
    
    <h3><bean:message key="welcome.heading"/></h3>
    <p><bean:message key="welcome.message"/></p>
    
    														
    																<p>
    														
    														
    																
    																		<ul>
    <li><html:link action="/TestSimpleValidation">
     <bean:message key="welcome.test-validation" />
    </html:link></li>
    </ul>
    </p>
    																
    
    </body>
    </html:html>
    
    												
    										

    html:link 標記是 Struts 中非常基本的構造。在這里,用它鏈接到一個 Struts Action,后者將裝入一個有一些驗證示例的頁面。但在介紹它之前,要修改一些屬性(welcome.titlewelcome.headingwelcome.message),還要添加一個屬性(welcome.test-validation)。

    這些屬性在 MessageResources.properties 文件中,該文件在應用程序結構的 WEB-INF/classes 目錄中。請打開這個文件,到文件的底部,按下面粗體的部分做修改:

    												
    														# -- welcome --
    welcome.title=Struts Validator Test Application
    welcome.heading=Welcome to the Validation Tester Application!
    welcome.message=
    														
    																
    																		This is a simple application meant to test and demonstrate the Struts Validator component.
    																
    																
    																		welcome.test-validation=Test out some simple uses of the Struts Validator
    																
    														
    												
    										

    現在只需要添加一個簡單的 forward 到 struts-config.xml 文件(這個文件應當在應用程序的 WEB-INF 文件夾中)。查找 action-mappings 元素并添加下面的內容:

    												
    														<action-mappings>
      <action path="/TestSimpleValidation"
              forward="/pages/test-validation.jsp" />
    
      <-- Other Action mappings -->
    </action-mappings>
    
    												
    										

    做了這些修改,初始的歡迎頁面即已就緒。在下一節,將重新部署應用程序,測試這個頁面。


    ?

    重新部署應用程序

    每次重新部署的時候,只要做幾個簡單步驟:

    1. jar 命令把應用程序壓縮回 WAR 文件,如清單 3 所示:


      清單 3. jar 命令
      							
      
      [bmclaugh:/usr/local/java]$ cd staging                           
      [bmclaugh:/usr/local/java/staging]$ jar cvf ../test-validation.war *
      added manifest
      ignoring entry META-INF/
      ignoring entry META-INF/MANIFEST.MF
      adding: WEB-INF/(in = 0) (out= 0)(stored 0%)
      adding: WEB-INF/classes/(in = 0) (out= 0)(stored 0%)
      adding: WEB-INF/classes/MessageResources.properties(in = 1167) 
       (out= 488)(deflated 58%)
      adding: WEB-INF/classes/resources/(in = 0) (out= 0)(stored 0%)
      adding: WEB-INF/classes/resources/MessageResources.properties(in = 1480)
        (out= 655)(deflated 55%)
      adding: WEB-INF/lib/(in = 0) (out= 0)(stored 0%)
      adding: WEB-INF/lib/commons-beanutils.jar(in = 118726) (out= 105729)
       (deflated 10%)
      adding: WEB-INF/lib/commons-collections.jar(in = 175426) (out= 144506)
       (deflated 17%)
      adding: WEB-INF/lib/commons-digester.jar(in = 109096) (out= 99033)
       (deflated 9%)
      adding: WEB-INF/lib/commons-fileupload.jar(in = 22379) (out= 19246)
       (deflated 13%)
      adding: WEB-INF/lib/commons-logging.jar(in = 38015) (out= 34595)
       (deflated 8%)
      adding: WEB-INF/lib/commons-validator.jar(in = 84260) (out= 76342)
       (deflated 9%)
      adding: WEB-INF/lib/jakarta-oro.jar(in = 65261) (out= 56142)
       (deflated 13%)
      adding: WEB-INF/lib/struts.jar(in = 526578) (out= 480962)
       (deflated 8%)
      adding: WEB-INF/src/(in = 0) (out= 0)(stored 0%)
      adding: WEB-INF/src/build.xml(in = 3672) (out= 1080)(deflated 70%)
      adding: WEB-INF/src/java/(in = 0) (out= 0)(stored 0%)
      adding: WEB-INF/src/java/resources/(in = 0) (out= 0)(stored 0%)
      adding: WEB-INF/src/java/resources/application.properties(in = 1480) 
       (out= 655)(deflated 55%)
      adding: WEB-INF/src/README.txt(in = 1923) (out= 837)(deflated 56%)
      adding: WEB-INF/struts-bean.tld(in = 8860) (out= 771)(deflated 91%)
      adding: WEB-INF/struts-config.xml(in = 6665) (out= 1994)(deflated 70%)
      adding: WEB-INF/struts-html.tld(in = 67559) (out= 2069)(deflated 96%)
      adding: WEB-INF/struts-logic.tld(in = 14731) (out= 830)(deflated 94%)
      adding: WEB-INF/struts-nested.tld(in = 65059) (out= 2086)(deflated 96%)
      adding: WEB-INF/struts-tiles.tld(in = 7842) (out= 717)(deflated 90%)
      adding: WEB-INF/tiles-defs.xml(in = 1379) (out= 535)(deflated 61%)
      adding: WEB-INF/validation.xml(in = 2121) (out= 550)(deflated 74%)
      adding: WEB-INF/validator-rules.xml(in = 12254) (out= 1628)(deflated 86%)
      adding: WEB-INF/web.xml(in = 1942) (out= 582)(deflated 70%)
      adding: index.jsp(in = 276) (out= 188)(deflated 31%)
      adding: pages/(in = 0) (out= 0)(stored 0%)
      adding: pages/Welcome.jsp(in = 657) (out= 318)(deflated 51%)
      

    2. jartvf 選項可以確保 WAR 文件包含所有應當包含的內容:


      清單 4. tvf 選項
      							
      
      [bmclaugh:/usr/local/java/staging]$ cd ..
      [bmclaugh:/usr/local/java]$ jar tvf test-validation.war 
           0 Thu May 19 17:13:34 CDT 2005 META-INF/
          70 Thu May 19 17:13:34 CDT 2005 META-INF/MANIFEST.MF
           0 Thu May 19 16:51:20 CDT 2005 WEB-INF/
           0 Thu May 19 16:55:00 CDT 2005 WEB-INF/classes/
        1167 Thu May 19 16:55:00 CDT 2005 WEB-INF/classes/MessageResources.properties
           0 Thu May 19 16:51:20 CDT 2005 WEB-INF/classes/resources/
        1480 Thu May 19 16:51:20 CDT 2005 WEB-INF/classes/resources/
          MessageResources.properties
           0 Thu May 19 16:51:20 CDT 2005 WEB-INF/lib/
      118726 Thu May 19 16:51:20 CDT 2005 WEB-INF/lib/commons-beanutils.jar
      175426 Thu May 19 16:51:20 CDT 2005 WEB-INF/lib/commons-collections.jar
      109096 Thu May 19 16:51:20 CDT 2005 WEB-INF/lib/commons-digester.jar
       22379 Thu May 19 16:51:20 CDT 2005 WEB-INF/lib/commons-fileupload.jar
       38015 Thu May 19 16:51:20 CDT 2005 WEB-INF/lib/commons-logging.jar
       84260 Thu May 19 16:51:20 CDT 2005 WEB-INF/lib/commons-validator.jar
       65261 Thu May 19 16:51:20 CDT 2005 WEB-INF/lib/jakarta-oro.jar
      526578 Thu May 19 16:51:20 CDT 2005 WEB-INF/lib/struts.jar
           0 Thu May 19 16:51:20 CDT 2005 WEB-INF/src/
        3672 Thu May 19 16:51:20 CDT 2005 WEB-INF/src/build.xml
           0 Thu May 19 16:51:20 CDT 2005 WEB-INF/src/java/
           0 Thu May 19 16:51:20 CDT 2005 WEB-INF/src/java/resources/
        1480 Thu May 19 16:51:20 CDT 2005 WEB-INF/src/java/resources/application.properties
        1923 Thu May 19 16:51:20 CDT 2005 WEB-INF/src/README.txt
        8860 Thu May 19 16:51:20 CDT 2005 WEB-INF/struts-bean.tld
        6665 Thu May 19 16:51:20 CDT 2005 WEB-INF/struts-config.xml
       67559 Thu May 19 16:51:20 CDT 2005 WEB-INF/struts-html.tld
       14731 Thu May 19 16:51:20 CDT 2005 WEB-INF/struts-logic.tld
       65059 Thu May 19 16:51:20 CDT 2005 WEB-INF/struts-nested.tld
        7842 Thu May 19 16:51:20 CDT 2005 WEB-INF/struts-tiles.tld
        1379 Thu May 19 16:51:20 CDT 2005 WEB-INF/tiles-defs.xml
        2121 Thu May 19 16:51:20 CDT 2005 WEB-INF/validation.xml
       12254 Thu May 19 16:51:20 CDT 2005 WEB-INF/validator-rules.xml
        1942 Thu May 19 16:51:20 CDT 2005 WEB-INF/web.xml
         276 Thu May 19 16:51:20 CDT 2005 index.jsp
           0 Thu May 19 16:53:24 CDT 2005 pages/
         657 Thu May 19 16:51:20 CDT 2005 pages/Welcome.jsp
      

    3. 把新的 WAR 文件拷貝到 Tomcat 的 webapps 目錄:

      [bmclaugh:/usr/local/java]$ cp test-validation.war jakarta-tomcat-5.5.9/webapps/
      

    4. 在 http://localhost:8080/test-validation/ 上訪問應用程序。

    可以編寫腳本或 Ant 文件來完成這些任務,也可以手工執行這些任務。在任何情況下,一修改應用程序(在本教程中就會做大量修改)就重新部署都是很好的快速方式。

    ?

    檢查歡迎頁面

    應用程序重新部署之后,請訪問 http://localhost:8080/test-validation/。應當看到像圖 2 一樣的頁面:


    圖 2. 對 Welcome.jsp 和消息資源文件的修改創建了新的歡迎屏幕
    ?struts-welcome.jpg

    這時,應用程序還沒有功能;在新鏈接上點擊只會出現討厭的錯誤。但這就對了 —— 已經得到了好的開始,可以直接使用 Validator 了。

    安裝 Validator 框架

    必要的庫

    Struts Validator 是一個組成相當復雜的軟件,而且它依賴于其他幾個庫才能正常工作。就像在 servlet 引擎中運行 Struts 需要多個 JAR 文件一樣,要讓 Validator 工作也還需要多個 JAR 文件。最重要的是需要 Jakarta ORO 包,它負責處理正則表達式。

    Validator 還使用 Jakarta Commons BeanUtilsJakarta Commons LoggingJakarta Commons CollectionsJakarta Commons Digester 包。這些 JAR 文件需要放在 Tomcat 的 common/lib 目錄中或 Web 應用程序的 WEB-INF/lib 目錄中。

    最后,Struts Validator 是建立于 Jakarta Commons 包 Jakarta Commons Validator 以及其他包的基礎之上的。所以需要另一個 JAR 文件。這些 JAR 文件已經很多了,但是要處理的還有更多。但是在開始下載之前,先繼續閱讀。我介紹完所有要求之后,我還會介紹一種快捷方式,不用自己下載并手工配置,就可以在應用程序中得到 Validator 支持。

    ?

    驗證規則

    Validator 庫就位之后,還需要兩個 XML 文件:validation-rules.xml 和 validator.xml。validation-rules.xml 文件或多或少是靜態的,所以先處理它。這個文件指定可用的驗證規則;因為 Validator 自帶了幾個默認規則,所以只要找到這個文件的工作目錄,并把它拷貝到自己應用程序的 WEB-INF 目錄即可。

    這個文件很長,所以我在清單 5 中只包含一小段來介紹它的樣子:


    清單 5. validation-rules.xml 文件

    												
    														
    <DOCTYPE form-validation PUBLIC
              "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN"
              "http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd">
    <form-validation>
    
       <global>
    
          <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.ActionMessages,
                          javax.servlet.http.HttpServletRequest"
                     msg="errors.required"/>
    
          <validator name="requiredif"
                classname="org.apache.struts.validator.FieldChecks"
                    method="validateRequiredIf"
                    methodParams="java.lang.Object,
                          org.apache.commons.validator.ValidatorAction,
                          org.apache.commons.validator.Field,
                          org.apache.struts.action.ActionMessages,
                          org.apache.commons.validator.Validator,
                          javax.servlet.http.HttpServletRequest"
                     msg="errors.required"/>
    
          <validator name="validwhen"
              msg="errors.required"
                classname="org.apache.struts.validator.validwhen.ValidWhen"
                    method="validateValidWhen"
                    methodParams="java.lang.Object,
                          org.apache.commons.validator.ValidatorAction,
                          org.apache.commons.validator.Field,
                          org.apache.struts.action.ActionMessages,
                          org.apache.commons.validator.Validator,
                          javax.servlet.http.HttpServletRequest"/>
    
    
          <validator name="minlength"
                classname="org.apache.struts.validator.FieldChecks"
                   method="validateMinLength" 
                   methodParams="java.lang.Object,
                          org.apache.commons.validator.ValidatorAction,
                          org.apache.commons.validator.Field,
                          org.apache.struts.action.ActionMessages,
                          javax.servlet.http.HttpServletRequest"
                   depends=""
                      msg="errors.minlength"
               jsFunction="org.apache.commons.validator.javascript.validateMinLength"/>
    
         <!--
           This simply allows struts to include the validateUtilities into a page, it should
           not be used as a validation rule.
         -->
         &lt;validator name="includeJavaScriptUtilities"
                classname=""
                   method=""
                   methodParams=""
                   depends=""
                      msg=""
               jsFunction="org.apache.commons.validator.javascript.validateUtilities"/>
    
       </global>
    </form-validation>
    												
    										

    不要太過擔心這個文件的復雜性;除非要編寫自己的驗證規則,否則只要接受并使用它的默認版本就可以了。

    ?

    向應用程序添加錯誤消息

    大多數版本的 validation-rules.xml 在文件頭的注釋中,都包含像清單 6 這樣的內容:


    清單 6. validation-rules.xml 注釋

    												
    																			
    
       These are the default error messages associated with
       each validator defined in this file.  They should be
       added to your projects ApplicationResources.properties
       file or you can associate new ones by modifying the
       pluggable validators msg attributes in this file.
    
       # Struts Validator Error Messages
       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 a byte.
       errors.short={0} must be a short.
       errors.integer={0} must be an integer.
       errors.long={0} must be a long.
       errors.float={0} must be a float.
       errors.double={0} must be a double.
    
       errors.date={0} is not a date.
       errors.range={0} is not in the range {1} through {2}.
       errors.creditcard={0} is an invalid credit card number.
       errors.email={0} is an invalid e-mail address.
    
    												
    										

    注釋頂部的消息是條好建議。不管您是否遵照指示操作,Validator 在輸出錯誤消息時都會采用這些屬性。如果沒有把這些插入應用程序的資源,結果就是空的錯誤消息,當然看起來就像根本沒有錯誤消息一樣。對于用戶來說,再也沒有什么會比提交表單之后、表單被拒絕、然后出錯的時候沒有任何反饋這件事更郁悶的了。

    這些屬性最好放在文件中,例如 MessageResources.properties,通常位于應用程序的 WEB-INF/classes 目錄中:


    清單 7. MessageResources.properties

    												
    														
    																
    <b># -- standard errors -- errors.header=<UL> errors.prefix=<LI> errors.suffix=</LI> errors.footer=</UL> # -- validator -- errors.invalid={0} is invalid. errors.maxlength={0} can not be greater than {1} characters. errors.minlength={0} can not be less than {1} characters. errors.range={0} is not in the range {1} through {2}. errors.required={0} is required. errors.byte={0} must be an byte. errors.date={0} is not a date. errors.double={0} must be an double. errors.float={0} must be an float. errors.integer={0} must be an integer. errors.long={0} must be an long. errors.short={0} must be an short. errors.creditcard={0} is not a valid credit card number. errors.email={0} is an invalid e-mail address. # -- other -- errors.cancel=Operation cancelled. errors.detail={0} errors.general=The process did not complete. Details should follow. errors.token=Request could not be completed. Operation is not in sequence.</b> # -- welcome -- welcome.title=Struts Validator Test Application welcome.heading=Welcome to the Validation Tester Application! welcome.message=This is a simple application meant to test and demonstrate the Struts Validator component. welcome.test-validation=Test out some simple uses of the Struts Validator

    但是,還是不用著急做這些修改,因為有更容易的方式(研究過 WEB-INF/classes/MessageResources.properties 文件的人可能對這個快捷方式已經有了認識)。如果想使用不同的錯誤消息,可以在這里做修改。例如,如果想讓無效電子郵件地址的出錯更好一些,可以把它改成像下面這樣:

    												
    														errors.email=You have entered an invalid e-mail address ({0}). Please try again.
    errors.email=You have entered an invalid e-mail address ({0}). Please try again.
    												
    										

    這是非常好的定制錯誤消息的方法,不用觸及實際的代碼行(從而避免了重新編譯、重新部署和許多重新測試)。

    ?

    把 Validator 連接到應用程序

    現在需要讓 Struts 應用程序知道 Validator。在這里,我指的是組件的整體,而不是 Validator 的某個特定應用(這是我將在 在應用程序中使用 Validator 中介紹的內容)。將需要使用 Struts 的 plugin 元素,這是讓 Struts 知道它應當集成進應用程序的組件的方法。在 struts-config.xml 文件中需要以下條目,這個文件位于應用程序的 WEB-INF 目錄下:

    												
    														<!-- =================================================== Validator plugin -->
    
      <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
        <set-property
            property="pathnames"
            value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
      </plug-in>
    												
    										

    className 屬性告訴 Struts 要裝載哪個類;這個類應當實現了 Struts 的 PlugIn 接口,就像 ValidatorPlugIn 做的那樣。然后,可能有許多特定于插件的 set-property 條目;對于 Validator,只需要一個:把 pathnames 屬性設置為 validator-rules.xml 和 validation.xml 文件所在路徑的值。如果想把這些值保存在其他地方,可以在 plugin 元素中指定替代位置。

    這些步驟完成之后,需要做的就是編寫特定于應用程序的表單、動作和驗證需求的 validation.xml 文件。但是,先讓我提供一些快捷方式,以避免 Validator 冗長的設置。

    ?

    struts-blank 應用程序的值

    如果在前面一直遵照我的指示,把 struts-blank.war 文件拷貝到新的文件 —— 用它作為開發 Struts 應用程序的基礎 —— 那么就揭開了一個巨大的秘密:struts-blank.war 預先已經做好了使用 Struts Validator 的配置!請看一下示例應用程序的 WEB-INF/lib 文件夾,將看到所有 Validator 需要的庫:

    • commons-beanutils.jar: Commons BeanUtils
    • commons-collections.jar: Commons Collections
    • commons-digester.jar: Commons Digester
    • commons-logging.jar: Commons Logging
    • commons-validator.jar: Commons Validator
    • jakarta-oro.jar: Jakarta ORO

    如果查看 WEB-INF/classes/MessageResources.properties,會看到定義了全部 Validator error 屬性。在 WEB-INF 中,將看到默認版本的 validation-rules.xml,它包含 Validator 的全部默認驗證規則,都已經準備好了。有一個非常基本的 validation.xml 版本可供修改(本教程下一節就要介紹它)。而且,最好的是,struts-config.xml 已經設置好了 Validator plugin 元素。

    這就是 struts-blank.war 真正美妙之所在,至少以我的觀點是這樣的:我從不需要記住需要什么 JAR 文件和配置步驟才能讓 Validator 工作。我只是把這個文件拷貝到新的位置,把它改成應用程序的名稱,然后就開始工作。即使一定要對現有的類或文件做些修改(例如添加鏈接到歡迎頁,或刪除某些 JSP),不用擔心 Validator 的設置也是值得的。

    您可能喜歡在每次開發新的 Struts 應用程序時都執行這一節描述的步驟,但是我寧愿拷貝 struts-blank.war 并改名,然后就開始工作。

    在應用程序中使用 Validator

    創建測試驗證的表單

    當我們離開示例應用程序時,有了一個歡迎頁面和一個到 pages/test-validation.jsp 的鏈接。現在可以讓這個頁面就位了。開始時,它只是一個普通的老式 JSP 頁面,有一個基本的表單;一旦讓簡單的 Struts 應用程序運行起來,我將介紹如何添加驗證邏輯。現在,先從清單 8 顯示的基本 JSP 開始:


    清單 8. 基本的 JSP

    																			???????????????????????????????????????
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib uri="/tags/struts-bean" prefix="bean" %> <%@ taglib uri="/tags/struts-html" prefix="html" %> <html:xhtml /> <html> <head> <title><bean:message key="valid.title" /></title> </head> <html:form action="/SubmitValid" focus="username"> <table border="0" width="100%"> <tr> <th align="right"> <bean:message key="prompt.username" />: </th> <td align="left"> <html:text property="username" size="10" maxlength="10" /> </td> </tr> <tr> <th align="right"> <bean:message key="prompt.password" />: </th> <td align="left"> <html:password property="password" size="16" maxlength="16" redisplay="false" /> </td> </tr> <tr> <th align="right"> <bean:message key="prompt.phone" />: </th> <td align="left"> <html:text property="phone" size="14" maxlength="14" /> </td> </tr> <tr> <th align="right"> <bean:message key="prompt.email" />: </th> <td align="left"> <html:text property="email" size="20" maxlength="100" /> </td> </tr> <tr> <th align="right"> <bean:message key="prompt.url" />: </th> <td align="left"> <html:text property="url" size="20" maxlength="100" /> </td> </tr> <tr> <td align="right"> <html:reset /> </td> <td align="left"> <html:submit property="Submit" value="Submit" /> </td> </table> </html:form> </body> </html>

    要添加到列表中的內容很少。可以看到,它創建了一個表單,然后提供了輸入錯誤數據的豐富機會。請注意對名稱屬性的豐富應用;現在應當把這些添加到 WEB-INF/classes/MessageResources.properties 文件中。把它們放在文件底部現有條目的后面:

    												
    														# -- validation test page --
    valid.title=Simple Validation Test Form
    prompt.username=Username
    prompt.password=Password
    prompt.phone=Phone Number
    prompt.email=E-Mail Address
    prompt.url=URL (Website Address)
    
    												
    										

    注意: 在本教程的這樣簡單的一個 JSP 中使用屬性看起來有點過分。但是,這只是一個良好的編碼實踐。可以本地化這些屬性,方便地修改它們和重用它們,而幾乎不需要額外的開發時間。請習慣于利用這類最佳實踐的優勢,即使在示例應用程序和原型設計中也該如此。它將帶來長期回報。

    試著訪問這個頁面,會生成錯誤;還有許多工作要做(有時讓 Struts 好的事情 —— 聲明性異常、高度可配置的表單等等 —— 反而讓它難以迅速就位運行)。在這一階段,應當得到類似清單 9 所示的消息:


    清單 9. 錯誤消息

    												
    														
    																
    javax.servlet.ServletException: Cannot retrieve mapping for action /SubmitValid
    org.apache.jasper.runtime.PageContextImpl.doHandlePageException( PageContextImpl.java:848) org.apache.jasper.runtime.PageContextImpl.handlePageException( PageContextImpl.java:781) org.apache.jsp.pages.test_002dvalidation_jsp._jspService( org.apache.jsp.pages.test_002dvalidation_jsp:102) org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:97) javax.servlet.http.HttpServlet.service(HttpServlet.java:802) org.apache.jasper.servlet.JspServletWrapper.service( JspServletWrapper.java:322) org.apache.jasper.servlet.JspServlet.serviceJspFile( JspServlet.java:291) org.apache.jasper.servlet.JspServlet.service(JspServlet.java:241) javax.servlet.http.HttpServlet.service(HttpServlet.java:802) org.apache.struts.action.RequestProcessor.doForward( RequestProcessor.java:1056) org.apache.struts.tiles.TilesRequestProcessor.doForward( TilesRequestProcessor.java:261) org.apache.struts.action.RequestProcessor.internalModuleRelativeForward( RequestProcessor.java:994) org.apache.struts.tiles.TilesRequestProcessor.internalModuleRelativeForward( TilesRequestProcessor.java:343) org.apache.struts.action.RequestProcessor.processForward( RequestProcessor.java:553) org.apache.struts.action.RequestProcessor.process( RequestProcessor.java:211) org.apache.struts.action.ActionServlet.process( ActionServlet.java:1164) org.apache.struts.action.ActionServlet.doGet( ActionServlet.java:397) javax.servlet.http.HttpServlet.service(HttpServlet.java:689) javax.servlet.http.HttpServlet.service(HttpServlet.java:802) root cause javax.servlet.jsp.JspException: Cannot retrieve mapping for action /SubmitValid org.apache.struts.taglib.html.FormTag.lookup(FormTag.java:723) org.apache.struts.taglib.html.FormTag.doStartTag(FormTag.java:419) org.apache.jsp.pages.test_002dvalidation_jsp._jspx_meth_html_form_0( org.apache.jsp.pages.test_002dvalidation_jsp:150) org.apache.jsp.pages.test_002dvalidation_jsp._jspService( org.apache.jsp.pages.test_002dvalidation_jsp:92) org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:97) javax.servlet.http.HttpServlet.service(HttpServlet.java:802) org.apache.jasper.servlet.JspServletWrapper.service( JspServletWrapper.java:322) org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:291) org.apache.jasper.servlet.JspServlet.service(JspServlet.java:241) javax.servlet.http.HttpServlet.service(HttpServlet.java:802) org.apache.struts.action.RequestProcessor.doForward( RequestProcessor.java:1056) org.apache.struts.tiles.TilesRequestProcessor.doForward( TilesRequestProcessor.java:261) org.apache.struts.action.RequestProcessor.internalModuleRelativeForward( RequestProcessor.java:994) org.apache.struts.tiles.TilesRequestProcessor.internalModuleRelativeForward( TilesRequestProcessor.java:343) org.apache.struts.action.RequestProcessor.processForward( RequestProcessor.java:553) org.apache.struts.action.RequestProcessor.process( RequestProcessor.java:211) org.apache.struts.action.ActionServlet.process(ActionServlet.java:1164) org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:397) javax.servlet.http.HttpServlet.service(HttpServlet.java:689) javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

    Struts 老手會認出這個錯誤消息的意義是:在 pages/validation-test.jsp 中定義了一個叫做 SubmitValid 的動作,但是在 struts-config.xml 文件中沒有匹配的 action 元素。還有其他相關問題:還需要 form-bean。下面我將處理這兩個問題。

    ?

    配置驗證測試頁面

    首先來處理遺漏的 SubmitValid 動作。請把清單 10 中的條目添加到 struts-config.xml 文件:


    清單 10. struts-config.xml 文件的條目

    												
    														
    <!-- Default "Welcome" action --> <!-- Forwards to Welcome.jsp --> <action path="/Welcome" forward="/pages/Welcome.jsp"/> <action path="/TestSimpleValidation" forward="/pages/test-validation.jsp" /> ????????<action path="/SubmitValid" type="com.ibm.struts.validation.ValidationAction" name="ValidationForm" scope="request" validate="true" input="/pages/test-validation.jsp"> <forward name="success" path="/pages/success.jsp" redirect="true"/> <forward name="failure" path="/pages/test-validation.jsp" redirect="true" /> </action> <!-- Other action elements -->

    這段代碼做的事情并不多;它只是把 test-validation.jsp 的表單關聯到一個新類 com.ibm.struts.validation.ValidationAction。這個類我還沒有介紹;馬上就要編寫它的代碼。剩下的內容對于任何 Struts 開發人員看起來都應當很典型。它指明了傳遞給動作的表單的名稱、范圍以及輸入頁面。它還開啟了驗證,至于原因,不言自明。

    現在,在訪問頁面時,將得到新的錯誤消息(假設做了以上修改,并重新部署了應用程序):


    清單 11. 新的錯誤消息

    												
    														
    javax.servlet.ServletException: Cannot retrieve definition for form bean ValidationForm on action /SubmitValid
      org.apache.jasper.runtime.PageContextImpl.doHandlePageException(PageContextImpl.java:848)
      org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:781)
      org.apache.jsp.pages.test_002dvalidation_jsp._jspService(org.apache.jsp.pages.test_002dvalidation_jsp:102)
      org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:97)
      javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
      org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:322)
      org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:291)
      org.apache.jasper.servlet.JspServlet.service(JspServlet.java:241)
      javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
      org.apache.struts.action.RequestProcessor.doForward(RequestProcessor.java:1056)
      org.apache.struts.tiles.TilesRequestProcessor.doForward(TilesRequestProcessor.java:261)
      org.apache.struts.action.RequestProcessor.internalModuleRelativeForward(RequestProcessor.java:994)
      org.apache.struts.tiles.TilesRequestProcessor.internalModuleRelativeForward(TilesRequestProcessor.java:343)
      org.apache.struts.action.RequestProcessor.processForward(RequestProcessor.java:553)
      org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:211)
      org.apache.struts.action.ActionServlet.process(ActionServlet.java:1164)
      org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:397)
      javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
      javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
    
    												
    										

    這是一個容易修復的問題;只需添加新的 form-bean 元素即可,也是添加到 WEB-INF/struts-config.xml 文件,這個元素定義了表單的 JavaBean,如清單 12 所示:


    清單 12. form-bean 元素

    												
    																
        <form-beans>
          <!-- Other form-bean listings -->
    
          
    														
    																
    																		<form-bean name="ValidationForm"
                     type="org.apache.struts.action.DynaActionForm">
            <form-property name="username" type="java.lang.String" />
            <form-property name="password" type="java.lang.String" />
            <form-property name="phone" type="java.lang.String" />
            <form-property name="email" type="java.lang.String" />
            <form-property name="url" type="java.lang.String" />
    																		
    </form-bean> </form-beans>

    現在就得到了一個可工作的配置。重新部署這些更改,訪問歡迎頁面,點擊鏈接。應當看到如圖 3 所示的驗證測試頁面:


    圖 3. 現在歡迎屏幕將把您帶到測試表單
    ?struts-validation_form.jpg

    這可能不是您看過的最漂亮的表單,但是對于我們的目的來說足夠了。需要放一個 Action 來處理表單,剩下的就是一些驗證了 —— 當然,這正是我們感興趣的部分!

    ?

    添加用于進行處理的定制動作

    因為不需要考慮什么業務邏輯(只不過是個示例應用程序),所以編寫驗證表單的定制 Action 很容易,如清單 13 所示:


    清單 13. 定制動作

    												
    														
    package com.ibm.struts.validation;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.apache.struts.action.Action;
    import org.apache.struts.action.ActionMapping;
    import org.apache.struts.action.ActionForm;
    import org.apache.struts.action.ActionForward;
    
    public class ValidationAction extends Action {
    
      public ActionForward execute(ActionMapping mapping, ActionForm form,
                                   HttpServletRequest req,
                                   HttpServletResponse res)
        throws Exception {
    
        ActionForward forward = null;
    
        // Perform some sort of business logic with the data. In this sample,
        //   we don't care about this; in fact, if the application got here,
        //   they've already passed validation, and we just need to return success
      
        forward = mapping.findForward("success");
        return forward;  
      }
    }
    
    												
    										

    當然,這個動作在 struts-config.xml 中用 SubmitValid 動作引用。在這個示例中,它什么也不做 —— 只是用 “success” 轉發把控制傳遞給 Struts 控制器。這與 struts-config.xml 文件匹配并請求 /pages/success.jsp JSP,如下所示:

    												
    														<%@ taglib uri="/tags/struts-html" prefix="html" %>
    
    <html:html locale="true">
    <head>
    <title>Welcome</title>
    <html:base/>
    </head>
    <body bgcolor="white">
    
    <h3>Validation Successful!</h3>
    
    </body>
    </html:html>
    
    												
    										

    當然,沒什么特別的內容,因為這篇教程介紹的是驗證,而不是頁面設計。

    值得一提的是,這里還沒有有驗證代碼!由于還沒有創建定制 ActionForm 和自行實現 validate() 方法,所以 Action 對于什么是正確的一無所知,實際上,如果沒有驗證問題,甚至不會訪問它。這意味著代碼完全沒有驗證邏輯,而且就像在下一節中看到的,代碼將保持這個樣子。

    實際上,這是我花了很多時間介紹應用程序設置的主要原因之一。代碼、業務邏輯、甚至大多數配置都缺乏驗證邏輯。所以每次修改允許的口令長度時,都不得不考慮重新部署表單和動作。實際上,只需要修改一個小小的 XML 文件就可以了。但是現在我還要向前走;在下一節,將開始查看要做 什么才能利用驗證。

    使用 Validator

    沒有 Validator 的 Struts

    在討論用 Validator 能做什么之前,先簡要地描述一下沒有 Validator 時驗證內容必須要做什么。回憶一下前面添加到 WEB-INF/struts-config.xml 中的 form-bean

    												
    														<form-bean name="ValidationForm"
         type="org.apache.struts.action.DynaActionForm">
      <form-property name="username" type="java.lang.String" />
      <form-property name="password" type="java.lang.String" />
      <form-property name="phone" type="java.lang.String" />
      <form-property name="email" type="java.lang.String" />
      <form-property name="url" type="java.lang.String" />
    </form-bean>
    												
    										

    如果 Validator 既沒安裝也不可用,還想執行服務器端驗證,那么需要替換表單的類型 —— 把當前的設置 org.apache.struts.action.DynaActionForm 換成定制類型,例如 com.ibm.struts.ValidationForm。這個類要擴展默認的 Struts 表單 org.apache.struts.action.ActionForm。然后,要實現 validate() 方法。看起來可能像這樣:

    												
    														public ActionErrors validate(ActionMapping mapping, HttpServletRequest req) {
      ActionErrors errors = new ActionErrors();
    
      // Do all sorts of validation
      if ((getUsername() == null) || (getUserName().length() < 1)) {
        errors.add("username", new ActionMessage("validation.errors.username.required"));
      } else if (getUsername().length() < 8) {
        errors.add("username", new ActionMessage("validation.errors.username.too-short"));
      } // ... etc.
    
      return errors;
    }
    
    												
    										

    不僅需要對應用程序中的每個表單創建定制類,而且還會違犯在教程前面的介紹中提到過的一個原則 —— 驗證是基于服務器的。每個請求都必須到達 servlet 引擎、被委托給 Struts、傳遞給正確的 ActionForm、得到處理、然后再返回(返回給 Struts、再到 servlet 容器,然后到用戶)。糟透了,是不是?

    您可能把驗證移動到 JavaScript(下一個最佳選擇),但是這也是一個痛苦,至于理由已經在前面提到過。另外,JavaScript 模塊(您正在模塊文件中編寫腳本,而不是直接寫到 JSP 中,對么?)不能訪問 Struts 的屬性文件,這意味著添加到 MessageResources.properties 中的所有這些好的錯誤消息,在驗證中都用不上。這樣就喪失了一些 Struts 最好的特性:模塊化和易于國際化。

    顯然,肯定有更好的方法。而且,謝天謝地,現在是時候研究 Validator 代碼了。

    ?

    動態驗證和 Validator

    如果關閉了 struts-config.xml 文件,請再次打開它。現在回到 form-bean 元素。需要修改表單類型,但不是改成定制類,而是使用 Validator 提供的類 org.apache.struts.validator.DynaValidatorForm,如下所示:

    												
    														<form-bean name="ValidationForm"
         type="org.apache.struts.validator.DynaValidatorForm">
      <form-property name="username" type="java.lang.String" />
      <form-property name="password" type="java.lang.String" />
      <form-property name="phone" type="java.lang.String" />
      <form-property name="email" type="java.lang.String" />
      <form-property name="url" type="java.lang.String" />
    </form-bean>
    									??????		
    										

    做這一修改,保存修改過的配置文件,并重新部署應用程序。如果進入驗證表單,輸入一些假值(或根本不輸入值),并點擊 Submit。將會看到和以前看到的一樣的 success.jsp 頁面。實際上,做這個修改對應用程序沒有實際的改變。因為沒有指定任何要應用的驗證規則。但是,現在有了一個可以指定這些規則的框架 —— 根本不用做代碼級或類級的修改。

    在進入之前,我要先給出一些強烈的建議:在表單 bean 中應當一直 使用 DynaValidatorForm。因為沒有設置驗證規則時,它的作用就像 Struts 的 DynaActionForm 一樣。但是,更重要的是,以后總能在不修改表單 bean 的情況下就添加驗證規則。由于這個原因(除非正在使用定制的 ActionForm 實現),我在我所有的表單 bean 中都嘗試使用 DynaActionForm

    ?

    添加驗證規則

    現在我們進入有趣的部分。打開 WEB-INF/validation.xml,這是我在前面提到過的兩個特定于 Validator 的配置文件的第二個(第一個是 validator-rules.xml,負責指定通用驗證規則)。validation.xml 文件包含表單特定字段(在 struts-config.xml 中定義)和通用驗證規則(在 validator-rules.xml 中)的映射。請打開 validation.xml 并找到 formset 元素。在這個元素內,添加清單 14 中的代碼(現在還沒有意義,但馬上會解釋它):


    清單 14. formset 元素的代碼

    												
    														
    <form name="ValidationForm">
      <field property="username"
            depends="required,minlength">
       <arg0 key="prompt.username" />
       <arg1 key="${var:minlength}" name="minlength"
            resource="false" />
       <var>
          <var-name>minlength</var-name>
          <var-value>6</var-value>
       </var>
      </field>
      <field property="password"
            depends="required,minlength">
       <arg0 key="prompt.password" />
       <arg1 key="${var:minlength}" name="minlength"
            resource="false" />
       <var>
          <var-name>minlength</var-name>
          <var-value>8</var-value>
       </var>
      </field>
    </form>
    												
    										

    首先,form 元素指明開始了一個新表單;name 屬性標識這個表單。不出所料,這里的名稱應當與 struts-config.xml 中的 form-bean 元素匹配。表單列出后,需要為每個想要驗證的字段指定規則。

    在這個示例中,我用了兩個最簡單、也最常見的在 usernamepassword 字段上的規則。第一個規則是 required(必需的),而且像其他規則一樣,由 field 元素的 depends 屬性指定。只需列出想要使用的規則,一個接著一個,用逗號分隔即可。然后,對于每個規則,要提供一些數據供 validator 使用。例如,required 規則需要一個參數;這個參數是字段的名稱,在字段沒有錯誤時,顯示在生成的錯誤信息上。使用 arg0 元素可以提供這個名稱(在這個示例中,是 prompt.usernameprompt.password,直接從可信任的 MessageResources.properties 文件提取)。現在開始來看這些內容是如何合在一起的吧?

    除了 required 規則,我還使用 minlength 規則。(請注意這些規則 大小寫敏感的!如果錄入錯誤,就會被忽略,會讓人很郁悶。)這條規則要求的參數不止一個;它需要一個變量指明字段可以接受的最小長度。這個值通過 varvar-namevar-value 元素傳遞給 minlength 規則。從代碼中看它應當更清楚,所以我讓您自己去弄清楚這里發生的事情。

    最后,還需要另一個參數 —— 這次針對的是 minlength 規則可能需要生成的任意錯誤消息。因為 arg0required 規則使用了,所以在此基礎上加 1,用 arg1minlength 規則提供必需的最小字符數。請注意在這里變量是如何引用的。resource="false" 語句告訴 validator 從當前文件中得到這個數據,而不是從應用程序的資源綁定(MessageResources.properties)中獲得。

    這里,應用程序將要求用戶名和口令字段的值,還要求輸入這些字段的數據有最小長度(請注意每個字段的最小長度不同)。非常漂亮!即使 validation.xml 中的規則定義非常詳細,對于每個規則該做什么也非常清楚。

    ?

    使用 Validator 的內置規則

    Struts Validator 自帶了許多有用的內置規則;可以檢查數據類型(integerdatabyte 等等。)和數據的范圍(range)。已經看過的有 minlength 規則,還有 maxlength 規則。甚至可以用 creditCard 規則保證數字和信用卡的數字格式匹配。我要使用另兩個規則 —— emailurl —— 來驗證測試表單上的數據正確。

    下面是 validation.xml 中的一些新規則:

    												
    														<field property="email"
        depends="email">
      <arg0 key="prompt.email" />
    </field>
    <field property="url"
        depends="url">
      <arg0 key="prompt.url" />
    </field>
    												
    										

    第一個要求 E-Mail 字段中的數據必須是正確的地址(讓 Struts 處理它不好么?)。第二個確保 URL 是正確的。

    請注意:至少在我自己的測試中,Struts 沒有生成 URL 驗證方法 的 JavaScript 版本。這意味著如果所有的表單字段都包含正確的數據,而獨獨 URL 字段不包含,那么客戶端驗證會通過但是服務器端驗證會失敗。這并不是可能發生的最壞的事情,因為 URL 字段仍然會得到驗證,但是我期望在 Struts 的未來版本中,這個問題會得到糾正。在任何情況下,顯示沒有理由可以停用 url 規則。)

    ?

    使用 mask 規則

    在許多情況下文本數據需要采用特殊的格式;但是 Struts 不可能解決所有這些可能的格式:電話號碼、電子郵件地址、URL、郵編、駕駛證號......這個列表在不斷地增長。所以,Struts 只處理最常見的(emailurl),而為其他格式提供了 mask 規則。使用正則表達式,可以用 mask 規則指定自己的文本模式。

    如果對于正則表達式比較熟悉,那么這就是小菜一碟。(對正則表達式的介紹超出了本教程的范圍。如果需要幫助,請參閱 參考資料 獲得關于正則表達式的更多內容。例如,可以這樣定義 phone 字段的規則:

    												
    														<field property="phone"
        depends="required,mask">
      <arg0 key="prompt.phone" />
      <var>
        <var-name>mask</var-name>
        <var-value>^\(?(\d{3})\)?[-| ]?(\d{3})[-| ]?(\d{4})$</var-value>
      </var>
    </field>
    												
    										

    這是一個使用得很普遍的模式,它允許輸入各種流行的電話格式。如果使用了錯誤的表單,Validator 會輸出關于錯誤數據的消息。

    但是,可以容易地在多個地方使用同一個掩碼。每次使用時不必重新定義,只要把掩碼定義移動到 global constant 即可。請把下面的內容添加到 validation.xml 文件中的 global 元素內(靠近文件頂部):

    												
    														<global>
      <constant>
        <constant-name>phone</constant-name>
        <constant-value>^\(?(\d{3})\)?[-| ]?(\d{3})[-| ]?(\d{4})$</constant-value>
      </constant>
    </global>
    
    												
    										

    現在修改 phone 字段的條目,像下面這樣使用新的常數掩碼值:

    												
    														<field property="phone"
        depends="required,mask">
      <arg0 key="prompt.phone" />
      <var>
         <var-name>mask</var-name>
         <var-value>${phone}</var-value>
      </var>
    </field>
    
    												
    										

    現在在整個應用程序的驗證規則中,都可以用其他形式重用這個模式。

    最后,請注意,我沒有提供 Validator 內置規則的完整列表。這是有意的,因為這些規則在不斷地變化,隨時都有對新規則的支持出現。對于最新的規則集,請查看在線的 Struts Validator 開發指南(請參閱 參考資料 獲得鏈接)。誰知道在您閱讀這篇教程的時候會有什么有趣的規則可用呢?

    ?

    在 JSP 中支持驗證

    這些規則都不錯,但是仍然有一個顯著的問題:JSP 頁面沒有辦法報告錯誤!例如,如果這里重新部署應用程序,將會發現用錯誤的值 提交驗證表單不會 轉向 success.jsp。這是對的,也是朝著正確方向的一步。但是,它也特別令人郁悶;表單只是在瀏覽器中重新出現,至于出了什么錯誤卻沒有任何指示。

    請打開 pages/test-validation.jsp 來處理這個問題。首先,需要提供了一個地方,供發生錯誤時顯示。這可以由 html:errors 元素很好地處理。請把以下內容插在 html:form 元素前:

    												
    														<%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib uri="/tags/struts-bean" prefix="bean" %>
    <%@ taglib uri="/tags/struts-html" prefix="html" %>
    
    <html:xhtml />
    
    <html>
     <head>
      <title><bean:message key="valid.title" /></title>
     </head>
    
    														

    <html:errors />
    <html:form action="/SubmitValid" focus="username">

    如果現在重新部署,并試著輸入錯誤數據,將開始看到錯誤消息,如圖 4 所示:


    圖 4. 用錯誤數據提交表單現在會觸發錯誤消息
    ?struts-error.jpg

    現在朝著真正堅固的驗證又進了一步。但是,仍然在服務器端;在提交表單時會得到討厭的閃爍,然后不得不等待服務器響應。這里的目標是用 JavaScript 編碼的驗證(或者更好一些,不必為了每個表單手工編寫 JavaScript)。高興的是,只要幾個額外標記,Validator 就允許把它的服務器端代碼轉換成客戶端 JavaScript 腳本:

    												
    </html:form> <html:javascript formName="ValidationForm" cdata="false" /> </body>

    不是很多哦!只有一行代碼,但是它告訴 Struts 插入所有支持表單客戶端驗證的 JavaScript。還請注意非常重要的 cdata 屬性。必須 把它設置成 false,否則客戶端驗證不會工作。如果把它設置成 true(默認設置),那么 Struts 生成的 HTML 會把 JavaScript 放在 <![CDATA[]]> 標記內。由于一些我不太清楚的原因,多數現代瀏覽器(Mozilla Firefox 和 Safari 在其中最出名)會忽略這樣包含的 JavaScript,所以客戶端驗證不會執行。

    在這一階段,我要指出,即使忘記了 cdata=false 這一部分,仍然可以得到驗證,只不過是在服務器端而已。在任何情況下,Validator 在服務器端都會驗證數據,所以如果忘記了這個屬性、甚至關閉 JavaScript 或跳過它,也都會得到一個備份。使用 Validator 有一個很好的副作用 —— 它會嘗試并捕獲每個可能的錯誤。

    (說明:如果按照作者的說法,得不到下面的測試結果,還需要修改一個地方)
    修改文件test-validation.jsp,增加黃色背景部分
    <html:form?action="/SubmitValid"?onsubmit="validateValidationForm(this)"??focus="username">


    測試完成的應用程序

    啟用 JavaScript 后,最后一次重新部署應用程序,并輸入各種錯誤數據。單擊 Submit,將得到一個精彩的客戶端錯誤列表(如圖 5、6、7 所示)。這可能是您惟一的一次因為看到錯誤消息而興奮!


    圖 5. 口令太短
    ?struts-error_password.jpg

    圖 6. 電話號碼格式不對
    ?struts-error_phone.jpg

    圖 7. 錯誤的電子郵件確實被當作錯誤
    ?struts-error_email.jpg

    這些消息是順序處理的,主要由 Validator 引擎決定一次處理多少消息。換句話說,有可能得到一條消息指示多個為空的字段必須填寫。但是,單擊 OK 并糾正這個錯誤之后,還會出現不同的錯誤(例如電話號碼格式不對)。Validator 總是只呈現一個對話框,但是這個對話框可以包含多個錯誤。雖然 Validator 有選擇地呈現這些錯誤,但是它還是會確保在允許用戶繼續操作之前,要滿足所有驗證規則。

    結束語

    結束語

    這篇教程看起來可能更像一大堆配置而不是編程。我更多是一個編碼人員,但是有時您不得不花大量的配置時間,以便可以少些編碼時間。沒有 Validator 或者類似的組件,就不得不編寫 Java 或 JavaScript 代碼,對 Struts 表單上的每個輸入框手工進行驗證。即使熱愛編碼的人也恨透了編寫驗證句柄,特別是憎恨一遍又一遍地編寫。

    現在應當已經從 Struts 示例應用程序和本教程介紹的驗證規則構建了一個可工作的 Validator 設置和一個好的測試環境。當我在新機器上安裝 Tomcat、Struts 和 Validator 時,我經常使用這個正確的設置;它可以幫我免除跟蹤錯誤的麻煩。另外,對于您現在和未來的 Web 應用程序,也可以使用這個配置。

    通過本教程,您應當已經對 Struts 和 Validator 組件真正有了些熟悉,特別是對它們的配置文件。甚至您現在還沒有使用 Validator 組件,也應當有助于您掌握 Struts 安裝。

    不論您如何使用本教程,我都希望它會把您的 Struts 開發(和驗證)帶上一個層次!希望您喜歡!

    下載

    描述文件名稱文件大小?下載方法
    Sample codej-strutsvalcode.zip2 MB?FTP

    參考資料

    學習

    關于作者

    作者照片

    Brett McLaughlin 從 Logo 時代(還記得那個小三角么?)就從事計算機工作。最近幾年,他已經成為 Java 技術和 XML 社區最著名的作者和程序員之一。他為 Nextel Communications 工作過,實現了復雜的企業系統;在 Lutris Technologies 工作,實際編寫了應用服務器;最近是在 O'Reilly Media, Inc. 工作,在這里他繼續編寫和編輯這方面的書籍。他的最新大作 Java 1.5 Tiger: A Developer's Notebook是關于最新版本 Java 技術的第一本圖書,他經典的 Java and XML保持著在 Java 語言中使用 XML 技術的權威作品之一的地位。

    主站蜘蛛池模板: 亚洲色大网站WWW永久网站| 亚洲五月激情综合图片区| 国产亚洲欧洲Aⅴ综合一区 | 91香蕉国产线在线观看免费| 91精品免费不卡在线观看| 国产成人午夜精品免费视频| 日本a级片免费看| 亚洲人成精品久久久久| 亚洲美女一区二区三区| 亚洲免费网站观看视频| 人妻巨大乳hd免费看| 一级做a爰全过程免费视频| 免费中文熟妇在线影片| 免费人成网站在线播放| 久久亚洲精品成人| 亚洲第一男人天堂| 狠狠躁狠狠爱免费视频无码| 久久精品人成免费| 免费v片在线观看无遮挡| 亚洲av无码片在线播放| 亚洲精品永久在线观看| 三级黄色免费观看| 一个人看的www在线观看免费| 亚洲国产一区视频| 亚洲精品在线视频观看| 午夜亚洲乱码伦小说区69堂| 性xxxx视频免费播放直播| 在线免费不卡视频| 久久精品国产亚洲AV麻豆不卡| 亚洲老熟女五十路老熟女bbw| 国产在线观a免费观看| 最近中文字幕无吗免费高清| 亚洲一区AV无码少妇电影☆| 亚洲永久在线观看| 中文字幕免费播放| 午夜两性色视频免费网站| 亚洲阿v天堂在线| 含羞草国产亚洲精品岁国产精品 | 免费h黄肉动漫在线观看| 亚洲欧洲在线观看| 偷自拍亚洲视频在线观看99|