使用Struts 2的輸入校驗
輸入校驗是所有的Web應用必須處理的問題。一個健壯的應用系統必須可以阻止一些非法的輸入,防止這些非法的輸入進入系統。這樣才可以保證系統不受到影響。</span> 輸入校驗可以分為客服端校驗和服務器端校驗。
服務器校驗:
服務器校驗是整個應用阻止非法數據的最后的防線,主要是通過在應用中編程實現。
Struts 2提供了基于驗證框架的輸入校驗,在這種校驗方式下,所有的輸入校驗只需要編寫簡單的配置文件,Struts 2的驗證框架將會負責進行服務器校驗。
如下表單:
假定在該應用中要求這三個請求參數必須滿足如下要求:
1、name和password只能是字母和數組,且長度必須在4到16之間。
2、年齡必須是1到150之間的整數。
<s:form action="regist" > <s:textfield name="name" label="用戶名"></s:textfield> <s:textfield name="password" label="密碼"></s:textfield> <s:textfield name="age" label="年齡"></s:textfield> <s:submit value="注冊"></s:submit> </s:form>
下面是該請求的Action代碼:
public class RegistAction extends ActionSupport { private String name; private String password; private int age; //省略上面三個屬性的getter和setter方法 public String execute() throws Exception { return SUCCESS; }
上面的Action中包含的execute方法,之間返回success字符串,不需要做任何的處理,所以這個Action不具備任何輸入校驗的功能。
但是通過為該Action指定一個校驗文件后,既可以利用Struts 2的輸入校驗功能對該Action進行校驗。
該校驗文件應該遵守以下的命名規則:
<Action name>-validation.xml
且該文件應該保持在和Action相同的路徑下。
校驗文件如下:
<validators> <!-- 校驗Action的name屬性 --> <field name="name"> <!-- 指定name屬性必須滿足的必填規則 --> <field-validator type="requiredstring"> <param name="trim">true</param> <message>必須輸入名字</message> </field-validator> <!-- 指定name屬性必須匹配正則表達式 --> <field-validator type="regex"> <param name="expression"><![CDATA[(\w{4,25})]]></param> <message>您輸入的用戶名只能是字母和數字,且長度必須在4到25之間</message> </field-validator> </field> <!-- 校驗Action的password屬性 --> <field name="password"> <!-- 指定password屬性必須滿足必填的規則 --> <field-validator type="requiredstring"> <param name="trim">true</param> <message>必須輸入密碼</message> </field-validator> <!-- 指定password屬性必須滿足匹配指定的正則表達式 --> <field-validator type="regex"> <param name="expression"><![CDATA[(\w{4,25})]]></param> <message>您輸入的密碼指定是字母和數字,且長度必須在4到25之間</message> </field-validator> </field> <!-- 校驗Action的age屬性 --> <field name="age"> <field-validator type="int"> <param name="min">1</param> <param name="max">150</param> <message>年齡必須在1到150之間</message> </field-validator> </field> </validators>
當輸入校驗失敗后,Struts 2是自動返回名為“input”的result,因此需要在struts.xml中配置名為"input"的Result.
如下:
<package name="myaction" extends="struts-default"> <action name="regist" class="com.app.action.RegistAction" > <result name="input">/regist.jsp</result> <result name="success">/welcome.jsp</result> </action> </package>
指定了校驗失敗后應用會跳轉到的物理資源頁面后,這樣我們就可以在該頁面中添加<s:fielderror/>來輸出錯誤提示
當用戶提交請求時,Struts 2的校驗框架會根據該文件對用戶請求進行校驗。如果用戶的輸入不滿足校驗規則,瀏覽器就會顯示相應的錯誤提示:
客服端校驗:
對于客服端校驗非常簡單,只需改變如下兩個地方:
1、將輸入頁面的表單元素全部改為使用Struts 2標簽來生成表單。
2、為該<s:form..../>元素增加validate="true"屬性
對于客服端校驗有三個地方需要注意:
1、Struts 2的<s:form.../>元素有一個theme屬性,不要將該屬性指定為simple。
2、瀏覽者不能直接訪問啟用客服端校驗的表單頁面,這樣會引起異常。我們可以把啟用客服端校驗的表單頁面放到WEB-INF路徑下,讓瀏覽者訪問所有資源之間都先經過它的核心Filter
3、啟動客服端校驗的表單頁面的action和namespace要分開寫。
例題和服務器校驗差不多。這里就不展示了......
校驗風格
Struts 2提供了兩種方式來配置校驗規則:
一種是字段優先,稱為字段校驗器風格
一種是校驗器優先,稱為非字段校驗器風格
字段校驗器器配置
對于字段校驗器配置,這是一種以字段優先的配置方式
使用字段校驗器配置風格時,每個字段校驗規則大致遵守如下形式:
<field name="被校驗的字段"> <field-validator type="校驗器名"> <!-- 此處需要為不同校驗器指定數量不等的校驗參數--> <param name="參數名">參數值</param> ...... <!-- 校驗失敗后的提示信息,其中key指定國際化信息的key--> <message key="I18Nkey">校驗失敗后的提示信息</message> </field-validator> <!-- 如果該字段需要滿足多個規則,下面可以配置多個校驗器--> </field>
非字段校驗器配置
對于非字段校驗器配置風格,是一種以校驗器優先的配置方式。
對于采用非字段校驗器風格的校驗規則文件,<validators.../>元素下有多個<validator.../>元素,每個<validator.../>元素都有如下格式:
<validator type="校驗器名"> <param name="fieldname">需要被校驗的字段</param> <!-- 此處需要為不同校驗器指定數量不等的校驗參數--> <param name="參數名">參數值</param> ..... <!-- 校驗失敗后的提示信息,其中key指定國際化信息的key--> <message key="I18Nkey">校驗失敗后的提示信息</message> </validator>
由于使用非字段校驗器的配置風格是,采用的是校驗器優先的方式,故必須為<validator.../>配置一個fieldName參數,該參數的值就是被校驗的Action的屬性名
短路校驗器
校驗規則文件的<validator..../>元素和<field-validator.../>元素可以指定一個可選的額short-circuit屬性,這個屬性指定該校驗器是否是短路校驗器。該屬性的默認值是false,即默認非短路校驗器。
對于校驗錯誤的信息輸出時,有時它會不友好的把所有的信息全部輸出來。
如:
你必須輸入密碼!!! 您輸入的密碼只能是字母和數字,且長度必須在4到16之間!!!
這種提示信息是很不友好的。而且第二條信息完全是多余的。所以,對于瀏覽者而言,如果校驗錯誤,只需要輸出相對應的錯誤提示信息,而不是一次輸出所有的校驗錯誤提示信息。
為了達到那種效果,我們可以使用短路校驗器。
采用短路校驗器只需要在<validator.../>元素或<field-validator.../>元素中增加short-circuit="ture"即可。
如下:
<validators> <!-- 校驗Action的name屬性 --> <field name="name"> <!-- 指定name屬性必須滿足的必填規則 --> <field-validator type="requiredstring" short-circuit="true"> <param name="trim">true</param> <message>必須輸入名字</message> </field-validator> <!-- 指定name屬性必須匹配正則表達式 --> <field-validator type="regex"> <param name="expression"><![CDATA[(\w{4,25})]]></param> <message>您輸入的用戶名只能是字母和數字,且長度必須在4到25之間</message> </field-validator> </field> </validators>
校驗順序和短路
校驗器增加了短路的特性后,校驗器的執行順序就非常重要了。因為前面的執行的校驗器可能會阻止后面的校驗器的執行。
校驗器的執行順序如下:
1、所有非字段風格的校驗器優先于字段風格的校驗器
2、所有非字段風格的校驗器中,排在前面的優先執行
3、所有字段風格的校驗器中,排在前面的會優先執行
校驗器短路的原則是:
1、所有非字段校驗器是最先執行的。如果某個非字段校驗器校驗失敗,則該字段上所 有字段校驗器都不會獲得校驗的機會。
2、非字段校驗器的校驗失敗,不會阻止其他非字段校驗的執行
3、如果一個字段校驗器校驗失敗后,則該字段下且排在該校驗失敗的校驗器之后的其他字段校驗器不會獲得校驗的機會。
4、字段校驗器都不會阻止非字段校驗器的執行。
內建校驗器
Struts 2提供了大量的內建校驗器,這些內建校驗器可以滿足大部分應用的校驗需求。
在xwork-core-2.2.1.jar文件中的com\opensymphony\xwork2\validator\validators路徑下的default.xml文件,該文件就是Struts 2默認的校驗器注冊文件。
<validators> <validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/> <validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/> <validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/> <validator name="long" class="com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator"/> <validator name="short" class="com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator"/> <validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/> <validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/> <validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/> <validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/> <validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/> <validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/> <validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/> <validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/> <validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/> <validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/> <validator name="conditionalvisitor" class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/> </validators>
通過上面可以發現,注冊一個校驗器只需要通過一個<validator.../>元素即可注冊一個校驗器,每一個<validator.../>元素的name屬性指定該校驗器的名字,class屬性指定該校驗器的實現類。
常用的內建校驗器
手動完成輸入校驗
對于一些特殊的校驗要求,對于Struts 2校驗器可以無法滿足,這時可能需要在Struts 2中進行手動校驗。由于Struts 2提供了良好的可擴展性,所有允許通過手動方式完成自定義校驗。
1、重寫validte()方法
我們可以通過重寫ActionSupport類的validate()方法來進行校驗
下面是重寫validate()方法的RegistAction代碼:
public class RegistAction extends ActionSupport { private String name; private String pass; private int age; //省略三個屬性的getter和setter方法 public void validate(){ System.out.println("進入validate 方法進行校驗"+name); if(!name.contains("ssy")){ addFieldError("user", "您的用戶名必須包括ssy!!!"); } } }
在validate方法中,一旦發現校驗失敗后,就會把校驗失敗提示通過addFieldError方法添加進系統的FieldError中。如果Struts 2發現系統的FieldError不為空,將會自動跳轉到input邏輯試圖,因此必須在struts.xml文件中為該Action的input邏輯試圖指定試圖資源。
當然為了顯示錯誤信息,應該在相應的jsp頁面增加如下代碼:
<s:fielderror/>
2、重寫validateXxx()方法
如果我們的輸入校驗只想校驗某個處理邏輯,那么重寫validate方法顯然不夠,因為validate方法無法準確知道需要校驗哪個處理方法,實際上,如果我們重寫validate方法,則該方法就會校驗所有的處理邏輯。
為了實現校驗指定處理邏輯,Struts 2的Action提供了一個validateXxx方法,其中xxx既是Action對應的處理邏輯方法。
如下:
為RegistAction增減一個regist方法,并且增加一個validateRegist()方法;
public class RegistAction extends ActionSupport { private String name; private String pass; private int age; //省略三個屬性的getter和setter方法 public void validate(){ System.out.println("進入validate 方法進行校驗"+name); if(!name.contains("ssy")){ addFieldError("user", "您的用戶名必須包括ssy!!!"); } } public String regist(){ return SUCCESS; } public void validateRegist(){ System.out.println("進入validateRegist方法進行校驗"+name); System.out.println("1111111111111"); if(!name.contains("tmt")){ addFieldError("user", "您的用戶名必須包含tmt"); } } }
上面的代碼中指定RegistAction的regist方法處理用戶請求。如果用戶再次向regist提交請求,該請求將交給RegistAction的regist處理邏輯處理,那么不僅validate()方法會進行輸入校驗,validateRegist()方法也會執行輸入校驗。
通過上面的頁面顯示:我們知道,如果該Action內除了validate方法外,還有該方法對應的validateXxx方法,則該方法會在validate方法之前被調用。
總結:
Struts 2的輸入校驗需要經過以下幾個步驟:
1、類型轉換器負責對字符串的請求參數執行類型轉換,并將這些值設置為Action的 屬性值。
2、在執行類型轉換過程中可能出現異常,如果出現異常,將異常信息保存到ActionContext中。conversionError攔截器負責將其封裝到FieldError里,然后執行第三步;如果轉換過程中沒有異常信息,則直接進入第三步。
3、使用Struts 2應用配置的校驗器進行輸入校驗
4、通過反射調用validateXxx()方法,其中Xxx是即將處理用戶請求的處理邏輯所對應的方法。
5、調用Action類里的validate方法。
6、如果經過上面5步都沒有出現FieldError,將調用Action里處理用戶請求的處理方法;如果出現了FieldError,系統將會轉入input邏輯視圖所指定的視圖資源。
流程如下: