版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、第二章 Struts 入門案例21 從基礎(chǔ)了解Struts現(xiàn)在,程序員們已經(jīng)編寫了很多的Web應(yīng)用程序。正如我們在第1章中指出的那樣,使用分層體系結(jié)構(gòu)來編寫應(yīng)用程序可以容易地保證同一個(gè)開發(fā)小組的成員對不同的部分有專長,同時(shí)還可以保證不同的程序員可以同時(shí)在應(yīng)用程序的不同部分并行進(jìn)行工作。但是如果小組的全體人員都能從頭至尾的了解Struts開發(fā)的全部流程也是有好處的。在我們開始了解Struts是如何讓不同部分組合在一起協(xié)同工作前,還是從最墓本例子說起。在本章會(huì)使用一個(gè)簡單但常常被用到的例子用戶登錄和退出的應(yīng)用程序,來說明Struts的結(jié)構(gòu)。在介紹了應(yīng)用程序后,我們會(huì)將應(yīng)用程序分解成不同的模塊,并且
2、詳細(xì)解說每一個(gè)模塊。如果你已經(jīng)在你的開發(fā)機(jī)器上安裝了Struts,我們希望你按照本書的介紹一步步完成開發(fā)工作。然后,打完根基后,我們會(huì)逐漸地開始構(gòu)造應(yīng)用程序。每一部分都根據(jù)你編寫該應(yīng)用程序的順序給出,而且會(huì)詳細(xì)到你可以按照它一步步編寫該應(yīng)用程序(對于我們而言,是多么麻煩的輸人工作呀!)。如果你是在自己的終端上工作,你可以按照我們的順序輸入全部的源代碼。如果不是在自己的終端上工作,你也可以通過閱讀本章來了解過程,因?yàn)槿康募?xì)節(jié)在本章中都列舉出來了。選擇登錄程序的原因我們的例子允許用戶登錄到應(yīng)用程序中。一旦用戶登錄進(jìn)入,則顯示的頁面會(huì)改變以反映出該用戶已經(jīng)獲得了使用該應(yīng)用程序的權(quán)限。一般而言,這是
3、用戶登錄到大型應(yīng)用程序的第一步,這樣應(yīng)用程序可以使授權(quán)的用戶從事其感興趣的動(dòng)作。但是對于我們而言,用戶登錄的過程已經(jīng)足夠顯示一個(gè)Struts應(yīng)用程序到底是如何工作的。正如表2-1顯示的那樣,選擇用戶登錄程序作為例子的原因主要是該例子具有如下的特性:容易被理解、簡單、自包容以及任何其他應(yīng)用程序都需要這樣的功能,因此我們僅僅選擇它作為例子。表2-1 選擇登錄應(yīng)用程序的原因原 因解 釋容易理解大多數(shù)人都曾經(jīng)登錄到某些應(yīng)用程序中,因此用戶登錄的流程容易理解簡單和自包含一個(gè)僅僅允許用戶登錄的例子程序很簡單也容易編寫,同時(shí)也是自包含的。它不需要復(fù)雜的模塊很多應(yīng)用程序都需要這樣的模塊我們中的大多數(shù)人都最終要
4、編寫需要某種登錄流程的應(yīng)用程序,因此我們需要該例程22 簡述登錄應(yīng)用程序的流程在開始簡述前,要先簡單討論一下該登錄例子程序的范圍以及如何如何遵循這個(gè)范圍。接著我們會(huì)說明該應(yīng)用程序使用的不同屏幕,同時(shí)說明當(dāng)用戶登錄時(shí)這些屏幕是如何變化的。最后在對本小節(jié)進(jìn)行了簡單的總結(jié)后,我們會(huì)回過頭來從整體上對該例子進(jìn)行分析。 起步我們在此處使用登錄例子程序的目的是使你體驗(yàn)一下Struts應(yīng)用程序的具體細(xì)節(jié)。為了保證我們專注在自己的目的上,本例子程序僅僅包含了用來顯現(xiàn)框架結(jié)構(gòu)功能的最基本模塊。該例子程序并不包含真正的業(yè)務(wù)邏輯、單元測試和漂亮的對話框。對于一個(gè)真正的應(yīng)用程序而言,這些都是很重要的,但是對于我們而言
5、,并不重要,因?yàn)槲覀儽仨氃谂芮皩W(xué)會(huì)走。本例子程序也是一個(gè)完完全全的國際化程序。它并沒有包含那些可以吸引你眼球的HTML元素它僅僅包含了我們需要的方法。當(dāng)然,你的Struts應(yīng)用程序可以做得非常漂亮。如果你期望在你自己的機(jī)器上運(yùn)行該例子程序,這可以在本書的站點(diǎn)上尋找該登錄程序Husted。該程序已經(jīng)打包作為一個(gè)可以自動(dòng)升級的WAR包。盡管我們不要求您運(yùn)行該應(yīng)用程序,但是它的運(yùn)行結(jié)果應(yīng)該還算是有趣的。要運(yùn)行該程序,你所需要做的事情都已經(jīng)包含在本章中了。首先,讓我們從用戶的角度來瀏覽這些頁面。然后,我們再回過頭來看看具體的代碼。222 將會(huì)使用的頁面正如表2-2所示,我們的登錄應(yīng)用程序有兩個(gè)頁面:歡
6、迎和登錄頁面頁 面目 的歡迎登錄歡迎用戶,同時(shí)給出應(yīng)用程序的鏈接允許輸入用戶名和密碼如果你已經(jīng)將應(yīng)用程序配置到自己的機(jī)器上,則通過瀏覽器打開下面的頁面就可以看見歡迎頁面http:1ocalhost:8080logon。22. 3 歡迎頁面第一次訪問歡迎頁面時(shí),上面僅僅有一個(gè)鏈接。該鏈接具有“Signin”的標(biāo)簽(圖2.1)。當(dāng)點(diǎn)擊該鏈接后,登錄頁面就會(huì)顯示出來。圖2-1登陸應(yīng)用程序的歡迎頁面 圖2-2登陸頁面224 登錄頁面正如圖2.2所示,登錄頁面會(huì)提交用戶名和密碼給應(yīng)用程序。檢驗(yàn)登錄表格是否工作,你可以試試在不輸入任何東西的情況下點(diǎn)擊提交按鈕。則登錄頁面會(huì)再次出現(xiàn),但是這次會(huì)多出一條消息。
7、正如圖2.3所示。圖2.3登陸頁面提示用戶名和密碼沒有輸入如果輸入了用戶名但是忘記了密碼,在按下提交按鈕后,顯示的消息則又不一樣了。如圖2.4所示。圖2-4登陸頁面提示你需要輸入密碼從用戶的角度而言,下面是關(guān)于該流程中需要記住的一些要點(diǎn):·它立刻告訴用戶是否忘記輸入某些數(shù)據(jù)項(xiàng)。·如果用戶僅僅提交了一個(gè)數(shù)據(jù),則它會(huì)提示用戶輸入另外一個(gè)數(shù)據(jù)。·它在屏幕上再次顯示已經(jīng)輸入的數(shù)據(jù)而不要用戶輸入Back鍵。·如果用戶輸入了正確的用戶名和密碼,則下一個(gè)頁面會(huì)顯示。如同第1章中的注冊程序一樣,本例子程序使用屬性文件來檢驗(yàn)登錄信息的合法性。如果你使用從同上下載的例子程序
8、,則可以用任何一個(gè)本書作者的名字來登錄進(jìn)去。如表3-3所示。表2-3 默認(rèn)的登錄用戶名和密碼用戶名密碼TedCedricGeorgeDavidCraigHustedDumoulinFranciscusWinterfeldtMcClanahan注意:密碼是大小寫敏感的。請確保第一個(gè)字母是大寫。225 再次進(jìn)入歡迎頁面當(dāng)成功登錄后,歡迎頁面再次出現(xiàn)。但是這次和第一次看見的歡迎頁面有兩點(diǎn)不同。如圖2.5所示。圖2.5首先,頁面上會(huì)顯現(xiàn)用戶名。而不是顯現(xiàn)“WelcomeWorld!”。而且,頁面上還多了一個(gè)超鏈接。除了“Signin”以外,還有“Sign out”。2,26 退出歡迎頁面如果點(diǎn)擊“Si
9、gn out”鏈接,則我們又回到了最開始的歡迎頁面(如圖2.1所示)。227 特性摘要盡管我們的應(yīng)用程序很簡單,但是它也顯示了幾個(gè)重要技術(shù):·輸出超鏈接。·輸出表格。·校驗(yàn)輸入。·顯示錯(cuò)誤信息。·重新填充表格。·顯示可改變的內(nèi)容。盡管不是顯而易見的,但是它還顯示了下面的技術(shù):·在動(dòng)態(tài)頁面中使用圖像。·重寫超鏈接。在下一節(jié)中,我們將通過研究源程序來說明這些核心特性是如何實(shí)現(xiàn)的。23 解剖登錄應(yīng)用程序此時(shí)我們已經(jīng)初步知道了如何使用Struts編寫登錄程序?,F(xiàn)在就要回過頭來仔細(xì)看看該程序的構(gòu)成。我們將說明每一個(gè)頁面的代碼
10、,同時(shí)也說明相關(guān)的組件以及每一個(gè)部分是如何工作的。在介紹完全部這些細(xì)節(jié)問題后,我們再說明如果使用這些部分組成一個(gè)應(yīng)用程序。231 瀏覽器中歡迎頁面的代碼我們的應(yīng)用程序是從歡迎頁面開始的?,F(xiàn)在先讓我們看看瀏覽器中的歡迎頁面的代碼僅僅是為了看看到底瀏覽器顯示了什么(見代碼清單2.1)。下面標(biāo)注為黑體的部分是顯示在屏幕上的文字。代碼清單2.1 瀏覽器中歡迎頁面的代碼<HTML><HEAD><TITLE>Welcome World!</TITLE><base href="http:/localhost:8080/logon/pages/W
11、elcome.jsp"></HEAD><BODY><H3>Welcome World!</H3><UL><LI><a href="/logon/logon.do">Sign in</a></LI></UL><IMG src='struts-power.gif' alt='Powered by Struts'></BODY></HTML>如果你是Web應(yīng)用程序的新手,則要記住
12、的一件重要事情就是這兒僅僅只有標(biāo)準(zhǔn)的HTML語句。實(shí)際上,Web頁面上僅顯現(xiàn)那些瀏覽器能夠理解的語言。所有的Web應(yīng)用程序都受到HTML的限制,因此不能做超過HTML能力范圍的事情。Struts通過使用Velocity模板、JSP以及任何我們愿意使用用來編寫HTML的工具來使得該過程簡單化。但是我們能夠做的事情范圍還是要在瀏覽器能夠理解的標(biāo)志語言范圍內(nèi)。關(guān)鍵字:jsessionid在瀏覽器源代碼中可能有某個(gè)東西你認(rèn)為不是標(biāo)準(zhǔn)的HTML語句。當(dāng)你第一次該 問該頁面時(shí),“sing-in”鏈接可能看上去實(shí)際類似于:<LI><a href=”/logon.do;jsessionid=
13、aa6xkGuY8qc”>Sign in </a</LI>大多數(shù)Web應(yīng)用程序都需要跟蹤使用該程序的用戶。HTTP對維護(hù)用戶登錄提供了一些最基本的支持,但是該方法能力有限,而且也不安全。Java的Servlet技術(shù)提供了更好的用戶會(huì)話支持。但是需要某種機(jī)制跨越不同的HTTP請示來維護(hù)會(huì)話信息。Jsessionid就是容器用來在HTTP上維護(hù)用戶會(huì)話的一個(gè)關(guān)鍵技術(shù)。在超鏈接的URL中包含的會(huì)話關(guān)鍵字的技術(shù)被稱為URL重寫。Servlet規(guī)范Sun,JST鼓勵(lì)在cookie中維護(hù)用戶會(huì)話。而當(dāng)cookie不可用時(shí),URL重寫技術(shù)就應(yīng)當(dāng)被使用。當(dāng)瀏覽器第一次向容器發(fā)出請求時(shí),
14、容器并不知道該瀏覽器是否接受cookie。盡管容器向?yàn)g覽器發(fā)出一個(gè)cookie,但是直到瀏覽器再次發(fā)出請求前,容器是無法辨別該瀏覽器是否接受了該cookie(HTTP協(xié)議沒有握手的過程)。同時(shí),當(dāng)前請求的響應(yīng)也一定也是要輸出的。因此,返回給瀏覽器的第一頁總是會(huì)使用URL重寫技術(shù)。如果后續(xù)請求中發(fā)現(xiàn)cookie存在,則容器就可以不用URL重寫方法。232 歡迎頁面的JSP源代碼代碼清單2-2 歡迎頁面的JSP源代碼(/pages/Welcome.jsp)<% taglib uri="/tags/struts-bean" prefix="bean" %
15、><% taglib uri="/tags/struts-html" prefix="html" %><% taglib uri="/tags/struts-logic" prefix="logic" %><HTML><HEAD><TITLE>Welcome!</TITLE><html:base/></HEAD><BODY><logic:present name="user"&
16、gt;<H3>Welcome <bean:write name="user"property="username"/>!</H3></logic:present><logic:notPresent scope="session" name="user"><H3>Welcome World!</H3></logic:notPresent><html:errors/><UL><LI><
17、;html:link forward="logon">Sign in</html:link></LI><logic:present name="user"><LI><html:link forward="logoff">Sign out</html:link></LI></logic:present></UL><IMG src='struts-power.gif' alt='Powered b
18、y Struts'></BODY></HTML> 現(xiàn)在我們看看那些標(biāo)記為黑體的行:<% taglib uri="/tags/struts-bean" prefix="bean" %><% taglib uri="/tags/struts-html" prefix="html" %><% taglib uri="/tags/struts-logic" prefix="logic" %>這些JSP語句等價(jià)于
19、Java中的輸入語句,并且使輸入的擴(kuò)展標(biāo)簽庫可以被頁面的其他部分使用。代碼<html:base>會(huì)生成一個(gè)標(biāo)準(zhǔn)的HTMLbase標(biāo)簽,這使得對圖像等資源的引用與原始JSP頁面的位置相關(guān)。你也許已經(jīng)注意到,我們的登錄應(yīng)用程序有時(shí)候引用do這樣的頁面。它們并不是真正存在于服務(wù)器上的頁面,而是引用由程序員編寫的Java類或者Action類。這些Action然后會(huì)將控制權(quán)傳遞給JSP文件來生成http響應(yīng)。JSP一般都包含類似于圖像或者CSS文件這樣資源的引用。最方便使用這些資源的方法就是使用與JSP模板位置相關(guān)的路徑。但是,當(dāng)Action將控制轉(zhuǎn)發(fā)給JSP頁面時(shí),它并沒有通知瀏覽器。因此
20、當(dāng)瀏覽器要使用任何具有相對路徑的資源引用時(shí),它會(huì)將Action所在的路徑認(rèn)為是基本路徑,而不是JSP模板所處的位置。根據(jù)你訪問歡迎頁面的時(shí)刻不同,瀏覽器顯示該頁面的位置可能是:http:/localhost:8080/logon/http:/localhost:8080/logon/LogonSubmit.dohttp:/localhost:8080/logon/Logoff.do對于使用動(dòng)態(tài)內(nèi)容的應(yīng)用程序而言,這是一個(gè)常見的問題。因此HTML規(guī)范提供了base標(biāo)簽作為解決方法。Struts提供的相對應(yīng)的html-base標(biāo)簽會(huì)將該JSP的位置作為基本路徑插入JSP文件中。對于從不同位置生成的
21、登錄頁面,如果查看對應(yīng)的HTML源代碼,你會(huì)發(fā)現(xiàn)無論在什么地方,生成的base標(biāo)簽都是: <base href="http:/localhost:8080/logon/pages/Welcome.jsp">這樣瀏覽器就可以在發(fā)現(xiàn)pages文件夾中的“Power by Struts”圖像?,F(xiàn)在我們看看下面的代碼:<logic:present name="user"><H3>Welcome <bean:write name="user" roperty="username"/&
22、gt;!</H3></logic:present>你可能還記得本歡迎頁面是根據(jù)用戶是否已經(jīng)登錄進(jìn)入系統(tǒng)來定制化自己的顯示。上面的代碼像是檢查是否在用戶session中存儲了userbean。如果存在該bean,則在歡迎頁面中顯現(xiàn)用戶名。下面的代碼顯示了維護(hù)用戶session的重要性。Struts的標(biāo)簽和Servlet容器會(huì)合作來自動(dòng)維護(hù)用戶session(不管用戶瀏覽器是否使用cookie)。對于程序員而言,就如同已經(jīng)在http中內(nèi)建了session一樣這就是框架結(jié)構(gòu)帶來的好處??蚣芙Y(jié)構(gòu)會(huì)擴(kuò)展底層的支持環(huán)境使得程序員可以關(guān)注于那些更高層次的任務(wù)。<logic:no
23、tPresent scope="session" name="user"><H3>Welcome World!</H3></logic:notPresent>相反的,如果存在user bean,則我們會(huì)使用定制化的歡迎頁面。Struts的邏輯標(biāo)簽都是使用“this”和“notThis”這樣的表單,并沒有提供類似于“Else”這樣的標(biāo)簽。盡管這意味著更多的條件判斷語句,但是這也簡化了總體語法和標(biāo)簽的實(shí)現(xiàn)代碼。當(dāng)然,也可以使用其他的擴(kuò)展標(biāo)簽庫。用戶并沒有被限制僅僅使用Struts提供的標(biāo)簽庫。在Struts網(wǎng)站上的可
24、用資源列表中已經(jīng)列出了多個(gè)共享的擴(kuò)展標(biāo)簽庫ASF,Struts。其中的某個(gè)標(biāo)簽庫就實(shí)現(xiàn)了if/then/else語法。如果你想用這種語法,就可以選用該標(biāo)簽庫。正如我們在231節(jié)中說的那樣,Struts會(huì)自動(dòng)重寫超鏈接來維護(hù)用戶會(huì)話。它也允許你給超鏈接一個(gè)邏輯名,同時(shí)將它們存儲在配置文件中。這就如同使用關(guān)鍵字來引用數(shù)據(jù)庫中的記錄一樣。記錄中的名字和地址是可以根據(jù)需要進(jìn)行改變的。而應(yīng)用程序通過使用關(guān)鍵字來找到更新后的記錄。在本例中<LI><html:link forward="logon">Sign in</html:link></LI
25、>我們使用logon這個(gè)關(guān)鍵字來尋找記錄,它存儲了使用戶登錄進(jìn)入系統(tǒng)的超鏈接。如果我們以后想改變該超鏈接,僅僅需要在配置文件中改變一次,然后重新啟動(dòng)應(yīng)用程序就可以了。頁面在被請求時(shí)就會(huì)自動(dòng)使用新鏈接。下面的代碼聯(lián)合使用了<logic:present> 和 <html:link>僅對已經(jīng)登錄的用戶顯現(xiàn)退出的鏈接。<logic:present name="user"><LI><html:link forward="logoff">Sign out</html:link></L
26、I></logic:present>2. 33 歡迎頁面的配置信息Struts使用配置文件來定義應(yīng)用程序中的很多事情,其中就包括超鏈接的邏輯名。Struts使用的配置文件是一個(gè)XML格式的文件,在其啟動(dòng)時(shí)會(huì)將它讀到內(nèi)存中,并且根據(jù)其內(nèi)容來創(chuàng)建一個(gè)存儲各種對象的數(shù)據(jù)庫。各個(gè)模塊都是使用該數(shù)據(jù)庫來提供不同的服務(wù)。配置文件的默認(rèn)名字是struts-configxml。正是因?yàn)椴煌哪K都使用同一個(gè)配置文件,因此我們就應(yīng)該一開始就定義好該文件?,F(xiàn)在,我們會(huì)逐步給出和每一步相關(guān)的那部分配置信息。最后,當(dāng)我們從頭開始構(gòu)造應(yīng)用程序時(shí),我們會(huì)從整體上了解該配置文件。在開始的歡迎頁面中,我們引
27、用了logon。在配置文件中,它是這樣定義的:<forwardname="logon"path="/Logon.do"/>此處,logon是用來尋找某個(gè)超鏈接實(shí)際路徑的關(guān)鍵字。盡管這兒引用的是Struts的一個(gè)Action,但是我們也可以很容易地引用JSP頁面、Velocity模板、HTML頁面或者帶有URl的任何資源。定義URI(uniform resource identifier)是用來定位因特網(wǎng)上或者任何其他計(jì)算機(jī)網(wǎng)絡(luò)上資源的短字符串。資源是指文檔,圖像,可以被下載的文件,電子郵箱或者其他東西。一個(gè)URI可以對應(yīng)服務(wù)器上文件系統(tǒng)的路徑
28、,但經(jīng)常是該路徑的別名。Struts應(yīng)用程序中的URI都是Java類或者Action的別名。因?yàn)樵撀窂蕉x在配置文件中,因此你可以在任何時(shí)候改變其值而不用修改JSP文件。如果你修改并且重新裝載了該配置文件,則再下次生成該JSP對應(yīng)頁面時(shí)就會(huì)使用修改后的值。234 瀏覽器中登錄頁面的代碼當(dāng)你點(diǎn)擊歡迎頁面中的sign-in超鏈接,瀏覽器就會(huì)跳轉(zhuǎn)到登錄頁面。代清單2-3顯示了該頁面在瀏覽器中的代碼。同樣地,下面代碼中的黑體部分就是顯示在屏幕上的文字。代碼清單2.3 登錄頁面在瀏覽器中的代碼<HTML><HEAD><TITLE>Sign in, Please!<
29、;/TITLE></HEAD><BODY><form name="logonForm" method="POST"action="/logon/LogonSubmit.do"><table border="0" width="100%"><TR><TH align="right">Username:</TH><TD align="left"><inp
30、ut type="text" name="username"value=""></TD></TR><TR><TH align="right">Password:</TH><TD align="left"><input type="password" name="password"value=""></TD></TR><
31、TR><TD align="right"><input type="submit" name="submit"value="Submit"></TD><TD align="left"><input type="reset" name="reset"value="Reset"></TD></TR></table></form>
32、<script language="JavaScript" type="text/javascript"><!-document.forms"logonForm".elements"username".focus()/ -></script></BODY></HTML>代碼清單2.4 登錄頁面對應(yīng)的JSP代碼(pageslogonjsp)<% taglib uri="/tags/struts-html" prefix="
33、html" %><HTML><HEAD><TITLE>Sign in, Please!</TITLE></HEAD><BODY><html:errors/><html:form action="/LogonSubmit" focus="username"><TABLE border="0" width="100%"><TR><TH align="right"
34、;>Username:</TH><TD align="left"><html:text property="username"/></TD></TR><TR><TH align="right">Password:</TH><TD align="left"><html:password property="password"/></TD></TR>&
35、lt;TR><TD align="right"><html:submit/></TD><TD align="left"><html:reset/></TD></TR></TABLE></html:form></BODY></HTML><%-Allow user to submit username and password to logon action.-%>我們還是如同處理歡迎頁面一樣來研究每個(gè)黑體部分
36、。首先,和歡迎頁面一樣,下面的代碼使Struts的html標(biāo)簽庫可以被頁面的其他部分使用:< taglib uri="tagsstrUts-html" prefix="html" >和Struts的action類似,taglib使用的URl也是一個(gè)邏輯引用。標(biāo)簽庫描述符(tag library descriptor TLD)定義在web.xml中。如果我們沒有輸入數(shù)據(jù)時(shí),就提交該表格,并看到一條錯(cuò)誤信息。下面的標(biāo)簽就是用來生成該錯(cuò)誤信息的。如果沒有錯(cuò)誤信息,則該標(biāo)簽不會(huì)進(jìn)行任何輸出,也不會(huì)出現(xiàn)在最終的頁面上顯示。<html:errors
37、/>而<html:form>標(biāo)簽會(huì)生成一個(gè)HTML表單來使用戶輸入數(shù)據(jù)。它同時(shí)還會(huì)使用簡單的JavaScript來使輸入焦點(diǎn)移動(dòng)到該表格的第一個(gè)輸入框上。而其action屬性指向Struts配置中的某個(gè)ActioinMapping對象。該對象決定了使用哪個(gè)JavaBean來填充HTML控件。同時(shí)該JavaBean也是Struts框架結(jié)構(gòu)的一個(gè)ActionForm類。<html:form action="/LogonSubmit"focus="username"><html:text>標(biāo)簽創(chuàng)建一個(gè)HTML文本域輸入
38、框。同時(shí),它還使用該表格對應(yīng)的JavaBcan中屬性名為username的屬性值來進(jìn)行自我填充。<TR><TH align="right">Username: </TH><TD align="left"><html:text property="usarname"/></TD>因此,如果該表格因?yàn)樾r?yàn)不通過而被返回,同時(shí)最后一次提交的用戶名是Ted,則該標(biāo)簽的輸出就是:<input type="text" name="usern
39、ame" value="Ted">否則,該標(biāo)簽就會(huì)使用JavaBean中username字段指定的默認(rèn)值來初始化自己。通常,該默認(rèn)值是null,但是也可以是任何其他值。同樣,<html:password>標(biāo)簽會(huì)創(chuàng)建一個(gè)HTML輸入控制框。<TR><TH align="right">Password:</TH><TD align="left"><html:password property="password"/></TD&
40、gt;當(dāng)表格被提交時(shí),需要使用兩個(gè)對象:ActionForm和Action。程序員負(fù)責(zé)創(chuàng)建這兩個(gè)對象并包含應(yīng)用程序的細(xì)節(jié)信息。正如圖2.6所示,ActionServlet使用配置文件來決定使用哪一個(gè)ActionForm和Action。ActionFormActionServlet配置圖2-6 配置文件決定使用哪個(gè)ActionForm和Action235 登錄頁面對應(yīng)的配置部分登錄頁面本身僅僅使用Struts配置文件中的一個(gè)元素:/LogonSubmit。該元素會(huì)引用兩個(gè)元素:app.LogonForm和app.LogonAction。在表2.4中我們依次解釋了這三個(gè)元素。表2.4 登錄頁面使用
41、的配置元素元素描述/LogonSubmit封裝了構(gòu)造和提交一個(gè)HTML表格給Struts應(yīng)用程序的實(shí)現(xiàn)細(xì)節(jié)app.LogonForm描述了HTML表格使用的屬性app.LogonAction用來完成提交表格流程236 LogonSubmit的源代碼在上一節(jié)中,我們曾經(jīng)提到<html:form>標(biāo)簽和Struts配置文件緊密合作使HTML的表格更加好用:<html:form action="LogonSubmit"focusc="username">上面的action參數(shù)告訴<html:form>標(biāo)簽使用哪一個(gè)Actio
42、nMapping。在本例中,對應(yīng)的ActionMapping如下:<actionpath="/LogonSubmit"typex="appLogonAction"name="logonForm"scope="request"validate="true"input="/pages/Logonjsp"/>表2.5說明了上面每一個(gè)元素的意義。正如我們在第2章中提到的那樣,Struts使用的很多對象名和屬性名都是很含糊的。例如,上面的name屬性并不是指定該Action
43、Mapping對象的名字,而是指定該ActionMapping使用的JavaBean或者ActionForm的名字。在配置文件中,同樣也定義了form bean:表2.5 ActionMapping的配置元素屬 性功 能path是該ActionMapping的唯一標(biāo)識符。它包含對應(yīng)的Web地址,例如http:/localhost:8080/logon/LogonSubmitdotype當(dāng)請求該路徑時(shí),調(diào)用的Action對象name定義對于一個(gè)HTML表格對應(yīng)的JavaBean(ActionForm)scope該屬性定義了存儲該JavaBean在請求中還是在會(huì)話中validate該屬性定義了在調(diào)
44、用由type指定的Action對象前是否調(diào)用由name指定的JavaBean上的validate方法input該屬性定義了當(dāng)validate方法返回false時(shí)控制要轉(zhuǎn)移的地址<form-beanname="logonform"type="app.LogonForm"/>該元素將邏輯名logonForm和一個(gè)指定的Java類app.LogonFonn聯(lián)系在一起。該類應(yīng)該是ActionForm的子類。在ActionForm類中已經(jīng)提供了一些標(biāo)準(zhǔn)的方法,例如validate方法?,F(xiàn)在我們先看看LogonForm的源代碼,然后再回來看看LogonA
45、ction對象。237 LogonForm的源代碼盡管HTML表格允許用戶輸入數(shù)據(jù),但是并沒有在應(yīng)用程序中定義何處來存放這些數(shù)據(jù)。當(dāng)用戶點(diǎn)擊提交按鈕時(shí),瀏覽器收集表格中的數(shù)據(jù),然后以名字值成對的形式發(fā)送給服務(wù)器。因此,當(dāng)用戶在登錄頁面上輸入用戶名和密碼并且提交其輸入后,應(yīng)用程序知道:username=Tedpassword=LetMeln瀏覽器將所有的數(shù)據(jù)都作為字符串進(jìn)行提交。在頁面上通過使用JavaScnpt,你可以強(qiáng)制用戶在某些域中輸入數(shù)字或者某種特定格式的數(shù)據(jù),但是這僅僅都是表面現(xiàn)象。用戶輸入的所有東西都最后會(huì)轉(zhuǎn)化為字符串來提交給應(yīng)用程序,而不是二進(jìn)制對象。這是瀏覽器和HTML的工作方式
46、,Web應(yīng)用程序沒有辦法控制這一點(diǎn)。類似Struts這樣的框架結(jié)構(gòu)已經(jīng)盡力來進(jìn)行處理了。Struts使用ActionForm作為解決方案來處理HTTP的數(shù)據(jù)對。在像Swing這樣的環(huán)境中,數(shù)據(jù)輸入控制都有一個(gè)內(nèi)置的文本緩沖區(qū)來對用戶輸入的字符進(jìn)行校驗(yàn)。當(dāng)用戶結(jié)束輸入離開該緩沖區(qū)時(shí),緩沖區(qū)中的內(nèi)容就可以被轉(zhuǎn)換為二進(jìn)制類型,然后就發(fā)送給后面的業(yè)務(wù)邏輯層進(jìn)行處理。不幸的是,HTTP/HTML平臺并不能提供類似的對輸入進(jìn)行緩存、校驗(yàn)和轉(zhuǎn)換的模塊。因此,Struts提供ActionForm(.action.ActionForm)來彌補(bǔ)Web瀏覽器和業(yè)務(wù)邏輯層之間的差距。ActionForm提供了我們需要
47、的緩存、校驗(yàn)和轉(zhuǎn)換機(jī)制來保證用戶僅僅能輸入期望的數(shù)據(jù)。當(dāng)提交HTML表格時(shí),Struts控制器獲得提交的名字一值對,然后將它們交給ActionForm來處理。ActionForm是一個(gè)和某個(gè)HTML表格具有對應(yīng)屬性的JavaBean。Struts會(huì)比較ActionForm的每一個(gè)屬性的名字和提交的表單中名字一值對中的名字。當(dāng)它們匹配時(shí),這控制器使用相應(yīng)提交的值來設(shè)定JavaBean的屬性值。其他的沒有匹配的屬性則被忽略掉。通常那些被忽略掉的屬性則保持其為默認(rèn)值(一般都是null或者false)。下面是LogonForm的屬性:private String password = null;pub
48、lic String getPassword() return (this.password);public void setPassword(String password) this.password = password;private String username = null;public String getUsername() return (this.username);public void setUsername(String username) this.username = username;大多數(shù)ActionForm類的屬性都這樣。一些程序員使用宏就可以容易地通過輸
49、入屬性名來生成對應(yīng)的代碼。另外一些可以在編輯器中使用代碼粘貼。而Struts代碼生成器則可以通過使用HTML或者JSP來創(chuàng)建對應(yīng)的ActionForm。注意 在Struts11中,如果使用DynaActionForm或者集合類型的ActionForm,則創(chuàng)建ActionForm會(huì)更加簡單?;镜腁ctionForm包含兩個(gè)標(biāo)準(zhǔn)方法reset和validate。在向?qū)?wizard)工作流中使用ActionForm時(shí),reset方法很有用。如果該對象工作的范圍被設(shè)定為請求(request),則可以使用默認(rèn)的實(shí)現(xiàn)。當(dāng)validate被設(shè)定為true時(shí),則在該bean通過HTTP請求進(jìn)行填充后會(huì)調(diào)用
50、它的validate方法。Validate方法經(jīng)常被用來進(jìn)行主要的校驗(yàn)工作。該校驗(yàn)方法僅僅檢查數(shù)據(jù)是“看上去”正確,并且所有需要的值都被提交。再重復(fù)一次,對于Swing控件而言,這些工作都是swing,組件在將數(shù)據(jù)傳遞給應(yīng)用程序前內(nèi)部進(jìn)行的操作。對于使用Struts的應(yīng)用程序而言,我們也可以手工進(jìn)行這些操作,或者通過使用ValidatorForm來實(shí)現(xiàn),它也可以通過配置文件進(jìn)行設(shè)置。下面就是LogonForm的validate方法。它僅僅檢查其對應(yīng)的兩個(gè)域是否都輸入了數(shù)據(jù)。如果應(yīng)用程序有其他的要求,例如用戶名或者密碼的長度有限制,則你可以在該方法中進(jìn)行檢查。public ActionError
51、s validate(ActionMapping mapping,HttpServletRequest request) ActionErrors errors = new ActionErrors();if (username = null) | (username.length() < 1)errors.add ("username",new ActionError("");if (password = null) | (password.length() < 1)errors.add("password",new A
52、ctionError("error.password.required");return errors;該方法返回的ActionError是Struts框架結(jié)構(gòu)提供的另外一個(gè)類。如果vslidate方法返回的ActionError對象既不是null也不是空,則控制器通過一個(gè)已定義的鍵將該對象保存在HTTP請求的上下文中。因?yàn)?lt;html:errors>標(biāo)簽也知道該鍵,所以如果該鍵存在,那么該標(biāo)簽會(huì)將錯(cuò)誤信息提取出來。如果在HTTP請求中不存在該鍵,那么該標(biāo)簽什么也不做。都是鍵。它們用來從Struts消息資源文件中提取真正的消息。每一個(gè)地區(qū),都有一個(gè)自己的資源文件。
53、這就簡化了消息的本地化。Struts的消息資源文件同樣使用名字一值對。在我們的例子中,對應(yīng)的兩項(xiàng)是:Error.Username,required=<li>Username is requxred</li>error.password.required=<ll>Passuord is renuired</li>注意 在Struts11中,還有其他的方法在消息中使用HTML標(biāo)簽。可以使用errorsprefix和errorsuffix的新特性來指定類似于<1i></li>這樣的標(biāo)簽。同時(shí),也可以使用新的消息標(biāo)簽來代替原有的&
54、lt;html:errors>標(biāo)簽。該標(biāo)簽簡化了表現(xiàn)層上標(biāo)簽的維護(hù)工作。就算不需要進(jìn)行本地化工作,Struts應(yīng)用程序?qū)⑷肯⒋鎯υ谝粋€(gè)地方,這樣用戶就可以在不修改JSP代碼的情況下對這些消息進(jìn)行瀏覽和修改了。238 LogonAction的源代碼在將數(shù)據(jù)收集進(jìn)ActionForm對象,并且進(jìn)行了初步的校驗(yàn)后,控制器將ActionForm對象傳遞給指定的Action類。Struts應(yīng)用程序認(rèn)為你會(huì)使用自己的類來完成絕大部分請求工作。Action會(huì)保存請求完成后的結(jié)果,而JSP文件是用來顯示該結(jié)果的。正如我們在第2章中闡述的那樣,這就是被稱為MVC或者M(jìn)odel2的解決方法。其中,Act
55、ion類的工作就是分派HTTP請求。當(dāng)Struts的sevrlet接受到某個(gè)Action的請求時(shí),它就會(huì)通過調(diào)用該Action的perform(execute)方法來分派該請求。代碼清單2.5包含了全部代碼。代碼清單2.5 LogonAction類的源代碼package app;n;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import javax.servlet.http.HttpServlet
56、Response;import org.apache.struts.action.Action;import org.apache.struts.action.ActionError;import org.apache.struts.action.ActionErrors;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;import org.apache.struts.act
57、ion.ActionServlet;public final class LogonAction extends Action /通過業(yè)務(wù)邏輯層校驗(yàn)用戶身份public boolean isUserLogon(String username,String password)throws UserDirectoryException return(UserDirectory.getInstance().isValidPassword(username,password);/isUserLogon結(jié)束public ActionForward perform(ActionMapping mappin
58、g,ActionForm form,HttpServletRequest request,HttpServletResponse response)throws IOException, ServletException /通過Web層獲取用戶名和密碼String username = (LogonForm) form).getUsername();String password = (LogonForm) form).getPassword();/ 校驗(yàn)用戶名和密碼的正確性boolean validated = false;try validated = isUserLogon(userna
59、me,password);catch (UserDirectoryException ude) /不能連接用戶目錄ActionErrors errors = new ActionErrors();errors.add(ActionErrors.GLOBAL_ERROR,ct");saveErrors(request,errors);return (new ActionForward(mapping.getInput();if (!validated) /身份不匹配ActionErrors errors = new ActionErrors();errors.add(ActionErr
60、ors.GLOBAL_ERROR,new ActionError("error.logon.invalid");saveErrors(request,errors);/返回到input屬性指定的頁面return (new ActionForward(mapping.getInput();/將登陸用戶信息存放在session中/因?yàn)橐院筮€要使用HttpSession session = request.getSession();session.setAttribute(Constants.USER_KEY, form);if (servlet.getDebug() >=
61、 Constants.DEBUG) StringBuffer message =new StringBuffer("LogonAction: User '");message.append(username);message.append("' logged on in session ");message.append(session.getId();servlet.log(message.toString();/返回successreturn (mapping.findForward(Constants.SUCCESS);/perfo
62、rm結(jié)束 /LogonAction結(jié)束Action類處于Struts的頂部,因此它又導(dǎo)入了其他幾個(gè)類。我們此時(shí)細(xì)化每一個(gè)被使用的類,這樣便于了解到底這些類是來自哪一個(gè)包。import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import javax.servlet.http.HttpServletResponse;import org.apache.str
63、uts.action.Action;import org.apache.struts.action.ActionError;import org.apache.struts.action.ActionErrors;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;import org.apache.struts.action.ActionServlet;如果偷懶的話,還可以這樣定義導(dǎo)人:import java.io.*;import javax.s
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 旅游紀(jì)念品銷售租賃合同
- 2024年國際貨物交易服務(wù)平臺協(xié)議
- 城市管道保溫施工合同
- 漁業(yè)資源保護(hù)苗種管理
- 醫(yī)療云計(jì)算設(shè)備養(yǎng)護(hù)管理辦法
- 珠寶首飾流通新規(guī):典當(dāng)管理辦法
- 旅游設(shè)施施工代理協(xié)議
- 消防設(shè)施采購招投標(biāo)注意事項(xiàng)
- 銷售部員工年度工作總結(jié)5篇
- 04版物業(yè)公司能源管理優(yōu)化合同
- 廣告宣傳費(fèi)用巧籌劃三個(gè)方案
- 模板支架及腳手架安全使用培訓(xùn)課件
- 企業(yè)財(cái)產(chǎn)保險(xiǎn)投保單
- CT報(bào)告單模板精編版
- 柿子品種介紹PPT課件
- 內(nèi)鏡清潔消毒登記表格模板
- 天然氣脫硫(課堂運(yùn)用)
- 幼兒園教師師德師風(fēng)考核表(共2頁)
- 城鎮(zhèn)職工醫(yī)療保險(xiǎn)運(yùn)行中的問題分析及措施
- 學(xué)校食堂五常法管理制度
- 畢業(yè)設(shè)計(jì)500kv變電站設(shè)計(jì)
評論
0/150
提交評論