struts2學習之---輸入校驗
客戶端校驗進行基本校驗,如檢驗非空欄位是否為空,數字格式是否正確等。客戶端校驗主要用來過濾使用者的誤操作。作用是:拒絕誤操作輸入提交到伺服器處理,降低伺服器端負擔。
伺服器端校驗也必不可少,伺服器端校驗防止非法資料進去程式,導致程式異常,底層資料庫異常。伺服器端校驗是保證程式有效進行及資料完整的手段。
對異常輸入的過濾,就是輸入校驗,也稱為資料校驗
輸入校驗分為客戶端校驗和伺服器校驗:
1. 客戶端校驗主要是過濾正常使用者的誤操作,主要通過js程式碼完成。
2. 伺服器端校驗是整個應用阻止非法資料的最後防線,主要通過在應用中程式設計實現。
1.編寫校驗檔案
struts2提供了基於驗證框架的輸入校驗,使用其進行校驗時無須對程式程式碼進行任何改變,只需編寫校驗規則檔案即可。
registForm.jsp
<s:form action ="regist">
<s:textfield name="name" label="使用者名稱"/>
<s:textfield name="pass" label="密碼"/>
<s:textfield name="age" label="年齡"/>
<s:textfield name="birth" label="生日" />
</s:form>
RegistAction.java
public class RegistAction extends ActionSupport{
private String name;
private String pass;
private int age;
private Date birth;
set,get方法
public String execute() throws Exception{
return SUCCESS;
}
}
RegistAction-validation.xml
<field-validator.../>是欄位校驗器的配置風格,而<validator.../>是非欄位校驗器的配置風格。
<validators>
<field name="name">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>必須輸入名字</message>
</field-validator>
<field-validator type="regex">
<param name="regex"><![CDATA[(\w{4,25})]]></param>
<message>您輸入的使用者名稱只能是字母和數字,且長度必須在4到25之間</message>
</field-validator>
</field>
<field name="pass">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>必須輸入密碼</message>
</field-validator>
<field-validator type="regex">
<param name="regex"><![CDATA[(\w{4,25})]]></param>
<message>您輸入的密碼只能是字母和數字,且長度必須在4到25之間</message>
</field-validator>
</field>
<field name="age">
<field-validator type="int">
<param name="min">1</param>
<param name="max">150</param>
<message>年級必須在1-150之間</message>
</field-validator>
</field>
<field name="birth">
<field-validator type="date">
<param name="min">1900-01-01</param>
<param name="max">2050-02-21</param>
<message>生日必須在${min}到${max}之間</message>
</field-validator>
</field>
</validators>
struts2中每個Action都有一個校驗檔案,因此該檔名應該遵循如下規則:
<Action名字>-validator.xml
該檔案被儲存在與Action class檔案相同的路徑下。與型別轉換失敗相似的是,當輸入校驗失敗後,sruts2也是自動返回名為”input”的Result,因此需要在struts.xml檔案中配置名為”input”的Result
<action name="regist" class="">
<result name="input">/WEB-INF/content/</result>
<result>/WEB-INF/content</result>
</action>
校驗失敗後可以在input邏輯檢視名的物理檢視中新增<s:fielderror/>
來輸出錯誤提示。
型別轉換失敗的提示資訊,輸入校驗失敗的提示資訊都被封裝成FieldError,並被放入Action Context中,而且校驗失敗時都將返回input邏輯檢視名,且都是用<s:fielderror/>
標籤來輸出錯誤提示資訊
2.國際化提示資訊
每個校驗檔案中每個<field-validator.../>
元素都包含一個必填的<message.../>
子元素,這個子元素中的內容就是校驗失敗後的提示資訊。為了國際化提示資訊,為message元素指定key屬性,該key屬性指定是國際化提示資訊對應的key。
RegistAction-validator.xml
<validators>
<field name="age">
<field-validator>
<param name="min">1</param>
<param name="max">150</param>
<message key="age.range"/>
</field-validator>
</field>
</validators>
RegistAction.properties
#違反年齡必須在指定範圍的提示資訊
age.range=您的年齡必須在${min}和${max}之間
3.使用客戶端校驗
在struts2中使用客戶端校驗,只需修改兩處:
- 將輸入頁面的表單元素改為使用struts2標籤來生成表單。
- 為該<s:form.../>
元素增加validate=”true”屬性,該表單就具有了客戶端校驗功能。
修改上面的表單元素:
<s:fielderror/>
<s:form action ="regist" validate="true">
<s:textfield name="name" label="使用者名稱"/>
<s:textfield name="pass" label="密碼"/>
<s:textfield name="age" label="年齡"/>
<s:textfield name="birth" label="生日"/>
</s:form>
該頁面的地址依然停留在原來的頁面,並未提交到對應的Action,這就表明:上面的資料校驗過程是客戶端完成的。
客戶端校驗值得注意的地方:
1. struts2的<s:form.../>
元素有一個theme屬性,不要將該屬性指定為simple。
2. 瀏覽者不能直接訪問啟用客戶端校驗的表單頁,這樣會引發異常。可以把啟用客戶端校驗的表單頁放到WEB-INF路徑下,讓瀏覽者訪問所有資源之前都先經過它的核心Filter。
3. 如何客戶端校驗希望輸出國際化提示資訊,那就需要使用全域性國際化資原始檔,不能使用Action範圍的國際化資原始檔。
4. 啟用客戶端校驗的表單頁面的action和namespace要分開寫,例如向namespace為/lee,name為registe的Action請求,應寫成<s:form action="regist" namespace="/lee">
而不應該寫成<s:form action="lee/regist">
一旦使用了MVC框架,就該嚴格遵守MVC思想,應該儘量避免讓瀏覽者直接訪問Web應用的檢視頁面,而應該讓瀏覽者向控制器傳送請求,有控制器呼叫頁面向瀏覽者呈現資料。
4.欄位校驗器配置風格
- 欄位優先,稱為欄位校驗器風格
- 校驗器優先,稱為非欄位校驗器風格
使用欄位校驗器配置風格時,每個欄位校驗規則遵循如下:
<field name="被校驗的欄位">
<field-validator type="校驗器名">
<!-- 此處需要為不同校驗器指定數量不等的校驗引數-->
<param name="引數名">引數值</param>
...
<!-- 校驗失敗後的提示資訊,其中key指定國際化的key-->
<message key="Il8Nkey">校驗失敗後的提示資訊</message>
</field-validator>
</field>
<field.../>
元素是校驗規則檔案的基本組成單位。
5.非欄位校驗器配置風格
<validators>
<validator type="校驗器名">
<param name="fieldName">需要被校驗的欄位</param>
<!-- 此處需要為不同校驗器指定數量不等的校驗引數-->
<param name="引數名">引數值</param>
...
<!-- 校驗失敗後的提示資訊,其中key指定國際化的key-->
<message key="Il8Nkey">校驗失敗後的提示資訊</message>
</validator>
</validators>
必須為
6.短路校驗器
校驗規則檔案的<validator.../>
元素和<field-validator../>
元素可以指定一個可選的short-circuit屬性,這個屬性指定校驗器是否是短路校驗器,該屬性的預設值為false,即預設是非短路校驗器。
短路校驗器的效果:瀏覽者完全沒有為某個輸入框輸入任何內容,系統應該僅輸入第一行提示資訊,而不是一次性輸出所有的校驗提示。
<validators>
<field name="name">
<field-validator type="requiredstring" short-circuit="true">
<param name="trim">true</param>
<message>必須輸入名字</message>
</field-validator>
<field-validator type="regex">
<param name="regex"><![CDATA[(\w{4,25})]]></param>
<message>您輸入的使用者名稱只能是字母和數字,且長度必須在4到25之間</message>
</field-validator>
</field>
</validators>
對於同一個欄位內的多個校驗器,如果一個短路校驗器校驗失敗,其他校驗器都根本不會繼續校驗。
7.校驗檔案的搜尋規則
struts2的一個Action中可能包含了多個處理邏輯,每個方法都是一個處理邏輯。不同的處理邏輯可能需要不同的校驗規則,struts2允許為不同控制邏輯指定不同校驗規則的檔案。
當需要讓一個Action可以處理多個請求時,應該在配置該Action是指定method屬性,就可以將一個Action處理類配置成多個邏輯。
struts.xml
<action name="*Pro" class="" method="{1}">
<result name="input">/WEB-INF/content/</result>
<result>/WEB-INF/content/</result>
</action>
為了能精確控制每個校驗邏輯,struts2允許通過為校驗規則檔名增加Action別名來指定具體需要校驗的處理邏輯。
<ActionClassName>-<ActionAliasName>-validation.xml
RegistAction-loginPro-validation.xml
假設系統有兩個Action:BaseAction和RegistAction,其中RegistAction繼承了BaseAction,則系統搜尋規則檔案順序如下:
1. BaseAction-validation.xml
2. BaseAction-別名-validation.xml
3. RegistAction-validation.xml
4. RegistAction-別名-validation.xml
即使找到一個校驗規則,系統還會繼續搜尋,不管有沒有這4份檔案,也不管是否找到配置檔案,系統總是按固定順序搜尋。
8.檢驗順序和短路
校驗器的執行順序有如下原則:
- 所有非欄位風格的校驗器優先於欄位風格的校驗器。
- 所有非欄位風格的校驗器中,排在前面的會執行。
- 所有欄位風格的校驗器中,排在前面的會先執行。
校驗器短路的原則如下:
1. 所有非欄位校驗器是最優先執行,如果某個非欄位校驗器校驗失敗了,則該欄位上所有欄位校驗器都不會獲得校驗的機會。
2. 非欄位校驗器的校驗失敗,不會阻止其他非欄位校驗的執行。
3. 如果一個欄位校驗器校驗失敗後,則該欄位下且排在該校驗失敗的校驗器之後的其他欄位校驗器不會獲得校驗的機會。
4. 欄位校驗器永遠都不會阻止非欄位校驗器的執行
9.內建校驗器
xwork-2.3.16.3.jar檔案中com\opensymphony\xwork2\validator\validators路徑下找到default.xml檔案中就是預設的校驗器註冊檔案。
1.必填校驗器(required)
該校驗器要求指定的欄位必須有值(非空)
引數為:
- fieldName:該引數指定校驗的Action屬性名。如果採用欄位校驗風格則不需自定該引數。
2.必填字串校驗器(requiredstring)
該校驗器要求欄位值必須非空且長度大於0,即該字串不能是”“。
引數為:
- fieldName: 該引數指定校驗的Action屬性名。
- trim:是否在檢驗前截斷被校驗屬性值前後的空白。該屬性是可選的
3.整數校驗器(int、long、short)
該校驗器要求欄位的整數值必須在指定範圍內。
引數為:
- fieldName:該引數指定校驗的Action屬性名。
- min:指定該屬性的最小值。
- max:指定該屬性的最大值。
4.日期校驗器(date)
該校驗器要求欄位的日期值必須在指定範圍內。
引數:
- fieldName:該引數指定校驗的Action屬性名。
- min:指定該屬性的最小值。
- max:指定該屬性的最大值。
5.表示式校驗器(expression)
它是一個非欄位校驗器,不可在欄位校驗器的配置風格中使用。該表示式校驗器要求OGNL表示式返回true,當返回true時,該校驗通過。
引數:
- expression:該引數指定一個邏輯表示式,該邏輯表示式基於ValueStack進行求值,最後返回一個Boolean值。
6.欄位表示式校驗器(fieldexpression)
要求指定欄位滿足一個邏輯表示式。
引數:
- fieldName:該引數指定校驗的Action屬性。
- expression:該引數指定一個邏輯表示式,該邏輯表示式基於ValueStack進行求值,最後返回一個Boolean值。
7.郵件地址校驗器(email)
要求被檢查欄位的字元如果非空,則必須是合法的郵件。不過這個校驗器其實就是基於正則表示式進行檢查的。
引數:
- fieldName:該引數指定校驗的Action屬性名。
8.網址校驗器(url)
要求被檢查欄位的字元如果非空,則必須是合法的URL地址。
引數:
- fieldName:該引數指定校驗的Action屬性名。
9.Visitor校驗器
主要用於檢測Action裡的複合屬性,例如一個Action裡包含了User型別的屬性。
public class RegistAction extends ActionSupport{
private User user;
set,get方法
}
public class User{
private String name;
private String pass;
set,get 方法
}
RegistAction-validation.xml
<validators>
<field name="user">
<field-validator type=""visitor>
<param name="context">userContext</param>
<!-- 指定校驗失敗後提示資訊是否新增下面字首-->
<param name="appendPrdfix">true</param>
<message>使用者的:</message>
</field-validator>
</field>
</validators>
User-userContext-validator.xml
<validators>
<field name="name">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message key="name.required"/>
</field-validator>
<field-validator type="regex">
<param name="regex"><![CDATA[(\w{4,25})]]></param>
<message>您輸入的使用者名稱只能是字母和數字,且長度必須在4到25之間</message>
</field-validator>
</field>
</validators>
JSP頁面
<s:form action="regist">
<s:textfield name="user.name" label="使用者名稱"/>
</s:form>
user.name 這個屬性表示直接繫結到Action例項的user屬性的name屬性
10.轉換校驗器(conversion)
檢查被校驗欄位在型別轉換過程中是否出現錯誤。
引數:
- fieldName:該引數指定校驗的Action屬性。
- repopulateField:該引數指定當型別轉換失敗後,返回input頁面是,型別轉換失敗的表單域是否保留原來的錯誤輸入。
11.字串長度校驗器(stringlength)
要求被校驗欄位的長度必須在指定的範圍之內,否則就算校驗失敗。
引數:
- fieldName:該引數指定校驗的Action屬性名。
- maxLength:該引數指定欄位值的最大值。
- minLength:該引數指定欄位值得最小值。
- trim:指定校驗該欄位之前是否截斷該欄位前後的空白。
12.正則表示式(regex)
檢查被校驗欄位是否匹配一個正則表示式。
引數:
- fieldName:該引數指定校驗的Action屬性名。
- regex:指定匹配用的正則表示式。
- caseSensitive:該引數指明進行正則表示式匹配時,是否區分大小寫。
10.基於註解的輸入校驗
是由XWork框架提供的。
使用驗證器註解修飾Action裡各成員變數對應的setter方法即可。
public class RegistAction extends ActionSupport{
private String name;
@RequiredStringValidator(key="name.required",message="")
@RegexFieldValidator(regex="\\w{4,25}",key="name.regex",message="")
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
}
11.手動完成輸入校驗
1. 重寫validate()方法
public class RegistAction extends ActionSupport{
private String name;
private String pass;
private int age;
privare Date birth;
set,get方法
public void validate(){
System.out.println("進入validate方法進行校驗" + name);
if(!name.contains("crazyit")){
addFieldError("user","您的使用者名稱必須包含crazyit!");
}
}
}
ActionSupport類裡包含了一個getText()方法,該方法可用於取得國際化資訊。
- 重寫validateXxx()方法
為了實現校驗指定處理邏輯的功能,struts2的Action允許提供一個validateXxx()方法,其中xxx即是Action對應的處理邏輯方法。
public class RegistAction extends ActionSupport{
private String name;
private String pass;
private int age;
privare Date birth;
set,get方法
public void validateRegist(){
System.out.println("進入validate方法進行校驗" + name);
if(!name.contains("crazyit")){
addFieldError("user","您的使用者名稱必須包含crazyit!");
}
}
}
struts.xml
<action name="regist" class="" method="regist">
</action>
瀏覽者向regist提交請求,該請求將由RegistAction的regist()處理邏輯處理,那麼不僅validate()方法會進行輸入校驗,validateRegist()方法也會執行輸入校驗,而validateRegist()方法先呼叫。
struts2輸入校驗需要經過如下幾個步驟
- 型別轉換器負責對字串的請求引數執行型別轉換,並將這些值設定成Action的屬性值。
- 在執行型別轉換過程中可能出現異常,如果出現異常,將異常資訊儲存到ActionContext中,conversionError攔截器負責將其封裝發哦FieldError裡,然後執行下一步,如果沒有異常,直接進行下一步。
- 使用strurs2應用中所配置的校驗器進行輸入校驗。
- 通過反射呼叫validateXxx()方法。
- 呼叫Action類裡的validate()方法。
- 如果經過上面都沒有出現FieldError,將呼叫Action裡處理使用者請求的處理方法;如果出現了,系統將轉入input邏輯檢視所指定的檢視資源。