Struts2中的校驗框架

Struts2提供的客戶端校驗
儘管這種支持比較弱,但採用Struts2中的客戶端校驗時需要注意以下幾點
1..將<s:form validate="true">的validate屬性設置爲TRUE
2..不能將<s:form theme="">的theme屬性設置爲simple
3..建議將<s:form/>的action和namespace屬性分開寫
4..可以在頁面中使用<s:head/>標籤來引入樣式
5..最好不要使用Struts2提供的客戶端校驗
設置validate="true"之前和之後的JSP頁面在運行時的源代碼是不同的
設置該屬性之前,表單的οnsubmit="return true;"
設置該屬性之後,表單的οnsubmit="return validateForm_register();"
並且在源碼中多出了一段函數名爲validateForm_register()的JavaScript代碼
這個函數的具體內容與ValidateFrameAction-validation.xml中設置的內容很相似
並且Struts2的客戶端驗證的提示信息都是顯示在表格中各個字段正上方的
這種顯示是很死板的,遠遠不如我們自己編寫JavaScript代碼來的強大
Struts2爲我們提供的客戶端校驗,在使用起來很不方便,故不推薦使用
所以儘管Struts2是很好的一個框架,但並不是說它的所有功能都是非常棒的
它所提供的客戶端校驗猶如雞肋一般,所以我們更多的還是自己編寫JavaScript代碼
在實際開發中,也幾乎不會使用到Struts2提供的客戶端校驗
使用的更多的還是它的服務端的校驗,這也是Strtus2的強項

Struts2提供的校驗框架
對於一個健壯的項目應用來說,僅僅提供一個客戶端校驗,是不安全的
因爲有些惡意的用戶可能會嘗試着不通過Web網頁的方式來訪問
可以通過遠程登錄的方式訪問某臺主機的某個資源,這時就完全脫離了瀏覽器,脫離了HTML
直接通過HTTP底層的協議來發送信息,此時就可以繞過輸入信息的頁面而直接向服務器發送請求
也就是說,服務器端的驗證,是整個請求的最後一道防線
而Struts2恰好爲我們提供了一個校驗框架,用於在服務端驗證前臺提交過來的表單
在Struts2中,它的每一個校驗框架都對應着每一個Action,而且它的命名是有限制的
比如相對於validateFrameAction而言,它的驗證框架就必須爲validateFrameAction-validation.xml
其中-validation.xml是固定不變的。然後在它前面加上Action名字之後,Struts2就可以識別了
並且校驗文件必須與它所對應的Action類處於同一目錄下
使用該驗證框架的兩個條件:1..使用validation攔截器,2..它所驗證的Action需要繼承ActionSupport類
並且當驗證失敗出現message時,它會轉向到INPUT頁面來顯示message消息

字段校驗和非字段校驗
所謂的字段校驗,即校驗ValidateFrameAction中的屬性。一個<field>表示對Action中的一個屬性的校驗
字段校驗,屬於是字段優先。即我去校驗誰,然後是我用誰去校驗
非字段校驗,則校驗器優先。即我用誰去校驗,然後是我去校驗誰
即字段校驗中先定義name="username"對哪個字段校驗,再定義type="requiredstring"如何校驗
而非字段校驗先定義type="requiredstring"確定校驗器,再定義name="fieldName"指定所校驗的屬性
字段校驗和非字段校驗的本質都是一樣的,只是說話的順序不同罷了。反映到底層後,二者實質上都是一樣的
相對來說不推薦使用非字段驗證,實際應用中如果需要驗證的字段非常多的話,那麼在維護的時候就比較困難了

深剖Struts2校驗框架的本質
展開xwork-2.0.4.jar中的com.opensymphony.xwork2.validator.validators包裏面發現有很多的校驗類
因此,我們知道,我們現在所使用的這種校驗框架,實際上就是由Struts2已經給我們提供好的一些類
這些類來校驗客戶端的表單的輸入請求,這些類,這些校驗,都是由Struts2已經內置好的了,我們可以直接使用
然後打開包裏面的default.xml文件,就可以知道<field-validator>中type是取值於default.xml文件的
expression和fieldexpression都是用於OGNL表達式的判斷,分別返回Action級別和Field級別的錯誤
conversion用於格式轉換出現錯誤時的判斷。stringlength判斷字符串長度。regex用於正則表達式的判斷

對Action中某一方法的校驗
假設在validateFrameAction中存在test()方法,如果對test()方法進行校驗的話
那麼就可以提供一個類似於validateFrameAction-test-validation.xml的文件
但是,validateFrameAction-validation.xml仍會被校驗
也就是說,如果validateFrameAction-validation.xml和validateFrameAction-test-validation.xml共存的話
那麼Struts2會先校驗validateFrameAction-validation,然後再校驗validateFrameAction-test-validation
但前提是,配置<action/>時,所調用的不是execute()方法,而是method="test",即調用的Action中的是test()方法
所以,假如一個Action中存在多個處理邏輯,那麼就不要再提供validateFrameAction-validation.xml全局校驗
而是建議爲具體的每一個方法提供對應的類似於validateFrameAction-test-validation.xml的局部的校驗文件

校驗文件與Action中的validate()共存時
如果在提供了校驗文件的同時,也重寫了Action中的validate()方法,那麼二者都會執行
當校驗的信息不是特別複雜的時候,推薦儘量使用校驗文件的方式
當校驗的信息特別特別複雜的時候,可以使用validate()方法,即硬編碼的方式進行校驗
如果validateFrameAction-validation.xml與validateFrameAction中的validate()共存的話
那麼執行順序是:校驗文件先執行,validate()後執行。假設二者都對username進行了校驗設置
那麼後執行的validate()並不會沖刷掉先執行的校驗文件中設置的信息,二者都會輸出
由於先執行校驗文件,所以首先顯示的是校驗文件中的錯誤提示信息,後顯示validate()的信息
另外,我們可以在Debug模式下運行項目,然後判斷出校驗文件和validate()的執行順序
首先在validationAwareSupport類的addFieldError()方法中設置斷點
然後以Debug模式運行,通過按F6在Debug中的Variables視圖裏觀察errorMessage顯示的信息的先後來判斷
最後得到的結果就是校驗文件先執行,而validate()方法是後執行的
而Struts2會先將校驗文件中<message/>放到與username的Key對應Value的ArrayList中,即增加一行錯誤消息
當Action中的validate()方法中的this.addFieldError("username","aaaaaaaaaaa")執行時
它就會將aaaaaaaaaaa直接放到Key爲userame所對應的ArrayList中
因此當執行完validate()中的this.addFieldError()方法時,內存中的情況是這樣的
一個username作爲一個Key,它的Value是一個ArrayList,而此時的ArrayList裏面包含了兩個元素
第一個元素是校驗文件裏面<message/>中的信息,第二個元素就是aaaaaaaaaaa
由於在頁面中採用的是Struts2的標籤庫,所以,它會將ArrayList中的信息全部都迭代取出來
因此在頁面中就會先顯示校驗文件中的<message/>信息,然後顯示addFieldError()所設定的錯誤信息
備註:這裏所說的東西,如果看不明白的話,可以先看看下面的剖析addFieldError()方法

子類Action中的方法的校驗細節
甚至還存在一種特殊的情況,比如ParentAction{test}和ChildAction extends ParentAction{test}
如果同時提供了ParentAction-validation.xml和ParentAction-test-validation.xml文件的話
並且對應子類也提供了ChildAction-validation.xml和ChildAction-test-validation.xml文件
我們想對子類中的test()方法進行校驗,那麼它的執行流程如下
先執行ParentAction-validation.xml文件,再執行ParentAction-test-validation.xml文件
再執行ChildAction-validation.xml文件,最後執行ChildAction-test-validation.xml文件
就好似類的繼承,在New子類的一個實例的時候,會先New出父類的對象,然後才New出子類的對象
先有父親,再有孩子嘛。校驗也是這樣的。但是我們不推薦將Action定義成這樣
僅僅是對子類的test()方法進行校驗,竟然需要調用四個校驗文件,很不合理
就這種情況而言,輕易不會發生,僅供瞭解

