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

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

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

    Java Study Center  
    日歷
    <2008年9月>
    31123456
    78910111213
    14151617181920
    21222324252627
    2829301234
    567891011
    統(tǒng)計(jì)
    • 隨筆 - 40
    • 文章 - 3
    • 評論 - 0
    • 引用 - 0

    導(dǎo)航

    常用鏈接

    留言簿(1)

    隨筆檔案(40)

    文章檔案(3)

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

     

    在寫前幾篇文章的時(shí)候,有些朋友建議我的寫一篇關(guān)于表單數(shù)據(jù)校驗(yàn)的文章。 正如文章的開頭所引用的《Writing Secure Code》的名言:“所有的輸入都是罪惡的”,所以我們應(yīng)該對所有的外部輸入進(jìn)行校驗(yàn)。而表單是應(yīng)用程序最簡單的入口,對其傳進(jìn)來的數(shù)據(jù),我們必須進(jìn)行校驗(yàn)。

    轉(zhuǎn)換與校驗(yàn)(Conversion & Validation)

    其實(shí)上篇文章,我本來是打算寫表單數(shù)據(jù)校驗(yàn)的內(nèi)容,但是經(jīng)過再三思考后,還是決定先寫Struts 2.0轉(zhuǎn)換器的內(nèi)容。原因是我認(rèn)為轉(zhuǎn)換是校驗(yàn)的基礎(chǔ),只有在數(shù)據(jù)被正確地轉(zhuǎn)換成其對應(yīng)的類型后,我們才可以對其取值范圍進(jìn)行校驗(yàn)。看個(gè)例子相信大家可以更清楚。現(xiàn)在我們就來改造一下《轉(zhuǎn)換器(Converter)——Struts 2.0中的魔術(shù)師》的第一個(gè)例子。

    首先,從Action開始,修改后的代碼如下:

    package tutorial;

    import java.util.Locale;

    import com.opensymphony.xwork2.ActionSupport;
    import com.opensymphony.xwork2.util.LocalizedTextUtil;

    public class HelloWorld extends ActionSupport {
       
    private String msg;
       
    private Locale loc = Locale.US;
       
       
    public String getMsg() {
           
    return msg;        
       }

       
       
    public Locale getLoc() {
           
    return loc;
       }

       
       
    public void setLoc(Locale loc) {
           
    this .loc = loc;
       }

       
       @Override
       
    public void validate() {
           System.out.println(
    " Calling validate() " );
           
    if ( ! (loc.equals(Locale.US) || loc.equals(Locale.CHINA))) {
                       addFieldError(
    " loc " , getText( " validation.loc " ));
           }

       }

           
       
    public void validateExecute() {
           System.out.println(
    " Calling validateExecute() by reflection " );
       }

       
       @Override
       
    public String execute() {
           System.out.println(
    " Calling execute() " );
           
    // LocalizedTextUtil是Struts 2.0中國際化的工具類,<s:text>標(biāo)志就是通過調(diào)用它實(shí)現(xiàn)國際化的
               msg = LocalizedTextUtil.findDefaultText( " HelloWorld " , loc);
           
    return SUCCESS;
       }

    }

    然后,修改Struts.xml中Action的定義指明輸入地址:

    < action name ="HelloWorld" class ="tutorial.HelloWorld" >
       
    < result > /HelloWorld.jsp </ result >
       
    < result name ="input" > /HelloWorld.jsp </ result >
    </ action >

    接著,在HelloWorld.jsp中加入錯(cuò)誤提示:

    <% @ page  contentType = " text/html; charset=UTF-8 " %>
    <% @taglib prefix = " s " uri = " /struts-tags " %>
    < html >
    < head >
       
    < title > Hello World </ title >
    </ head >
    < body >
       
    < div style ="color:red;" >
           
    < s:fielderror />
       
    </ div >
       
    < s:form action ="HelloWorld" theme ="simple" >            
            Locale:
    < s:textfield name ="loc" /> &nbsp; < s:submit />
       
    </ s:form >    
       
    < h2 >< s:property value ="msg" /></ h2 >
    </ body >
    </ html >

    再修改LocaleConverter.java文件,將內(nèi)容改為:

    package tutorial;

    import java.util.Locale;
    import java.util.Map;
    import java.util.regex.Pattern;

    public class LocaleConverter extends ognl.DefaultTypeConverter {
       @Override
       
    public Object convertValue(Map context, Object value, Class toType) {
           
    if (toType == Locale. class ) {            
               System.out.println(
    " Converting String to Locale " );
               String locale
    = ((String[]) value)[ 0 ];
               
    return new Locale(locale.substring( 0 , 2 ), locale.substring( 3 ));
           }
    else if (toType == String. class ) {
               System.out.println(
    " Converting Locale to String " );
               Locale locale
    = (Locale) value;
               
    return locale.toString();
           }

           
    return null ;
       }

    }

    之后,修改國際化資源文件,內(nèi)容為:

    HelloWorld = 你好,世界!
    invalid.fieldvalue.loc
    = Locale必須為\ " xx_XX\ " 的格式
    validation.loc
    = 區(qū)域必須為中國或美國
    globalMessages_zh_CN.properties

    HelloWorld = Hello World!
    invalid.fieldvalue.loc
    = Locale must like \ " xx_XX\ "
    validation.loc
    = Locale must be China or USA
    globalMessages_en_US.properties

    發(fā)布運(yùn)行應(yīng)用程序,在瀏覽器中鍵入http://localhost:8080/Struts2_Validation/HelloWorld.action,在Locale中輸入zh_CN,按“Submit”提交,效果如上篇文章所示。而在服務(wù)器控制臺有如下輸出:

    Converting String to Locale...
    Calling validateExecute() by reflection...
    Calling validate()...
    Calling execute()...
    Converting Locale to String...

    上述的輸出說明了Struts 2.0的數(shù)據(jù)校驗(yàn)工作方式,它需要經(jīng)過下面幾個(gè)步驟:

    1. 通過轉(zhuǎn)換器將請求參數(shù)轉(zhuǎn)換成相應(yīng)的Bean屬性;
    2. 判斷轉(zhuǎn)換過程是否出現(xiàn)異常。如果有,則將其保存到ActionContext中,conversionError攔截器再封裝為fieldError;如果沒有,進(jìn)行下一步;
    3. 通過反射(Reflection)來調(diào)用validateXxx()方法(其中,Xxx表示Action的方法名);
    4. 調(diào)用validate()方法;
    5. 如果經(jīng)過上述步驟沒有出現(xiàn)fieldError,則調(diào)用Action方法;如果有,則會(huì)跳過Action方法,通過國際化將fieldError輸出到頁面。

    不喜歡看文字的朋友,可以參考下面的圖1。

    圖1 校驗(yàn)順序圖
    圖1 校驗(yàn)順序圖

    看到這里可能大家會(huì)疑問:“這么多地方可以校驗(yàn)表單數(shù)據(jù),到底我應(yīng)該在那里做呢?”有選擇是好事,但抉擇的過程往往是痛苦的,往往讓人不知所措。如果大家參照以下幾點(diǎn)建議,相信會(huì)比較容易地做出正確的抉擇。

    1. 如果需要轉(zhuǎn)換的數(shù)據(jù),通常做法在轉(zhuǎn)換的時(shí)候做格式的校驗(yàn),在Action中的校驗(yàn)方法中校驗(yàn)取值。假如用戶填錯(cuò)了格式,我們可以通過在資源文件配置invalid.fieldvalue.xxx(xxx為屬性名)來提示用戶正確的格式,不同的階段出錯(cuò)顯示不同的信息。具體做法請參考上面的例子;
    2. 至于用validate()還是validateXxx(),我推薦使用validate()。原因是validateXxx()使用了反射,相對來說性能稍差,而validate()則是通過接口com.opensymphony.xwork2.Validateable調(diào)用。當(dāng)然如果你的表單數(shù)據(jù)取值是取決于特定Action方法,則應(yīng)該使用validateXxx()。

    在運(yùn)行上面的例子時(shí),在Locale中輸入zh并提交時(shí)出現(xiàn)圖2所示頁面。

    圖2 錯(cuò)誤格式
    圖2 錯(cuò)誤格式

    在Locale中輸入de_DE時(shí),出現(xiàn)如圖3所示頁面。

    圖3 取值錯(cuò)誤
    圖3 取值錯(cuò)誤

    使用Struts 2.0的校驗(yàn)框架

    上一節(jié)的內(nèi)容都是關(guān)于如何編程實(shí)現(xiàn)校驗(yàn),這部分工作大都是單調(diào)的重復(fù)。更多情況下,我們使用Struts 2.0的校驗(yàn)框架,通過配置實(shí)現(xiàn)一些常見的校驗(yàn)。

    我學(xué)習(xí)編程有個(gè)習(xí)慣——喜歡先看輸出結(jié)果,再看代碼實(shí)現(xiàn)。這樣學(xué)的好處是先看結(jié)果可以刺激學(xué)習(xí)的激情,也可以在看代碼前自已思考一下如何實(shí)現(xiàn),然后帶著問題去看代碼,那就清晰多了。因此下面我們先來做演示。

    首先,在tutorial包下新建ValidationAction.java,代碼如下:

    package tutorial;

    import com.opensymphony.xwork2.ActionSupport;

    public class ValidationAction extends ActionSupport {
       
    private String reqiuredString;

       
    public String getReqiuredString() {
           
    return reqiuredString;
       }


       
    public void setReqiuredString(String reqiuredString) {
           
    this .reqiuredString = reqiuredString;
       }

       
       @Override
       
    public String execute() {
           
    return SUCCESS;
       }
       
    }

    然后,配置上述所建的Ation,代碼片段如下:

    < action name ="ValidationAction" class ="tutorial.ValidationAction" >
       
    < result > /Output.jsp </ result >
       
    < result name ="input" > /Input.jsp </ result >
    </ action >

    接著,創(chuàng)建Input.jsp和Output.jsp,內(nèi)容分別如下:

    <% @ page  contentType = " text/html; charset=UTF-8 " %>
    <% @taglib prefix = " s " uri = " /struts-tags " %>
    < html >
    < head >
       
    < title > Hello World </ title >
       
    <!-- 此標(biāo)志的作用是引入Struts 2.0的常用的Javascript和CSS -->
       
    < s:head />
    </ head >
    < body >
       
    < s:form action ="ValidationAction" >            
           
    < s:textfield name ="reqiuredString" label ="Required String" />
           
    < s:submit />
       
    </ s:form >    
    </ body >
    </ html >
    Input.jsp

    <% @ page  contentType = " text/html; charset=UTF-8 " %>
    <% @taglib prefix = " s " uri = " /struts-tags " %>
    < html >
    < head >
       
    < title > Hello World </ title >
    </ head >
    < body >
        Required String:
    < s:property value ="reqiuredString" />    
    </ body >
    </ html >
    Output.jsp

    再接下來,在tutorial包下創(chuàng)建ValidationAction的校驗(yàn)配置文件Xxx-validation.xml(Xxx為Action的類名),在本例中該文件名ValidationAction-validation.xml,內(nèi)容如下:

    <? xml version="1.0" encoding="UTF-8" ?>
    <! DOCTYPE validators PUBLIC 
              "-//OpenSymphony Group//XWork Validator 1.0//EN" 
              "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"
    >          
    < validators >
       
    < field name ="reqiuredString" >
           
    < field-validator type ="requiredstring" >
               
    < message > This string is required </ message >
           
    </ field-validator >
       
    </ field >
    </ validators >

    發(fā)布運(yùn)行應(yīng)用程序,在地址欄中鍵入http://localhost:8080/Struts2_Validation/Input.jsp,出現(xiàn)如圖4所示頁面。

    圖4 Input.jsp
    圖4 Input.jsp

    直接點(diǎn)擊“Submit”提交表單,出現(xiàn)圖5所示的頁面。

    圖5 錯(cuò)誤提示
    圖5 錯(cuò)誤提示

    在Required String中隨便填點(diǎn)東西,轉(zhuǎn)到Output.jsp頁面,如圖6所示。

    圖6 Output.jsp
    圖6 Output.jsp

    通過上面的例子,大家可以看到使用該校驗(yàn)框架十分簡單方便。不過,上例還有兩點(diǎn)不足:

    1. 還沒有國際化錯(cuò)誤消息;
    2. 沒有實(shí)現(xiàn)客戶端的校驗(yàn)。

    當(dāng)然,要完善以上不足,對于Struts 2.0來說,只是小菜一碟。

    1. 在Xxx-validation.xml文件中的<message>元素中加入key屬性;
    2. 在Input.jsp中的<s:form>標(biāo)志中加入validate="true"屬性,就可以在用Javascript在客戶端校驗(yàn)數(shù)據(jù)。

    下面是具體的實(shí)現(xiàn),首先在國際化資源文件中加入錯(cuò)誤消息,然后按照上面說明實(shí)現(xiàn)。因?yàn)橐褂肑avascript在客戶端顯示出錯(cuò)信息,所以在加載Input.jsp頁面時(shí),Struts 2.0需要獲得國際化的字符串,故我們需要使用Action來訪問Input.jsp頁面,具體實(shí)現(xiàn)請參考《在Struts 2.0中國際化(i18n)您的應(yīng)用程序》的最后部分。最后發(fā)布運(yùn)行應(yīng)用程序,直接在頁面中點(diǎn)擊“Submit”,表單沒有被提交并出現(xiàn)錯(cuò)誤提示,如圖7所示:

    圖7 客戶端校驗(yàn)
    圖7 客戶端校驗(yàn)

    校驗(yàn)框架是通過validation攔截器實(shí)現(xiàn),該攔載被注冊到默認(rèn)的攔截器鏈中。它在conversionError攔截器之后,在validateXxx()之前被調(diào)用。這里又出現(xiàn)了一個(gè)選擇的問題:到底是應(yīng)該在action中通過validateXxx()或validate()實(shí)現(xiàn)校驗(yàn),還是使用validation攔截器?絕大多數(shù)情況,我建議大家使用校驗(yàn)框架,只有當(dāng)框架滿足不了您的要求才自已編寫代碼實(shí)現(xiàn)。

    配置文件查找順序

    在上面的例子中,我們通過創(chuàng)建ValidationAction-validation.xml來配置表單校驗(yàn)。Struts 2.0的校驗(yàn)框架自動(dòng)會(huì)讀取該文件,但這樣就會(huì)引出一個(gè)問題——如果我的Action繼承其它的Action類,而這兩個(gè)Action類都需要對表單數(shù)據(jù)進(jìn)行校驗(yàn),那我是否會(huì)在子類的配置文件(Xxx-validation.xml)中復(fù)制父類的配置嗎?

    答案是不,因?yàn)镾truts 2.0的校驗(yàn)框架跟《在Struts 2.0中國際化(i18n)您的應(yīng)用程序》提到的“資源文件查找順序”相似,有特定的配置文件查找順序。不同的是校驗(yàn)框架按照自上而下的順序在類層次查找配置文件。假設(shè)以下條件成立:

    1. 接口 Animal;
    2. 接口 Quadraped 擴(kuò)展了 Animal;
    3. 類 AnimalImpl 實(shí)現(xiàn)了 Animal;
    4. 類 QuadrapedImpl 擴(kuò)展了 AnimalImpl 實(shí)現(xiàn)了 Quadraped;
    5. 類 Dog 擴(kuò)展了 QuadrapedImpl;

    如果Dog要被校驗(yàn),框架方法會(huì)查找下面的配置文件(其中別名是Action在struts.xml中定義的別名):

    1. Animal-validation.xml
    2. Animal-別名-validation.xml
    3. AnimalImpl-validation.xml
    4. AnimalImpl-別名-validation.xml
    5. Quadraped-validation.xml
    6. Quadraped-別名-validation.xml
    7. QuadrapedImpl-validation.xml
    8. QuadrapedImpl-別名-validation.xml
    9. Dog-validation.xml
    10. Dog-別名-validation.xml

    已有的校驗(yàn)器

    Struts 2.0已經(jīng)為您實(shí)現(xiàn)很多常用的校驗(yàn)了,以下在jar的default.xml中的注冊的校驗(yàn)器。

    < 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 ="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" />
    </ validators >
    關(guān)于每個(gè)校驗(yàn)器的具體用法,請參考以下鏈接:
    http://wiki.javascud.org/display/ww2cndoc/Validation
    該鏈接中還有一些很有的信息,請大家仔細(xì)閱讀。

    總結(jié)

    使用校驗(yàn)框架既可以方便地實(shí)現(xiàn)表單數(shù)據(jù)校驗(yàn),又能夠?qū)⑿r?yàn)與Action分離,故我們應(yīng)該盡可能使用校驗(yàn)框架。在使用校驗(yàn)框架時(shí),請不要忘記通過在資源文件加入invalid.fieldvalue.xxx字符串,顯示適合的類型轉(zhuǎn)換出錯(cuò)信息;或者使用conversion校驗(yàn)器。

    posted on 2008-09-17 15:33 綠茶_鄭州 閱讀(83) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
     
    Copyright © 綠茶_鄭州 Powered by: 博客園 模板提供:滬江博客
    主站蜘蛛池模板: 亚洲欧洲高清有无| 18女人水真多免费高清毛片| 亚洲一级毛片免观看| 亚洲线精品一区二区三区影音先锋| 成全高清视频免费观看| 三年片在线观看免费大全电影| 日本高清不卡中文字幕免费| 亚洲乱妇老熟女爽到高潮的片 | 亚洲综合av一区二区三区不卡| 亚洲国产精品国自产拍AV| 亚洲精品国产综合久久一线| 精品国产免费一区二区| 亚洲人成电影网站免费| 96免费精品视频在线观看| 两个人看的www高清免费观看| 草久免费在线观看网站| 亚洲日韩在线中文字幕综合 | 成年人视频免费在线观看| 日韩在线永久免费播放| 国产色无码精品视频免费| 一区二区3区免费视频| 精品特级一级毛片免费观看| 亚洲av永久中文无码精品综合 | 97超高清在线观看免费视频| 免费人成再在线观看网站| 国产成人综合久久精品亚洲| 亚洲欧洲无卡二区视頻| 中文字幕亚洲情99在线| 亚洲一卡二卡三卡四卡无卡麻豆| 亚洲伊人久久大香线蕉| 亚洲图片校园春色| 亚洲视频一区二区三区四区| 亚洲人成片在线观看| 91亚洲自偷在线观看国产馆| 亚洲免费观看网站| 在线观看亚洲AV日韩AV| 亚洲精品无码久久久久秋霞| 国产成人精品日本亚洲语音| 亚洲成av人在线观看网站| 美女羞羞视频免费网站 | 亚洲精品亚洲人成人网|