深入理解Struts2----數(shù)據(jù)校驗(yàn)

?????在表現(xiàn)層的數(shù)據(jù)處理方面主要分為兩種類型,一種是類型轉(zhuǎn)換,這點(diǎn)我們上篇已經(jīng)簡(jiǎn)單介紹過(guò),另外一種則是我們本篇文章將要介紹的:數(shù)據(jù)校驗(yàn)。對(duì)于我們的web應(yīng)用,我們經(jīng)常需要和用戶進(jìn)行交互收集用戶信息,那么無(wú)論是用戶誤操作還是惡意攻擊,這些錯(cuò)誤的信息一旦被傳入到后臺(tái),小則導(dǎo)致程序異常關(guān)閉,大則導(dǎo)致整個(gè)系統(tǒng)癱瘓。數(shù)據(jù)校驗(yàn)就是對(duì)用戶的輸入做一層過(guò)濾,保護(hù)我們的系統(tǒng)免受侵入。下面我們開(kāi)始介紹本篇的內(nèi)容,主要包括以下幾小節(jié):

  • 一個(gè)簡(jiǎn)單的例子(用于全局把握整個(gè)校驗(yàn)過(guò)程)
  • 兩種校驗(yàn)配置風(fēng)格
  • 為不同Action處理邏輯配置不同的校驗(yàn)配置
  • 詳解struts2框架內(nèi)置的幾種校驗(yàn)器
  • 自定義校驗(yàn)器

一、一個(gè)簡(jiǎn)單的例子
?????在詳細(xì)介紹數(shù)據(jù)校驗(yàn)的每一步驟之前,我們先通過(guò)一個(gè)簡(jiǎn)單的例子從全局范圍把握下整個(gè)數(shù)據(jù)校驗(yàn)流程都需要哪些文件,各個(gè)步驟執(zhí)行的順序。強(qiáng)調(diào)的是從全局粗略的感受下,不用在意具體的代碼。

//登錄表單頁(yè)面,信息提交到loginAction
<html>
  <head>
    <title></title>
  </head>
  <body>
    <s:form method="POST" action="/login">
      <s:textfield name="name" label="姓名"/>
      <s:textfield name="age" label="年齡"/>
      <s:submit value="提交"/>
    </s:form>
    
  </body>
</html>
//定義一個(gè)action
public class LoginAction extends ActionSupport {

    private String name;
    private int age;
    public void setName(String n){
        this.name= n;
    }
    public String getName(){
        return this.name;
    }
    public void setAge(int a){
        this.age = a;
    }
    public int getAge(){
        return this.age;
    }

    public String execute(){
        return SUCCESS;
    }
}
//創(chuàng)建校驗(yàn)文件并鍵入以下內(nèi)容
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator 1.0.2//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">

<validators>
    <field name="name">
        <field-validator type="requiredstring">
            <param name="trim">true</param>
            <message>姓名不能為空</message>
        </field-validator>
    </field>
    <field name="age">
        <field-validator type="requiredstring">
            <param name="trim">true</param>
            <message>年齡不能為空</message>
        </field-validator>
    </field>
</validators>

我們首先從login這個(gè)表單頁(yè)面提交表單信息到loginAction中的屬性,然后框架會(huì)查找是否有校驗(yàn)規(guī)則文件,如果有則執(zhí)行它。在校驗(yàn)的過(guò)程中,如果校驗(yàn)失敗會(huì)跳轉(zhuǎn)到處理結(jié)果為 input 視圖頁(yè)面,這里和上篇介紹的類型轉(zhuǎn)換是一樣的,我們也一般是需要為其指定一個(gè)input視圖頁(yè)面的。在我們上述的校驗(yàn)文件中,我們規(guī)定兩個(gè)屬性的值不能為空,如果為空則該數(shù)據(jù)不符合要求,框架會(huì)封裝錯(cuò)誤信息并跳轉(zhuǎn)到input視圖頁(yè)面。下面我們看看上述代碼的運(yùn)行截圖:

這里寫圖片描述

這里寫圖片描述