Struts2中的兩種類型的錯誤信息
在Struts2中,提示的錯誤信息有兩種,一種是Field級別的,一種是Action級別的
將錯誤信息放到ActionError的過程中,實際上是把錯誤信息放到Arraylist()中了
將錯誤信息放到FieldError的過程中,實際上是把錯誤信息放到Map()中了
這個Map的key就是屬性的名字,它的value就是增加的錯誤消息
當FileError或者ActionError中包含錯誤信息時,Struts2就會認爲類型轉換是錯誤的
然後就會轉向到INPUT頁面,而不會執行execute()方法
如果在Action中將某一個出錯信息放到了addFieldError()裏面的話
那麼就可以在JSP頁面中使用<s:fielderror/>標籤將FieldError中的信息輸出
另外,儘管Struts2內置了錯誤信息顯示的功能,但是它也只能顯示FileError中的錯誤信息
但我們可以通過手工添加<s:actionerror/>標籤在頁面中顯示ActionError裏的錯誤信息

剖析addFieldError()方法

Java代碼
  1. //通過查看父類ActionSupport.java的源碼,查找到了該方法的原形,代碼如下
  2. public void addFieldError(String fieldName,String errorMessage){
  3. validationAware.addFieldError(fieldName,errorMessage);
  4. }
  5. //fieldName代表屬性的名字,errorMessage代表錯誤的消息
  6. //validationAware是一個validationAwareSupport類型的一個實例
  7. //validationAwareSupport類實現了validationAware和Serializable接口
  8. //validationAwareSupport類中的addFieldError()方法的代碼如下所示
  9. public synchronized void addFieldError(String fieldName,String errorMessage){
  10. final Map errors = internalGetFieldErrors();
  11. List thisFieldErrors = (List) errors.get(fieldName);
  12. if (thisFielsErrors == null){
  13. thisFielsErrors = new ArrayList();
  14. errors.put(fieldName, thisFielsErrors);
  15. }
  16. thisFielsErrors.add(errorMessage);
  17. }
  18. //這是非常非常重要的方法,通過它的代碼就足以顯示出FieldError中的Map裏面到底是什麼東西
  19. //而internalGetFieldErrors方法也是在validationAwareSupport類中定義的,它的代碼如下
  20. private Map internalGetFieldErrors(){
  21. if (fieldErrors == null){
  22. fieldErrors = new LinkedHashMap();
  23. }
  24. return fieldErrors;
  25. }

這裏的fieldErrors是validationAwareSupport類定義的私有的Map類型的成員變量
LinkedHashMap是Map的一個具體的實現,它使用列表的方式來實現的
也就是說,首先判斷fieldErrors是否爲空。起初fieldErrors肯定爲空
那麼既然它是空的,那麼就實例一個LinkedHashMap對象,賦給fieldErrors並返回它
接着在addFieldError()方法中用final的Map類型的errors接收LinkedHashMap類型的fieldErrors
所以說真正存放Field級別錯誤信息的對象是LinkedHashMap
然後通過ListthisFieldErrors=(List)errors.get(fieldName);代碼可以發現
它是使用LinkedHashMap類型的errors.get()一個String類型的Key,然後將返回的Value值再轉換成List類型
因此我們可以很明確的大膽的說出來:對於LinkedHashMap,它的key是一個String,它的value是一個List
接下來執行if()語句。如果它得到的value值是null,那麼它就會New一個ArrayList()
換句話說,這個List類型的value是用一個ArrayList()來實現的
所以說該LinkedHashMap的key是String類型的,value是ArrayList類型的
由於它的value是ArrayList類型的,所以它的一個key所對應的value裏面就可以存放多個值
只要調用了validationAwareSupport類中的addFieldError()方法的話,就說明已經有一個錯誤發生了
那麼它首先會針對於fieldName的名字,找到它對應的value
如果value爲空,說明與fieldName所對應的value根本就不存在
也就是說LinkedHashMap中並沒有這一行映射,因此它就直接給我們New出來一個新的ArrayList
然後將fieldName和剛剛生成好的ArrrayList放置到LinkedHashMap中
此時的LinkedHashMap中的Key就是表單裏的輸入域的name值,Value是一個空的ArrayList
然後再執行thisFielsErrors.add(errorMessage);也就是在ArrayList中增加一條錯誤信息

剖析addFieldError()方法

Java代碼
  1. //通過查看父類ActionSupport.java的源碼,查找到了該方法的原形,代碼如下
  2. public void addActionError(String anErrorMessage){
  3. validationAware.addActionError(anErrorMessage);
  4. }
  5. //而validationAwareSupport類中的addActionError()方法的代碼如下所示
  6. public synchronized void addActionError(String anErrorMessage){
  7. internalGetActionErrors.add(anErrorMessage);
  8. }
  9. //而internalGetActionErrors方法也是在validationAwareSupport類中定義的,它的代碼如下
  10. private Collection internalGetActionErrors(){
  11. if (actionErrors == null){
  12. actionErrors = new ArrayList();
  13. }
  14. return actionErrors;
  15. }

所以說:對於Action級別的錯誤信息,實際上是放置在ArrayList中的



關於getFieldErrors()的使用誤區
com.opensymphony.xwork2.ActionSupport類之所以非常重要
就是因爲它已經實現了很多很多的接口,而這些接口都是用來處理不同的事情的
在ActionSupport中有很多的方法,其實只要明白了ActionError和FieldError的區別的話
對於這裏的很多關於Error的方法,直接看一下API文檔,然後再跟蹤一下代碼,就都一目瞭然了
有一個在日常開發中,很容易犯錯誤的一個地方,需要強調一下,那就是getFieldErrors()方法
它是這樣的:public Map getFieldErrors()
它的描述是:得到Field級別的錯誤消息,並關聯到當前Action,不應該直接在這裏增加錯誤消息
因爲這個實現,可以隨意的返回一個新的Collection或者是不可修改的Collection
先舉個例子:正常情況下是通過this.addFieldError("username","22");往Field中增加一個錯誤信息
但是有人可能有這樣一種思路:先通過this.getFieldErrors()得到一個與Field所對應的LinkedHashMap
然後再執行this.getFieldErrors().put("username", "88");往LinkedHashMap中增加一條信息
但是通過實際操作,運行項目後,發現沒有輸出"88"錯誤信息。這時就需要研究一下getFieldErrors()方法

剖析getFieldErrors()方法

Java代碼
  1. //通過查看父類ActionSupport.java的源碼,查找到了該方法的原形,代碼如下
  2. public Map getFieldErrors(){
  3. return validationAware.getFieldErrors();
  4. }
  5. //而validationAwareSupport類中的getFieldErrors()方法的代碼如下所示
  6. public synchronized Map getFieldErrors(){
  7. return new LinkedHashMap(internalGetFieldErrors());
  8. }

這時,我們就可以很清楚的知道,它實際上是返回了一個LinkedHashMap的一個副本
實際上this.getFieldErrors().put("username", "88")所增加的信息
是增加到了以前的FieldError的一個副本里面了,根本沒有對以前的FieldError有任何影響
這裏需要注意一下,實際上它並不是真正的return出來了一個原來的集合
而是return出來了一個用原來集合的內容作爲參數的一個LinkedHashMap的一個副本
很多人都會犯這個錯誤
因爲根據我們通常意義上的理解,this.getFieldErrors()應該返回的是一個LinkedHashMap本身
但是實際上它返回的是LinkedHashMap的一個副本。所以在Struts2的API中對該方法有這樣的一段描述
Error messages should not be added directly here
as implementations are free to return a new Collection or an Unmodifiable Collection
這個getFieldErrors就相當於返回了一個只讀的屬性
我們只可以把它get出來,然後讀它的內容,但是不能再往裏面增加或者修改裏面的任何內容


下面是示例工程,這是一個Struts2.0.11應用

首先是web.xml文件

