在寫(xiě)前幾篇文章的時(shí)候,有些朋友建議我的寫(xiě)一篇關(guān)于表單數(shù)據(jù)校驗(yàn)的文章。 正如文章的開(kāi)頭所引用的《Writing Secure Code》的名言:“所有的輸入都是罪惡的”,所以我們應(yīng)該對(duì)所有的外部輸入進(jìn)行校驗(yàn)。而表單是應(yīng)用程序最簡(jiǎn)單的入口,對(duì)其傳進(jìn)來(lái)的數(shù)據(jù),我們必須進(jìn)行校驗(yàn)。
其實(shí)上篇文章,我本來(lái)是打算寫(xiě)表單數(shù)據(jù)校驗(yàn)的內(nèi)容,但是經(jīng)過(guò)再三思考后,還是決定先寫(xiě)Struts 2.0轉(zhuǎn)換器的內(nèi)容。原因是我認(rèn)為轉(zhuǎn)換是校驗(yàn)的基礎(chǔ),只有在數(shù)據(jù)被正確地轉(zhuǎn)換成其對(duì)應(yīng)的類(lèi)型后,我們才可以對(duì)其取值范圍進(jìn)行校驗(yàn)。看個(gè)例子相信大家可以更清楚。現(xiàn)在我們就來(lái)改造一下《轉(zhuǎn)換器(Converter)——Struts 2.0中的魔術(shù)師》的第一個(gè)例子。
首先,從Action開(kāi)始,修改后的代碼如下:
然后,修改Struts.xml中Action的定義指明輸入地址:
接著,在HelloWorld.jsp中加入錯(cuò)誤提示:
再修改LocaleConverter.java文件,將內(nèi)容改為:
之后,修改國(guó)際化資源文件,內(nèi)容為:
發(fā)布運(yùn)行應(yīng)用程序,在瀏覽器中鍵入http://localhost:8080/Struts2_Validation/HelloWorld.action,在Locale中輸入zh_CN,按“Submit”提交,效果如上篇文章所示。而在服務(wù)器控制臺(tái)有如下輸出:
上述的輸出說(shuō)明了Struts 2.0的數(shù)據(jù)校驗(yàn)工作方式,它需要經(jīng)過(guò)下面幾個(gè)步驟:
不喜歡看文字的朋友,可以參考下面的圖1。
圖1 校驗(yàn)順序圖
看到這里可能大家會(huì)疑問(wèn):“這么多地方可以校驗(yàn)表單數(shù)據(jù),到底我應(yīng)該在那里做呢?”有選擇是好事,但抉擇的過(guò)程往往是痛苦的,往往讓人不知所措。如果大家參照以下幾點(diǎn)建議,相信會(huì)比較容易地做出正確的抉擇。
在運(yùn)行上面的例子時(shí),在Locale中輸入zh并提交時(shí)出現(xiàn)圖2所示頁(yè)面。
圖2 錯(cuò)誤格式
在Locale中輸入de_DE時(shí),出現(xiàn)如圖3所示頁(yè)面。
圖3 取值錯(cuò)誤
上一節(jié)的內(nèi)容都是關(guān)于如何編程實(shí)現(xiàn)校驗(yàn),這部分工作大都是單調(diào)的重復(fù)。更多情況下,我們使用Struts 2.0的校驗(yàn)框架,通過(guò)配置實(shí)現(xiàn)一些常見(jiàn)的校驗(yàn)。
我學(xué)習(xí)編程有個(gè)習(xí)慣——喜歡先看輸出結(jié)果,再看代碼實(shí)現(xiàn)。這樣學(xué)的好處是先看結(jié)果可以刺激學(xué)習(xí)的激情,也可以在看代碼前自已思考一下如何實(shí)現(xiàn),然后帶著問(wèn)題去看代碼,那就清晰多了。因此下面我們先來(lái)做演示。
首先,在tutorial包下新建ValidationAction.java,代碼如下:
然后,配置上述所建的Ation,代碼片段如下:
接著,創(chuàng)建Input.jsp和Output.jsp,內(nèi)容分別如下:
再接下來(lái),在tutorial包下創(chuàng)建ValidationAction的校驗(yàn)配置文件Xxx-validation.xml(Xxx為Action的類(lèi)名),在本例中該文件名ValidationAction-validation.xml,內(nèi)容如下:
發(fā)布運(yùn)行應(yīng)用程序,在地址欄中鍵入http://localhost:8080/Struts2_Validation/Input.jsp,出現(xiàn)如圖4所示頁(yè)面。
圖4 Input.jsp
直接點(diǎn)擊“Submit”提交表單,出現(xiàn)圖5所示的頁(yè)面。
圖5 錯(cuò)誤提示
在Required String中隨便填點(diǎn)東西,轉(zhuǎn)到Output.jsp頁(yè)面,如圖6所示。
圖6 Output.jsp
通過(guò)上面的例子,大家可以看到使用該校驗(yàn)框架十分簡(jiǎn)單方便。不過(guò),上例還有兩點(diǎn)不足:
當(dāng)然,要完善以上不足,對(duì)于Struts 2.0來(lái)說(shuō),只是小菜一碟。
下面是具體的實(shí)現(xiàn),首先在國(guó)際化資源文件中加入錯(cuò)誤消息,然后按照上面說(shuō)明實(shí)現(xiàn)。因?yàn)橐褂肑avascript在客戶端顯示出錯(cuò)信息,所以在加載Input.jsp頁(yè)面時(shí),Struts 2.0需要獲得國(guó)際化的字符串,故我們需要使用Action來(lái)訪問(wèn)Input.jsp頁(yè)面,具體實(shí)現(xiàn)請(qǐng)參考《在Struts 2.0中國(guó)際化(i18n)您的應(yīng)用程序》的最后部分。最后發(fā)布運(yùn)行應(yīng)用程序,直接在頁(yè)面中點(diǎn)擊“Submit”,表單沒(méi)有被提交并出現(xiàn)錯(cuò)誤提示,如圖7所示:
圖7 客戶端校驗(yàn)
校驗(yàn)框架是通過(guò)validation攔截器實(shí)現(xiàn),該攔載被注冊(cè)到默認(rèn)的攔截器鏈中。它在conversionError攔截器之后,在validateXxx()之前被調(diào)用。這里又出現(xiàn)了一個(gè)選擇的問(wèn)題:到底是應(yīng)該在action中通過(guò)validateXxx()或validate()實(shí)現(xiàn)校驗(yàn),還是使用validation攔截器?絕大多數(shù)情況,我建議大家使用校驗(yàn)框架,只有當(dāng)框架滿足不了您的要求才自已編寫(xiě)代碼實(shí)現(xiàn)。
在上面的例子中,我們通過(guò)創(chuàng)建ValidationAction-validation.xml來(lái)配置表單校驗(yàn)。Struts 2.0的校驗(yàn)框架自動(dòng)會(huì)讀取該文件,但這樣就會(huì)引出一個(gè)問(wèn)題——如果我的Action繼承其它的Action類(lèi),而這兩個(gè)Action類(lèi)都需要對(duì)表單數(shù)據(jù)進(jìn)行校驗(yàn),那我是否會(huì)在子類(lèi)的配置文件(Xxx-validation.xml)中復(fù)制父類(lèi)的配置嗎?
答案是不,因?yàn)镾truts 2.0的校驗(yàn)框架跟《在Struts 2.0中國(guó)際化(i18n)您的應(yīng)用程序》提到的“資源文件查找順序”相似,有特定的配置文件查找順序。不同的是校驗(yàn)框架按照自上而下的順序在類(lèi)層次查找配置文件。假設(shè)以下條件成立:
如果Dog要被校驗(yàn),框架方法會(huì)查找下面的配置文件(其中別名是Action在struts.xml中定義的別名):
Struts 2.0已經(jīng)為您實(shí)現(xiàn)很多常用的校驗(yàn)了,以下在jar的default.xml中的注冊(cè)的校驗(yàn)器。
使用校驗(yàn)框架既可以方便地實(shí)現(xiàn)表單數(shù)據(jù)校驗(yàn),又能夠?qū)⑿r?yàn)與Action分離,故我們應(yīng)該盡可能使用校驗(yàn)框架。在使用校驗(yàn)框架時(shí),請(qǐng)不要忘記通過(guò)在資源文件加入invalid.fieldvalue.xxx字符串,顯示適合的類(lèi)型轉(zhuǎn)換出錯(cuò)信息;或者使用conversion校驗(yàn)器。