至此我們簡(jiǎn)單了解了數(shù)據(jù)校驗(yàn)整個(gè)過(guò)程大致需要的文件及其作用,當(dāng)然該例中還有很多細(xì)節(jié)之處沒(méi)有展現(xiàn)出來(lái),因?yàn)槟康闹皇菑恼w上直觀感受下,詳細(xì)的內(nèi)容將在下面的小節(jié)中展現(xiàn)。

二、兩種校驗(yàn)配置風(fēng)格
?????下面我們從校驗(yàn)文件開(kāi)始看起。首先一點(diǎn),校驗(yàn)文件的命名是有要求的并且一般一個(gè)校驗(yàn)文件只服務(wù)一個(gè)Action,所以該文件的命名規(guī)則如下:

<ActionName>-validation.xml

所以上述我們?yōu)長(zhǎng)oginAction創(chuàng)建的校驗(yàn)文件名為:LoginAction-validation.xml。該文件有個(gè)根元素 validators ,我們的屬性校驗(yàn)元素是其子元素。下面我們介紹第一種配置校驗(yàn)文件的方式,上述的例子就是這種方式,該種方式使用field 作為一級(jí)子元素,該元素將對(duì)應(yīng)于Action實(shí)例中實(shí)際的屬性,它有一個(gè)name屬性,該屬性就是用于指定此field元素配置的是Action的哪個(gè)實(shí)例屬性,有幾個(gè)實(shí)例屬性就應(yīng)該有幾個(gè)field元素。

我們由field元素可以定位到Action實(shí)例中具體的某個(gè)屬性,使用field-validator元素為給屬性指定校驗(yàn)器(Struts默認(rèn)提供的檢驗(yàn)器,具體有關(guān)內(nèi)置的校驗(yàn)器后文詳細(xì)介紹),param 元素用于指定校驗(yàn)的參數(shù),message元素用于指定不符合校驗(yàn)規(guī)則時(shí)輸出的信息。我們可以根據(jù)不同的處理需要為Action實(shí)例屬性指定不同的校驗(yàn)器,當(dāng)然我們也是可以自定義校驗(yàn)器來(lái)校驗(yàn)屬性的數(shù)值的。

上面介紹的是用field元素來(lái)配置的數(shù)據(jù)校驗(yàn)規(guī)則。下面我們介紹第二種配置風(fēng)格,使用validator取代field作為一級(jí)子元素,用fieldName屬性指定對(duì)應(yīng)的Action實(shí)例屬性,對(duì)于上面的配置,我們也可以改寫為:

<validators>
    <validator type="requiredstring">
        <param name="fieldName">name</param>
        <param name="trim">true</param>
        <message>姓名不能為空</message>
    </validator>
    <validator type="requiredstring">
        <param name="fieldName">age</param>
        <param name="trim">true</param>
        <message>年齡不能為空</message>
    </validator>
</validators>

我們看到該方式的配置每個(gè)屬性用一個(gè)validator元素表示,通過(guò)param元素的fieldName屬性對(duì)應(yīng)實(shí)際的Action實(shí)例屬性,其余內(nèi)容和第一種方式類似。他們之間的區(qū)別相信大家對(duì)比之后也能明白,只是書寫方式不同,都能達(dá)到效果,大家可以根據(jù)自己喜好選擇使用哪種方式,由于個(gè)人喜好,下文都會(huì)采用第一種方式進(jìn)行介紹。

三、為不同Action處理邏輯配置不同的校驗(yàn)配置
?????我們的某個(gè)具體的Action類在很多情況下是可以用于多個(gè)不同的處理邏輯的,例如某個(gè)action既可以處理用戶注冊(cè)請(qǐng)求也可以處理用戶登錄請(qǐng)求,但是對(duì)于這兩種截然不同的請(qǐng)求,我們的數(shù)據(jù)校驗(yàn)卻不盡相同,下面看個(gè)例子:

public class LoginAction extends ActionSupport {

    private String name;
    private String pass1;
    private String pass2;
    public void setName(String n){
        this.name= n;
    }
    public String getName(){
        return this.name;
    }
    public void setPass1(String p1){
        this.pass1 = p1;
    }
    public String getPass1(){
        return this.pass1;
    }
    public void setPass2(String p2){
        this.pass2 = p2;
    }
    public String getPass2(){
        return this.pass2;
    }