Xhtml代碼
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  5. http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  6. <filter>
  7. <filter-name>struts2</filter-name>
  8. <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
  9. </filter>
  10. <filter-mapping>
  11. <filter-name>struts2</filter-name>
  12. <url-pattern>/*</url-pattern>
  13. </filter-mapping>
  14. <welcome-file-list>
  15. <welcome-file>validateFrame.jsp</welcome-file>
  16. </welcome-file-list>
  17. </web-app>

然後是用於提供表單輸入的validateFrame.jsp頁面

Xhtml代碼
  1. <%@ page language="java" pageEncoding="UTF-8"%>
  2. <%@ taglib prefix="s" uri="/struts-tags"%>
  3. <s:form action="validateFrame" theme="simple">
  4. <table border="9">
  5. <tr>
  6. <td>姓名</td>
  7. <td><s:textfield name="username" id="usernameId"/></td>
  8. <%-- 在字段的後面顯示錯誤信息,如此稍顯人性化 --%>
  9. <td>
  10. <s:fielderror cssStyle="font-size:20px;color:red;text-align:left;font-weight:bold">
  11. <s:param>username</s:param>
  12. </s:fielderror>
  13. </td>
  14. </tr>
  15. <tr>
  16. <td>密碼</td>
  17. <td><s:password name="password" id="passwordId"/></td>
  18. <td>
  19. <s:fielderror cssStyle="font-size:20px;color:red;text-align:left;font-weight:bold">
  20. <s:param>password</s:param>
  21. </s:fielderror>
  22. </td>
  23. </tr>
  24. <tr>
  25. <td>重複密碼</td>
  26. <td><s:password name="repassword" id="repasswordId"/></td>
  27. <td>
  28. <s:fielderror cssStyle="font-size:20px;color:red;text-align:left;font-weight:bold">
  29. <s:param>repassword</s:param>
  30. </s:fielderror>
  31. </td>
  32. </tr>
  33. <tr>
  34. <td>年齡</td>
  35. <td><s:textfield name="age"/></td>
  36. <td>
  37. <s:fielderror cssStyle="font-size:20px;color:red;text-align:left;font-weight:bold">
  38. <s:param>age</s:param>
  39. </s:fielderror>
  40. </td>
  41. </tr>
  42. <tr>
  43. <td>生日</td>
  44. <td><s:textfield name="birthday"/></td>
  45. <td>
  46. <s:fielderror cssStyle="font-size:20px;color:red;text-align:left;font-weight:bold">
  47. <s:param>birthday</s:param>
  48. </s:fielderror>
  49. </td>
  50. </tr>
  51. <tr>
  52. <td>畢業時間</td>
  53. <td><s:textfield name="graduation"/></td>
  54. <td>
  55. <s:fielderror cssStyle="font-size:20px;color:red;text-align:left;font-weight:bold">
  56. <s:param>graduation</s:param>
  57. </s:fielderror>
  58. </td>
  59. </tr>
  60. <tr>
  61. <td>&nbsp;</td>
  62. <td><s:submit value="校驗框架測試"/></td>
  63. </tr>
  64. </table>
  65. </s:form>

當表單輸入域均正確時的validateSuccess.jsp頁面

Xhtml代碼
  1. <%@ page language="java" pageEncoding="UTF-8"%>
  2. <%@ taglib prefix="s" uri="/struts-tags"%>
  3. 姓名:<s:property value="username"/><br/>
  4. 密碼:<s:property value="password"/><br/>
  5. 年齡:<s:property value="age"/><br/>
  6. 生日:<s:property value="birthday"/><br/>
  7. 畢業:<s:property value="graduation"/>

然後是struts.xml文件

Xhtml代碼
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE struts PUBLIC
  3. "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
  4. "http://struts.apache.org/dtds/struts-2.0.dtd">
  5. <struts>
  6. <package name="struts2" extends="struts-default">
  7. <action name="validateFrame" class="com.jadyer.action.ValidateFrameAction" method="test">
  8. <result>/validateSuccess.jsp</result>
  9. <result name="input">/validateFrame.jsp</result>
  10. </action>
  11. </package>
  12. </struts>

然後是用到的Action類

Java代碼
  1. package com.jadyer.action;
  2. import java.util.Date;
  3. import com.opensymphony.xwork2.ActionSupport;
  4. @SuppressWarnings({"serial", "unused"})
  5. public class ValidateFrameAction extends ActionSupport {
  6. private String username;
  7. private String password;
  8. private String repassword;
  9. private int age;
  10. private Date birthday;
  11. private Date graduation;
  12. /* 以上六個屬性的setter和getter略 */
  13. public String execute() throws Exception {
  14. System.out.println("------execute is invoked------");
  15. return SUCCESS;
  16. }
  17. public String test() throws Exception {
  18. System.out.println("------test is invoked------");
  19. return SUCCESS;
  20. }
  21. }

最後是用到的驗證框架文件ValidateFrameAction-validation.xml