    public String execute(){
        return SUCCESS;
    }
}
//Struts.xml中指定該類用于響應(yīng)兩個(gè)請(qǐng)求
<struts>
    <package name="my" extends="struts-default" namespace="/">
        <action name="login" class="MyPackage.LoginAction">
            <result name="success">/index.jsp</result>
            <result name="input">/input.jsp</result>
        </action>
        <action name="regist" class="MyPackage.LoginAction">
            <result name="success">/index.jsp</result>
            <result name="input">/input.jsp</result>
        </action>
    </package>
</struts>

此時(shí)我們需要?jiǎng)?chuàng)建兩個(gè)數(shù)據(jù)校驗(yàn)文件,一個(gè)用于校驗(yàn)請(qǐng)求login,一個(gè)用于校驗(yàn)請(qǐng)求regist。當(dāng)然為了框架能夠快速搜索到,這里兩個(gè)文件的命名也是有要求的,規(guī)則如下:

<ActionName>-<ActionAliasName>-validation.xml

對(duì)應(yīng)于上述的兩個(gè)文件名為:LoginAction-login-validation.xml和LoginAction-regist-validation.xml。下面給出此例中上述兩個(gè)文件的內(nèi)容:

//LoginAction-login-validation.xml局部?jī)?nèi)容
<validators>
    <field name="name">
        <field-validator type="requiredstring">
            <param name="trim">true</param>
            <message>姓名不能為空</message>
        </field-validator>
    </field>
    <field name="pass1">
        <field-validator type="requiredstring">
            <param name="trim">true</param>
            <message>密碼不能為空</message>
        </field-validator>
    </field>
</validators>
//LoginAction-regist-validation.xml局部?jī)?nèi)容
//該校驗(yàn)文件為pass1屬性添加了一個(gè)fieldexpression校驗(yàn)器,用于校驗(yàn)是否和pass2相等
<validators>
    <field name="name">
        <field-validator type="requiredstring">
            <param name="trim">true</param>
            <message>姓名不能為空</message>
        </field-validator>
    </field>
    <field name="pass1">
        <field-validator type="requiredstring">
            <param name="trim">true</param>
            <message>密碼不能為空</message>
        </field-validator>
        <field-validator type="fieldexpression">
            <param name="expression"><![CDATA[(pass1==pass2)]]></param>
            <message>兩次密碼不同</message>
        </field-validator>
    </field>
    <field name="pass2">
        <field-validator type="requiredstring">
            <param name="trim">true</param>
            <message>密碼不能為空</message>
        </field-validator>
    </field>
</validators>

上述的兩個(gè)文件依然是需要存放在和Action相同目錄下,框架會(huì)根據(jù)不同的請(qǐng)求而去檢索相應(yīng)的校驗(yàn)文件,下面我們看表單頁(yè)面:

//注冊(cè)頁(yè)面
  <body>
    <s:form method="POST" action="/regist">
      <s:textfield name="name" label="姓名"/>
      <s:textfield name="pass1" label="密碼"/>
      <s:textfield name="pass2" label="密碼"/>
      <s:submit value="提交"/>
    </s:form>
  </body>
這里寫圖片描述

這里寫圖片描述

而對(duì)于login登錄邏輯來(lái)說(shuō),

  <body>
    <s:form method="POST" action="/login">
      <s:textfield name="name" label="姓名"/>
      <s:textfield name="pass1" label="密碼"/>
      <s:submit value="提交"/>
    </s:form>
  </body>
這里寫圖片描述

這里寫圖片描述

只需要用戶名和密碼不為空即可,并沒(méi)有別的校驗(yàn)邏輯,可能上述的例子并不是十分恰當(dāng),但是卻很清晰的展示了這種校驗(yàn)分離的處理過(guò)程。對(duì)于校驗(yàn)文件中的內(nèi)容,我們將在下文詳細(xì)介紹,此處不必糾結(jié)。最后需要強(qiáng)調(diào)一點(diǎn)的是,當(dāng)我們?yōu)槊總€(gè)不同的處理邏輯配置相對(duì)應(yīng)的校驗(yàn)文件時(shí),原來(lái)的那個(gè)LoginAction-validation.xml文件則會(huì)被作為默認(rèn)的校驗(yàn)文件,當(dāng)LoginAction-login-validation.xml或者LoginAction-regist-validation.xml執(zhí)行之后,會(huì)自動(dòng)繼續(xù)執(zhí)行該校驗(yàn)文件,也就會(huì)導(dǎo)致校驗(yàn)了兩遍,所以一般會(huì)在該文件中添加該Action的通用校驗(yàn)代碼。

四、詳解struts2框架內(nèi)置校驗(yàn)器
?????有關(guān)框架的內(nèi)置校驗(yàn)器,我們?cè)谏衔闹幸恢倍际褂茫菦](méi)有詳細(xì)的介紹,本小節(jié)就專門介紹這些內(nèi)置校驗(yàn)器的使用,下一小節(jié)將介紹如何自定義一個(gè)校驗(yàn)器。首先解壓xwork-core-2.3.32.jar,從com\opensymphony\xwork2\validator\validators中找到default.xml并打開(kāi):

這里寫圖片描述

這是框架內(nèi)建立的所有校驗(yàn)器,我們會(huì)介紹其中的部分, 剩余的一些校驗(yàn)器由于某些局限性不經(jīng)常使用,所以此處就不在介紹。

下面看第一種校驗(yàn)器,必填校驗(yàn)器。該校驗(yàn)器要求指定字段的值非空(null)。該校驗(yàn)器的使用比較簡(jiǎn)單,此處不再演示。

第二種校驗(yàn)器,必填字符串校驗(yàn)器。該校驗(yàn)器要求字段的值非空并且長(zhǎng)度要大于0。即字段不能是""。該校驗(yàn)器要求比第一種必填校驗(yàn)器嚴(yán)格一點(diǎn)。它還具有一個(gè)參數(shù):trim。該參數(shù)用于剔除字段中前后的空白,默認(rèn)值為true。這一點(diǎn)也是比較容易理解的,此處不再贅述。

第三種校驗(yàn)器,整數(shù)校驗(yàn)器。對(duì)于Action中字段類型為int,long,short的情況,我們可以使用該校驗(yàn)器來(lái)要求該字段的值必須存在于指定的范圍內(nèi)。它有兩個(gè)參數(shù),min,max,一個(gè)是指定該字段的值可能出現(xiàn)的最小值,一個(gè)則是指定該字段的值可能出現(xiàn)的最大值。下面看個(gè)例子:

//LoginAction中添加age屬性的代碼并未貼出
//此處指定了該age屬性必須在0-100之間
<validators>
    <field name="age">
        <field-validator type="int">
            <param name="min">0</param>
            <param name="max">100</param>
            <message>輸入的年齡必須在指定0-100之間</message>
        </field-validator>
    </field>
</validators>
這里寫圖片描述

這里寫圖片描述

第四種校驗(yàn)器,日期校驗(yàn)器。該校驗(yàn)器用于規(guī)定日期類型的屬性值可能出現(xiàn)的范圍。有兩個(gè)參數(shù),min和max。兩者分別指定日期最小值和最大值。下面看一個(gè)例子:

//LoginAction中添加屬性date
<validators>
    <field name="date">
        <field-validator type="date">
            <param name="min">1990-01-01</param>
            <param name="max">2017-5-19</param>
            <message>日期范圍為:1990-01-01到2017-5-19</message>
        </field-validator>
    </field>
</validators>
這里寫圖片描述

這里寫圖片描述

第五種校驗(yàn)器,字段表達(dá)式校驗(yàn)器,fieldexpression。它要求該字段滿足一個(gè)基于ognl的表達(dá)式。該校驗(yàn)器具有一個(gè)參數(shù),expression,該參數(shù)指定了一個(gè)表達(dá)式。下面我們看一個(gè)具體的例子:

//表達(dá)式要寫在 <![CDATA[....]]> 內(nèi)
<validators>
    <field name="pass1">
        <field-validator type="fieldexpression">
            <param name="expression"><![CDATA[(pass1 == pass2)]]></param>
            <message>無(wú)法匹配表達(dá)式</message>
        </field-validator>
    </field>