Xhtml代碼
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
  3. "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
  4. <!-- *************************************************************************************************** -->
  5. <!-- 一個<field>表示對Action中的一個屬性的校驗,它的name值要與Action的屬性名一致 -->
  6. <!-- <field-validator/>表示對屬性校驗的方式 -->
  7. <!-- requiredstring用來校驗String的屬性是必填的,此外都要用required來驗證必填 -->
  8. <!-- 校驗失敗時,即用戶輸入的信息不符合要求時,就會顯示<message/>中設定的提示信息 -->
  9. <!-- *************************************************************************************************** -->
  10. <!-- 而<param name="trim">true</param>則表示忽略掉字符串左右兩邊出現的空格 -->
  11. <!-- 事實上requiredstring會自動將字符串左右兩邊的空格去掉,所以它可寫可不寫 -->
  12. <!-- 因爲在RequiredStringValidator源碼中的doTrim屬性默認的就是TRUE -->
  13. <!-- 雖然RequiredStringValidator中的屬性名是doTrim,但不可以寫成name="doTrim" -->
  14. <!-- 因爲它真正的值取決於public void setTrim(boolean trim)中的參數的值 -->
  15. <!-- *************************************************************************************************** -->
  16. <!-- <field-validator/>還有一個short-circuit屬性,用來表示短路,默認值爲FALSE -->
  17. <!-- 對於邏輯與來說,前面如果爲假,後面就不再判斷了,直接短路 -->
  18. <!-- 對於邏輯或來說,前面如果爲真,後面也不再判斷了,直接短路 -->
  19. <!-- 所以,如果short-circuit的值爲TRUE的話 -->
  20. <!-- 當username的requiredstring驗證失敗,就不再執行stringlength驗證了 -->
  21. <!-- *************************************************************************************************** -->
  22. <!-- 可以使用stringlength驗證字符串的長度,並用minLength和maxLength限定長度範圍 -->
  23. <!-- 運行時${minLength}就會自動被6替換掉,${maxLength}就會被10替換掉 -->
  24. <!-- 也可以利用<message/>進行國際化,如<message key="username.xml.invalid"/> -->
  25. <!-- 無論是字段驗證還是非字段驗證,產生的<message/>信息都會放到FieldError中 -->
  26. <!-- 所以需要在前臺頁面中使用<s:fielderror/>來顯示錯誤提示信息 -->
  27. <!-- *************************************************************************************************** -->
  28. <validators>
  29. <field name="username">
  30. <field-validator type="requiredstring" short-circuit="true">
  31. <param name="trim">true</param>
  32. <message>username should not be blank</message>
  33. </field-validator>
  34. <field-validator type="stringlength">
  35. <param name="minLength">6</param>
  36. <param name="maxLength">10</param>
  37. <message>username should be between ${minLength} and ${maxLength}</message>
  38. </field-validator>
  39. </field>
  40. <!-- **********這裏只列舉出username的非字段校驗寫法,其餘字段寫法與其類似********* -->
  41. <!--
  42. <validator type="requiredstring">
  43. <param name="fieldName">username</param>
  44. <message>username should not be blank!</message>
  45. </validator>
  46. <validator type="stringlength">
  47. <param name="fieldName">username</param>
  48. <param name="minLength">6</param>
  49. <param name="maxLength">10</param>
  50. <message>username should be between ${minLength} and ${maxLength}</message>
  51. </validator>
  52. -->
  53. <field name="password">
  54. <field-validator type="requiredstring">
  55. <message>password should not be blank</message>
  56. </field-validator>
  57. <field-validator type="stringlength">
  58. <param name="minLength">6</param>
  59. <param name="maxLength">10</param>
  60. <message>password should be between ${minLength} and ${maxLength}</message>
  61. </field-validator>
  62. </field>
  63. <field name="age">
  64. <field-validator type="int">
  65. <param name="min">1</param>
  66. <param name="max">150</param>
  67. <message>age should be between ${min} and ${max}</message>
  68. </field-validator>
  69. </field>
  70. <field name="birthday">
  71. <field-validator type="required">
  72. <message>birthday should not be blank</message>
  73. </field-validator>
  74. <field-validator type="date">
  75. <param name="min">2002-09-09</param>
  76. <param name="max">2003-08-28</param>
  77. <message>birthday should be between ${min} and ${max}</message>
  78. </field-validator>
  79. </field>
  80. </validators>
  81. <!-- **********關於repassword屬性的校驗,與password類似,故略去********** -->
  82. <!-- **********關於graduation屬性的校驗,與birthday類似,故略去********** -->