</validators>
這里寫圖片描述

這里寫圖片描述

需要注意一點(diǎn)的是我們可以使用ognl表達(dá)式從ValueStack中取數(shù)據(jù)進(jìn)行比較,但是ognl表達(dá)式本身必須被寫在<![CDATA[....]]>中。至于為什么,作者還沒(méi)參透。

第六種校驗(yàn)器,字符串長(zhǎng)度校驗(yàn)器。該校驗(yàn)器比較簡(jiǎn)單,和之前介紹的幾種很是類似,主要有幾個(gè)參數(shù),maxLength,minLength,trim。相信大家也都知道他們什么意思,此處不再贅述。

第七種校驗(yàn)器,正則表達(dá)式校驗(yàn)器。該校驗(yàn)器有兩個(gè)參數(shù),regex代表正則表達(dá)式內(nèi)容,caseSensitive指定校驗(yàn)時(shí)是否考慮大小寫。具體使用情況比較容易,此處不再贅述。下面我們看自定義校驗(yàn)器。

五、自定義校驗(yàn)器
?????相比于使用Struts2內(nèi)置校驗(yàn)器,自定義一個(gè)校驗(yàn)器反而簡(jiǎn)單些。我們只需要重寫ActionSupport類中的一個(gè)方法即可:

  public void validate() {}

下面我們看一個(gè)例子:

//在LoginAction中添加如下一個(gè)方法
    public void validate(){
        if(name.isEmpty()){
            addFieldError("name","用戶名不能為空");
        }
        if (!pass1.equals(pass2)){
            addFieldError("pass1","兩次輸入的密碼必須相同");
        }
    }

該方法用于判斷字段name是否為空,如果為空打包錯(cuò)誤信息添加到FieldError中,判斷兩次輸入的密碼是否一致,如果不一致打包錯(cuò)誤信息添加到FieldError中。在方法結(jié)束時(shí),框架會(huì)去查看FieldError是否為空,如果不為空說(shuō)明校驗(yàn)出錯(cuò),跳轉(zhuǎn)視圖input頁(yè)面。下面我們看上述代碼的運(yùn)行截圖:

這里寫圖片描述

這里寫圖片描述

從運(yùn)行的結(jié)果看,自定義校驗(yàn)器和使用框架內(nèi)置校驗(yàn)器都能完成數(shù)據(jù)校驗(yàn)的工作,但是個(gè)人認(rèn)為自定義校驗(yàn)方式反而顯得過(guò)程簡(jiǎn)單。對(duì)于之前介紹的一個(gè)Action類響應(yīng)多個(gè)請(qǐng)求時(shí)候?qū)?shù)據(jù)校驗(yàn)的不同形態(tài),在我們自定義校驗(yàn)器中也是可以實(shí)現(xiàn)的,只是定義的方法名有所區(qū)別,例如:

響應(yīng)login處理邏輯的自定義校驗(yàn)方法命名為:validateLogin()
響應(yīng)regist處理邏輯的自定義校驗(yàn)方法命名為:validateRegist()

至此,我們簡(jiǎn)單介紹完了有關(guān)Struts2框架的數(shù)據(jù)校驗(yàn)部分的內(nèi)容,總結(jié)的粗糙,望大家多多評(píng)論指點(diǎn)!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,596評(píng)論 19 139
  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說(shuō)閱讀 12,441評(píng)論 6 13
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 34,734評(píng)論 18 399
  • 11月22日新聞簡(jiǎn)報(bào) 星期三 美麗的魚為您推送工作愉快 生活喜樂(lè)! 1、MH370失聯(lián)案庭前會(huì)議確認(rèn)5被告,家屬最...
    睡遍全世界閱讀 138評(píng)論 0 0
  • 福特公司意識(shí)到需要發(fā)展AI和機(jī)器人團(tuán)隊(duì) 一個(gè)新的研發(fā)團(tuán)隊(duì)將會(huì)幫助福特趕上其自動(dòng)駕駛的競(jìng)爭(zhēng)對(duì)手 原文鏈接:https...
    肥寒925閱讀 174評(píng)論 0 1

友情鏈接更多精彩內(nèi)容