另附:ValidateFrameAction-validation.xml的補充說明

Xhtml代碼
  1. <!-- ******************【type="fieldexpression"】************************************************************************ --&gt;
  2. <!-- 下面的password.equals(repassword)不是字符串,而是OGNL表達式 -->
  3. <!-- 因爲Action中的屬性會被自動放到ValueStack裏面,所以纔可以在這裏使用OGNL -->
  4. <!-- 通常人們不會將錯誤放到Action級別中,而是普遍性的都放到FieldError中 -->
  5. <!-- 在進行數據庫驗證,比如用戶名已存在時等等,才把錯誤消息放到ActionError中 -->
  6. <!-- 另外,如果在Action使用的是領域模型接收表單參數的話,那麼這裏就應該寫成user.password等等 -->
  7. <!-- 因爲放在ValueStack裏面的是user對象,而不是password屬性 -->
  8. <field name="password">
  9. <field-validator type="fieldexpression">
  10. <param name="expression">password.equals(repassword)</param>
  11. <message>密碼不一致</message>
  12. </field-validator>
  13. </field>
  14. <!-- ******************【type="visitor"】******************************************************************************** --&gt;
  15. <!-- 使用visitor驗證類型可以實現驗證框架的複用,所以人們比較喜歡這個驗證類型 -->
  16. <!-- 在使用的時候,首先<field name="">的name不是某一個字段,而是一個對象 -->
  17. <!-- 而且該對象必須在validateFrameAction中出現,並提供setXxx和getXxx方法 -->
  18. <!-- 比如User對象,在validateFrameAction中提供了private User user;及對應的setUser()和getUser()方法 -->
  19. <!-- 然後新建在com.zhangbing.bean.User.java的包中,即在com.zhangbing.bean包中建立User-validation.xml文件 -->
  20. <!-- 也就是說此時是對對象進行驗證,然後Struts2會根據Action中的對象找到與之對應的Bean類,也稱VO類 -->
  21. <!-- 然後就會找到與之同名的User-validation.xml文件,這個文件裏面寫的就是公共的驗證信息 -->
  22. <!-- 而User-validation.xml返回的信息會通過type="visitor"被嵌套在我們當前的文件中 -->
  23. <!-- 然後我們在頁面中使用<s:fielderror/>標籤就可以輸出驗證框架所產生的錯誤信息了 -->
  24. <field name="user">
  25. <field-validator type="visitor">
  26. <message>用戶:</message>
  27. </field-validator>
  28. </field>
  29. <!-- **********【下面簡單示例一下User-validation.xml中的內容】********** -->
  30. <?xml version="1.0" encoding="UTF-8"?>
  31. <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
  32. "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
  33. <validators>
  34. <field name="username">
  35. <field-validator type="requiredstring" short-circuit="true">
  36. <param name="trim">true</param>
  37. <message>username should not be blank</message>
  38. </field-validator>
  39. <field-validator type="stringlength">
  40. <param name="minLength">6</param>
  41. <param name="maxLength">10</param>
  42. <message>username should be between ${minLength} and ${maxLength}</message>
  43. </field-validator>
  44. </field>
  45. </validators>
  46. <!-- ******************【<param name="context">user</param& gt;】************************************************************ -->
  47. <!-- context參數用來指定上下文的名字,比如這裏定義的上下文是user,則對應User-user-validation.xml校驗文件 -->
  48. <!-- 其中<param name="appendPrefix">true</param>和<message>user's </message>經常成對出現 -->
  49. <!-- 參數appendPrefix用來指定是否在顯示給用戶的錯誤消息上添加前綴,而<message>用來指定所添加的文本 -->
  50. <field name="user">
  51. <field-validator type="visitor">
  52. <param name="context">user</param>
  53. <param name="appendPrefix">true</param>
  54. <message>user's </message>
  55. </field-validator>
  56. </field>
  57. <!-- ******************************************************************************************************************** -->
明天你還會愛我?
發佈了14 篇原創文章 · 獲贊 6 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章