Jakarta Struts簡介
翻譯作者:-
Matrix開源技術-Wingc
翻譯前的話 呵呵,這是wingc第一次真正意義的翻譯技術文章,自己看E文文檔和把E文翻譯成能讀的中文那真是兩回事啊,翻譯得不好再所難免,您可別罵wingc哦:)若有什么地方不通、不爽或不妥,請見
http://www.onjava.com/pub/a/onjava/2001/09/11/jsp_servlets.html看原文吧。
Web應用開發早期曾經是那么的“簡單”,那個時候還只是純HTML頁面和瀏覽器特效而已。由于還涉及不到動態數據操作和商業應用,也就省去了很多麻煩。但是這樣的“簡單”只是過眼云煙,如今我們不得不為復雜的基于Web的商業應用開發采用諸多技術。
本文將介紹如何利用Struts進行應用開發的前臺整合的開發過程。Struts是一個為開發基于模型(Model)-視圖(View)-控制器(Controller)(MVC)模式的應用架構的開源框架(譯注1),是利用Java Servlet和JSP構建Web應用的一項非常有用的技術。
閱讀本文需要讀者具有以下幾方面的開發經驗:JSP、Servlet、自定義標簽庫(custom tag library)和XML。如果讀者想補一補自定義標簽庫的知識,可以參考作者以前關于這方面的文章。而本文也是關于介紹如何使用Struts系列文章的上半部分,本系列暫定分為上下兩部分。
新手上路注意事項 Struts是一個基于Sun J2EE平臺的MVC框架,主要是采用Servlet和JSP技術來實現的。其最初萌芽于Craig McClanahan的構思,誕生至今也一年有余了(譯注2)?,F在,Struts是Apache軟件基金會旗下Jakarta項目組的一部分,其官方網站是
http://jakarta.apache.org/struts。由于Struts能充分滿足應用開發的需求,簡單易用,敏捷迅速,在過去的一年中頗受關注。Struts把Servlet、JSP、自定義標簽和信息資源(message resources)整合到一個統一的框架中,開發人員利用其進行開發時不用再自己編碼實現全套MVC模式,極大的節省了時間,所以說Struts是一個非常不錯的應用框架。
目前的Struts 1.0修正版包括完整的文檔,既可以說是用戶文檔又是開發指導文檔。如果讀者是JSP新手,或者對MVC設計模式不是太熟的話,可能剛上路時會比較慢,不過不用擔心,要相信自己會盡快趕上的:)
此外,應該注意到盡管當前Struts只是1.0版,但已經相當穩定了,作者從Struts 0.9版就在一個大規模的項目中應用了(最近升級到1.0版),至今還沒有遇到什么麻煩問題。實際上,Struts在這個要開發復雜用戶界面的項目中,為我們團隊大大的縮短了開發時間,在此衷心的感謝Struts項目團隊的所有開發人員。
哦,還有,如果讀者開始上路了,要知道Struts的郵件列表可是有相當分量的,在這里混混才可保證能及時跟上Jakarta項目的最新動態哦
http://jakarta.apache.org/site/mail.html。
開始上路! Struts框架可分為以下四個主要部分,其中三個就和MVC模式緊密相關:
1、模型(Model),本質上來說在Struts中Model是一個Action類(這個會在后面詳細討論),開發者通過其實現商業邏輯,同時用戶請求通過控制器(Controller)向Action的轉發過程是基于由struts-config.xml文件描述的配置信息的。
2、視圖(View),View是由與控制器Servlet配合工作的一整套JSP定制標簽庫構成,利用她們我們可以快速建立應用系統的界面。
3、控制器(Controller),本質上是一個Servlet,將客戶端請求轉發到相應的Action類。
4、一堆用來做XML文件解析的工具包,Struts是用XML來描述如何自動產生一些JavaBean的屬性的,此外Struts還利用XML來描述在國際化應用的用戶提示信息的(這樣一來就了應用系統的實現多語言支持)。
好,下一步咱們來看看構成這個框架的各個部分以及相互之間是怎樣運作的吧!
搞定配置先 在使用Struts之前,咱們必先設置好JSP服務器,以便讓服務器在用戶請求時,知道該如何將指定后綴的請求轉到相應的Controller-Struts ActionServlet處理,當然,這些配置信息都一般在服務器啟動時通過web.xml文件讀入的。我們可以在web.xml定義多個Controlloer,為每一個應用定義一個。一個典型的web.xml文件配置如下,其中有相應的注釋,很好懂的,在后面討論Action的時候,我們將主要分析strutc-config.xml。
<web-app>
<servlet>
<!--
以下配置信息聲明了Struts中的ActionServlet,即一個名為OreillyAction的Servlet,其具體實現為org.apache.struts.action.ActionServlet。在這個配置中還有這個Servlet的兩個參數:debug level和detail,此處這兩個參數的值都設為了2,此外還設置了在啟動載入時創建兩個實例。
-->
<servlet-name>OreillyActionServlet</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>2</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<!--
設置所有后綴為.action的請求,都轉發到OreillyActionServlet
-->
<servlet-mapping>
<servlet-name> OreillyActionServlet </servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<!--
將初始請求頁面設置為login.jsp
-->
<welcome-file-list><welcome-file>login.jsp</welcome-file></welcome-file-list>
<!--
設置Struts的JSP頁面要用到的標簽庫和她們的路徑
-->
<taglib>
<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
</web-app>
控制器(Controller) Controller是這個框架中扮演“交通警察”的角色,當客戶端與服務器有交互動作時,都由她來控制。Controller將HTTP請求封包并轉發到框架中相應的對象,這些對象可能是一個JSP頁面或一個Action。
Controller在web.xml中設置為org.apache.struts.action.ActionServlet的一個實例,在本例中,這個實例就是OreillyActionServlet。在一個完整的控制過程中,也就是處理一個HTTP請求時,在控制過程之初,這個Servlet會從一個配置文件struts-config.xml中獲取請求與控制動作向對應的配置信息,這個我們會在后面詳細討論,Controller通過這些配置信息來決定HTTP請求該往何處轉發,而這些Action在接收到轉發來的請求后,實現真正的商業邏輯。我們要注意的非常重要的一點是Action對象要能夠調用這個ActionServlet的若干方法,通過這個有力的特性,當Action對象在控制過程中將請求再向別的Action對象轉發時(最初的請求是由ActionServlet獲取,向Action對象轉發,而Action對象還可以再轉發到別的對象),我們可以將一些需要共享的數據對象通過調用一些方法放入這個Servlet相關的一些標準容器中捎帶過去。
模型(Model) 所謂Model就是在對用戶請求的整個控制過程中,真正處理用戶請求并保存處理結果的對象,在整個過程中,我們一般利用JavaBean來把一些信息保存起來以便在各個對象之間傳遞。因為在框架中,Model對象是真正處理商業邏輯功能的對象,因此也就是框架中應用需求實現相關性最大的部分。在Struts的實現里,Model的具體表現形式就是ActionForm對象和與其對應的Action對象了。對用戶提交表單的數據進行校驗,甚至對數據進行預處理都能在ActionForm中完成。通常的應用中,一般是一個Model對象和一個請求頁面對應的關系,但也可以一個Model對象對應多個頁面請求。如果struts-config.xml配置文件沒有指定一個Model對象對應的Action,那么控制器將直接把(通過模型對象完成數據封裝的)請求轉到一個View對象。
struts-config.xml 前面多次提到的struts-config.xml配置文件是整個框架的主心骨。web.xml文件定義了一個請求到來應向何處轉發后,后面的工作就全權由struts-config.xml管理控制了??梢哉fstruts-config.xml就是整個Struts框架的“扛把子”(譯注3),只有這位“老大”清楚所有請求與動作的映射關系,要是他哪里沒有搞定或不爽的話,整個“社團”就什么也擺不平了:)如今的應用系統,XML形式的配置文件越來越多,如果整個系統只使用一個這樣的配置文件的話,那么保持整個系統的模塊化和可維護性都非常的輕松。使用配置文件來描述請求-動作的控制過程和相互關系,而不是在代碼中將對象之間的調用關系寫死,那么都應用系統有變動時,我們只用修改配置文件就行了,而不是再重新編譯發布程序了。
Controller通過struts-config.xml文件的配置信息確定當有請求時應該調用那個對象來處理,從效率的角度出發,這些信息都是在系統啟動時讀入并存在內存中的。下面我們將講解一個極短小的struts-config.xml文件,文件中定義了一個與登錄請求對應的登錄動作,請求到達后將被轉發到com.oreilly.ui.authentication.actions.LoginAction這個Action對象,該對象處理的結果決定向用戶返回的頁面。這個例子同時還示范了一個Action對象將請求轉發到別的Action對象,而例子中另一個返回的對象則是一個View對象,即我們看到的login.jsp頁面。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
"
http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd";>
<struts-config>
<!-- ========== Action 映射定義 =================== -->
<action-mappings>
<!-- <action> 屬性的說明 -->
<!-
type - 完整的Action實現類名
name - 該Action要用到的ActionForm名
path - 請求該Action的URI
validate - 如果本屬性為true則在Action動作之前其對應的ActionForm的validate方法會自動被調用,一般用以校驗用戶輸入的數據
-->
<!-- ~~~~~~~~~~~~~~~~~~~~~ -->
<!-- O'Reilly Main Actions -->
<!-- ~~~~~~~~~~~~~~~~~~~~~ -->
<action path="/Login"
type="com.oreilly.ui.authentication.actions.LoginAction">
<forward name="success" path="/DisplayMainPage.action"/>
<forward name="failure" path="/login.jsp"/>
</action>
</action-mappings>
</struts-config>
視圖(View) View對象通常來說都是指的JSP頁面。Struts框架實際上并沒有真正的JSP的要求規范,而是提供了大量的標簽庫來為開發者更簡便的將JSP整合到Struts框架中。在Struts中通過標簽定義方式的JSP頁面能夠將用戶通過表單輸入的數據存入一個JavaBean中,也就是我們前面提到的ActionForm bean。通過Action類調用(自動或手動)ActionForm的校驗方法來檢查用戶輸入的數據,如果發現不合法的數據,再通過Struts的一個通用機制將錯誤信息返回給用戶顯示。
Struts框架提供了若干個標簽庫,它們有各自不同的用途。由于這些庫還可以脫離Struts框架單獨使用,這樣我們也可以在其他系統中嘗試使用這些標簽庫,它們包括:
* struts-html - 這個標簽庫用來創建動態的HTML頁面和表單。
* struts-bean - 提供了類似甚至更強于<jsp:useBean>中的功能。
* struts-logic - 用于在頁面輸出文本信息時的條件、循環等流程的控制。
* struts-template - 用于產生有共同風格的動態JSP頁面模板。
此外,可定制標簽庫在Struts中還有一大用處是,通過資源文件的方式來實現應用系統的多語言特性,應用Struts的系統若想將系統中的用戶交互信息換一種語言的會很簡單,更換一個不同的資源文件就可以了。
大家都開始應用Struts吧! Struts框架可能對于大多數開發人員來說,是一門比較新的技術。但我們現在已經可以在不少的應用系統中看到Struts的身影了,而我們大可在新的應用或正在開發的JSP項目中使用Struts框架。
例如,在作者現在正在為客戶開發的一個大型數據庫應用系統中,商業邏輯都是通過EJB來實現的,用戶界面則是JSP頁面。在struts-config.xml文件中定義了用戶輸入表單和對應的Action類,當一個請求發生時,即用戶數據以ActionForm的形式封裝提交到Action時,Action先調用ActionForm的校驗方法,數據檢查校驗通過后,Action再調用相應的EJB中的方法來完成數據操作,操作的結果以XML的形式返回,XML解析后再放入我們數據的封裝傳遞JavaBean - ActionForm中顯示到JSP頁面里返回用戶。
整個的控制流程(包括Action調用后的不同的返回結果)都盡在struts-config.xml中所掌握,這種“中央集權”的方式非常便于應用流程的調整。而不管是Servlet還是JSP頁面中(甚至在一些n層的應用架構)都無需撰寫如何獲取顯示數據的代碼。
由于目前作者所開發的是一個較大型的系統,有很多的JSP頁面和用戶要提交的ActionForm類型,因此發現Struts的一個麻煩的地方,那就是:我們要為如此多頁面和ActionForm開發對應的Action類來完成控制,因為我們目前JSP和ActionForm與Action是一對一的關系。不過我認為如果在項目前期分析和設計時多下些功夫,做出更完美一些的設計方案的話,這樣的情況是可以避免的,當然,在新產品的開發過程中,想一步就把所有需求弄清楚明白那也是不可能的。我們不是都有這樣的經歷嗎?在開發中的應用系統正一步一步走向成熟的時候,更新和更明確的需求才會被提出來。不過,像我們手里這個利用Struts開發了六個月的系統也確實少見了,呵呵。除去這些非技術因素不談,Struts框架為我們實現MVC模式節省了大量的時間,并且開發出的系統相當的穩定,可以說是很成熟的產品了。
在本系列文章的第二部分,我們將把各小段代碼集成起來,完成一個完整的Struts應用的實例,希望大家繼續和作者一起學習Struts!
Sue Spielman是ONJava.com的副編輯,主要擅長于JSP和Servlet技術,她還是Switchback Software LLC公司的總裁和高級技術咨詢專家。
譯注1:雖然常見將Controller、Model和View這三個翻譯為對應的“控制器”、“模型”和“視圖”,但總感覺在表達上還是有欠本意,所以譯文中只在需要名詞定義的地方將三個中文詞匯寫上,文中其他的發還是保留E文“真身”。
譯注2:這是2001年9月11日(沒錯,就是“911”當天哦)發的文章啦,要知道文章里的“那時”也是現在的好久之前的時候了。
譯注3:原文中此處是用“Vito Corleone”來形容struts-config.xml的,知道唯托.科尼奧尼是誰嗎?呵呵,經典電影《教父I》和《教父II》里的教父啊,馬龍.白蘭度和羅伯特.德尼羅先后塑造的經典形象,所以wingc在這里也用了一點江湖詞匯,請勿見怪。
學習Jakarta Struts(第二篇)
本文是三篇學習Struts框架系列文章的第二篇(原文請見
http://www.onjava.com/pub/a/onjava/2001/10/31/struts2.html)。在本系列的的第一篇中,我們大致瀏覽了Struts框架,框架的功能以及框架中應用到的各個模塊。而本文,我將利用Struts 1.0為大家演示建立一個簡單的應用;在第三篇文章中將介紹如何利用Struts的標簽在JSP中訪問ApplicationResource文件中的信息。
我們在這篇文章將會一步一步的講解Struts的應用,以這樣的形式打開Struts一道道神秘的大門,通過這樣的過程,相信也能激起你在應用開發中如何應用Struts的靈感。如果你對Struts的一些術語不是很清楚的話,可以參考本系列前一篇對Struts作大體介紹的文章。
再次重復一遍,本文需要讀者有如下幾方面的知識和經驗:JSP,Servlets,自定義標簽庫(Custom Tag libraries)和XML。此外,在本文中,我還會用到Jakarta項目組其他一些好東東,比如Tomcat
http://jakarta.apache.org/tomcat/index.html(實現Java Servlet和JSP官方標準的Servlet容器,通俗的講就是一個JSP的Web Server啦)和Ant
http://jakarta.apache.org/ant/index.html(基于Java的自動編譯發布工具,這可是好東東?。?。
作為一名一直使用前沿技術開發了諸多應用的技術人員,我一直堅信掌握新技術,理解該技術開發的邏輯是至關重要的。但這往往就是陷住我們學習步伐的泥潭,正因如此,我打算將利用Struts開發的一套完整流程作為我們教學的案例。該流程的這個案例可謂“麻雀雖小、五臟據全”,你完全可以將這個流程應用到你手頭那些復雜龐大的項目中,至少在我們的大項目中應用這個流程效果不錯。
有開發復雜商業應用的開發人員都知道,客戶的需求總是在不停變幻,所以如果有一套規范的開發流程來遵循,當客戶提出新的需求時,我們至少可以明確哪些“無理”需求其實是合理可行的。好,接下里我將在我的這個例子中向各位展示和應用整個流程。
本文中的示例代碼是StrutsSample應用中的一部分,包括build.xml的完整代碼可以到此處
http://www.onjava.com/onjava/2001/10/31/examples/StrutsPartII.jar下載。
Struts開發過程 從Struts發布的版本號可以看出,Struts是個新玩意,她有好幾個部分組成,明智的你如果搞清楚了何時該開發完成合適的部分,那將會更好的利用我們的開發時間。從我所開發的幾個利用Struts應用中,我大致總結出如下這個比較有效的開發步驟:
1,明確應用需求;
2,由用戶輸入和獲取數據的角度出發,明確和設計出每一個用戶界面;
3,確定用戶界面的進入路徑;
4,由應用邏輯信息確定動作映射表(ActionMapping);
5,由設計完成的用戶界面開發其所用到的類和應用函數;
6,由用戶界面中的數據信息開發ActionForm和相應的數據校驗方法;
7,ActionMapping中將會被調用相應的Action或轉到相應的JSP頁面,這一步我們先開發這些Action;
8,開發商業應用邏輯,就是相應的JavaBean、EJB或其他東東;
9,開發由ActionMapping定義的系統工作流程完成對應的JSP頁面;
10,完成系統配置文件:struts-config.xml和web.xml;
11,編譯/測試/發布。
明確應用需求 開發任何應用系統的第一步就是收集用戶需求信息。不管一個用戶邏輯初看上去多么合理,但總有可能在開發時才發現它比看上去要難得多。所以,建議擬一份明確的用戶需求列表,這不只是出于開發的目的,還能通過該表分析用戶需求以確定哪些地方可能需要花更多的精力。
在我們這個StrutsSample項目中,應用需求就是:
作為一個展示Struts框架應用的完整例子,本示例完成的功能是用戶登錄。目的只為明確Struts的應用,本示例將不會涉及到一般復雜應用系統中可能應用的安全、數據庫、EJB開發等等相關技術。
設計用戶界面 這個應用中,包括如下三個用戶界面:
1)登錄界面,用于用戶名和密碼輸入;
2)當登錄用戶為合法用戶時的歡迎界面;
3)當登錄失敗時的錯誤提示界面。
確定用戶界面的進入路徑1)登錄界面作為這個應用的默認頁面;
2)歡迎界面只有當成功登錄后才能進入;
3)任何可能發生錯誤的頁面能可以進入錯誤提示界面;
由應用邏輯信息確定ActionMapping ActionMapping為整個應用確定的“線路圖”,在配置文件struts-config.xml對ActionMapping進行定義,通過轉發請求(forward)來理順應用的處理流程,確定應用中每個用戶請求對應的動作。
通常我們在開發過程中就逐步確定了ActionMapping所需的信息,開發代碼的過程就是在由草稿開始一步步完善struts-config.xml的過程。當Action類處理完用戶請求后,其返回的的forward就是在ActionMapping中定義的一個。一個Action返回的forward完全有多種可能,盡管一個Action一般只定義其相關的幾個forward。那么,如果有多個Action都可能返回的同一個forward,那么就可以將其定義為全局轉發(global forward)。這類似于C中的頭文件中全局變量,如果在struts-config.xml描述信息中,某一個forward并不是在當前Action描述中定義的而是全局定義的,那么這個全局的將起作用,同樣,一個Action中當前定義的forward將覆蓋全局定義。在我們所給的這個簡單實例中,我們定義了全局forward――“error”,當某Action返回的forward是“error”這個映射,那么Errorpage.jsp頁面將會顯示給用戶,盡管當前Action并沒有對其定義。
我們繼續不斷的開發,項目日漸完善,項目相關的配置文件也會越來越詳細。在下面的例子中,我們將以StrutsSample中用到的struts-confug.xml文件為例,學習global forward和一個Action中相關映射的定義。下面定義了一個名為“login”的Action,其為com.oreilly.actions.LoginAction的實例,當Action處理用戶登錄成功后將一個名為"success"的forward返回,用戶也就會看到Welcome.jsp頁面,如果登錄失敗,Action將返回對應的forward以再顯示Login.jsp給用戶,而如果處理過程中發生其他錯誤,Action將返回全局定義的forward――“error”,用戶也就會看到錯誤提示頁面Errorpage.jsp。
<!-- ========== Global Forward 定義 -->
<global-forwards>
<forward name="login" path="/Login.jsp"/>
<forward name="error" path="/Errorpage.jsp"/>
</global-forwards>
<!-- ========== Action Mapping 定義 -->
<action-mappings>
<!-- <action>元素的相關屬性 -->
<!--
以下只列出常用屬性,其他請參考org.apache.struts.action.ActionMapping的相關文檔
path - 當前Action對應的用戶請求URI路徑
type - 實現當前Action的Java class的完整名字
name - 當前Action中用到的ActionForm的名字,其具體信息在配置文件其他地方另有詳細定義
unknown - 如果將該屬性設置為true,那么就是聲明這個Action將處理整個應用中所有未找到相應處理Action的請求,當然,一個應用系統中也只會有一個Action的unknown屬性可以設為true
scope - Action中所用到的ActionForm的生存期,可以為“request”或“session”,隨著生存期的設置,該Action也會在相應的時間被創建
input - 該Action中相關ActionForm獲取用戶輸入的輸入頁面,當將ActionForm設為自動驗證輸入數據,發現不合法數據返回錯誤時,將返回該頁面
validate - 如果本屬性為true則在Action動作之前其對應的ActionForm的validate方法會自動被調用,一般用以驗證用戶輸入的數據
forward 元素 - 定義當前Action相關的ActionForward
-->
<!-- =================== -->
<!-- O'Reilly Struts Sample Main Actions -->
<!-- =================== -->
<action path="/login"
type="com.oreilly.actions.LoginAction"
name="loginForm"
scope="request"
input="/Login.jsp">
<forward name="success" path="/Welcome.jsp"/>
<forward name="failure" path="/Login.jsp"/>
</action>
</action-mappings>
在前一篇文章中,我們曾說過,struts-config.xml就是MVC模式的的Controller。在確定struts-config.xml中的配置信息時,應該多花些時間精力在上面,以保證每一個Action定義及其相關定義是符合應用的需求的。如果在項目開始沒有詳細的設計其定義,當將所有代碼和配置集成到一起的時候,我們將不可避免的將各部分的代碼和配置完全重新組織一遍。
我們當前的例子StrusSample因為只是處理用戶登錄,所以只需要一個Action。一個應用系統中所要用到的Action的多少完全依應用的大小而定。一旦整套Action的映射完全的定義出來后,我們就可以一個一個開發其具體實現的Action和ActionForm類,并逐漸將完成的部分一點一點集成起來。
由設計完成的用戶界面開發其所用到的類和應用函數 所有ActionForm的實現類都是org.apache.struts.ActionForm的子類。一個ActionForm是與頁面上的輸入表單相關聯的,而且ActionForm的實現還可以對用戶輸入數據的合法性進行驗證。作為一個Java Bean,ActionForm有Set和Get方法,當一個頁面中表單被提交時,系統將自動調用Set方法將數據放入ActionForm中,而Get方法將為在Action中操作這些數據所提供。一般來說,處理表單中的所有數據,并進行合法性驗證都完全可以交由ActionForm來完成。在應用中,就我個人而言,傾向于將ActionForm和Action劃分到不同的包中,因為當一個頁面中要用到幾對ActionFrom和Action時,都放在一個包內會混淆的。下面的代碼,就是實例中登錄頁面用到的ActionForm的代碼。
/*
* LoginForm.java
*/
package com.oreilly.forms;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
/**
* 驗證用戶要用到的兩個數據
*
* username - 登錄用戶名
* password - 用戶密碼
*
*/
public final class LoginForm extends ActionForm {
private String userName = null;
private String password = null;
/**
* userName的Get方法
* @return String
*/
public String getUserName() {
return (userName);
}
/**
* userName的Set方法
* @param userName
*/
public void setUserName(String newUserName) {
userName = newUserName;
}
/**
* password的Get方法
* @return String
*/
public String getPassword() {
return (password);
}
/**
* password的Set方法
* @param password
*/
public void setPassword(String newPassword) {
password = newPassword;
}
/**
* 重置所有數據
*
* @param mapping 當前的ActionMapping
* @param request 當前Server正在處理的HttpServletRequest
*/
public void reset(ActionMapping mapping, HttpServletRequest request) {
userName = null;
password = null;
}
/**
* 驗證當前HTTP請求提交上來的數據
* 如果數據驗證發現不合法數據,將返回一個封裝
* 所有驗證錯誤的ActionErrors對象
* 如果數據驗證通過,該方法返回null或者一個
* 沒有封裝任何驗證錯誤的ActionErrors對象
*
* @param mapping 當前的ActionMapping
* @param request 當前Server正在處理的HttpServletRequest
*/
public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
// 當前ActionForm中,只需要檢查用戶輸入的用戶名數據
if( userName == null || userName.length()==0 ){
errors.add("userName",new ActionError("error.userName.required"));
}
return (errors);
}
}
以上的代碼,只有兩點和一般的Java Bean有所不同。其一是reset方法,方法中設置的值將在表單被reset時反應到其對應的表單項上,即將表單項的數據恢復到默認值。其二是validate方法,是用來驗證用戶在表單中所輸入數據的方法。在當前這個例子中,我們只驗證用戶輸入的用戶名。因為一個用戶名其對應的密碼可能為空,所以我們的邏輯就是驗證時不去檢查密碼。驗證用戶名,當發現輸入的用戶名為空時,方法就會產生一個錯誤對象(ActionError)。
在Struts中用ActionErrors來裝載多個錯誤,從ActionErrors結尾的那個“s”就可以知道她是一個ActionError對象的集合。在驗證用戶輸入時,可以驗證完表單中所有數據后,再將可能發現的多個錯誤通過ActionErrors返回給用戶,這樣的邏輯應該是想當然的啦,不可能用戶有五個不同的輸入錯誤,卻要分五次提示,讓用戶修改提交五遍吧,呵呵。
同時,要知道在我們這個例子中,我們將錯誤信息提示給用戶是通過ApplicationResource.properties文件。這個文件在Tomcat啟動時通過web.xml中的定義為這個應用所使用。通常每一個應用都在其WEB-INF目錄下都有web.xml文件來描述系統,而關于部署應用時具體的結構信息,請參考Tomcat
http://jakarta.apache.org/tomcat/index.html等Server相關的用戶手冊。
ApplicationResource.properties文件中可以定義應用中所要用到的提示信息的字符串,字符串都通過一個鍵值來唯一確定其位置。在我們這個例子中,鍵值error.userName.required所對應的字符串信息是“A username is required”,在給用戶顯示錯誤信息時,也就通過鍵值確定的錯誤提示顯示該字符串。通過這樣的機制,為我們在系統中實現多語言提供了便利,將該文件中的這些字符串翻譯成相應的語言,我們的系統就可以實現西班牙語、德語、法語和漢語等等語言的版本了。
下面這些ApplicationResource.properties中的信息對于我們這個簡單的示例中已經夠用了:
login.title=Login Struts Sample
error.userName.required=A username is required
error.login.authenticate=Invalid username/password
errors.footer=</ul><hr>
errors.header=<h3><font color="red">Page
Validation</font></h3>Please correct the
following error(s) before contiuing:<ul>
applicationResources=Cannot load application resources bundle
{0}
頁面的標題,按鈕或其他什么需要文本提示的地方都可以通過這個文件來定義顯示用字符串。我們將在該系列的最后一篇文章,也就是后續幾個開發步驟中講解如何通過Struts的標簽從這個文件中獲取顯示用字符串。
學習Jakarta Struts(第三篇)
本文是三篇學習Struts框架系列文章的最后一篇(原文請見
http://www.onjava.com/pub/a/onjava/2001/11/14/jsp_servlets.html)。
在第一篇文章《Jakarta Struts簡介》中,我大致分析了Struts框架,討論了它所能完成的功能,還瀏覽了組成Struts的各個組成部分。在第二篇文章《學習Jakarta Struts》中,我開始詳細描述如何利用Struts來構建一個簡單應用的過程步驟。而本篇文章將會向大家演示如何將ApplicationResource文件中的文本信息,通過Struts標簽在JSP頁面中顯示出來。
Action類是連接Struts架構和應用中業務邏輯代碼的橋梁。所以你應該盡可能讓Action類小巧簡單,因為真實應用中的邏輯處理應該是由單獨分離出來的邏輯層來完成的。如果你正在從事n層應用的開發,你當然希望層與層之間的接口越簡單越好。而事實上,Action類中的主要方法"perform()"(1.1中為execute())卻有點暗示應該在本方法中做點什么的意思。我們知道,每個Action類都需要從 org.apache.struts.action.Action 繼承而來。在小型應用中,我們的Action類很可能就只要繼承org.apache.struts.action.Action就足夠了;而在某些特定的復雜應用中,我就從我們所實現的Action類中總結出來了一些通用特性。因此,在我看來,構造一個基類將這些通用特性的代碼實現出來,讓應用中所用到的所有Action類不直接繼承org.apache.struts.action.Action,而繼承這個完成了一些通用特性的基類以實現代碼重用,是一個相當不錯的設計。我在StrutsSample中就應用了這種方法,構造了這樣的一個基類,該基類的方法在完成復雜邏輯的和簡單轉發請求的Action類中都可以使用。
package com.oreilly.actions;
import java.io.IOException;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.MissingResourceException;
import java.util.Enumeration;
import java.util.Properties;
import java.rmi.RemoteException;
import javax.ejb.EJBHome;
import javax.ejb.CreateException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
這個類就是使用Struts開發時,所有Action類都要繼承的基類。它把一些通常在實際應用中最有可能被用到的東西都考慮進來了。就這篇文章而言, 類中一些與Struts并不是太緊密相關的方法將只做注釋而不會完整的實現,而從事開發工作的你,有興趣的話,請完成這些方法并應用這個類,將為你在實際項目中的開發快馬加鞭。注意,因為所有的Action類都要從org.apache.struts.action.Action 繼承而來,所以我們的這個類同樣。
public abstract class AbstStrutsActionBase extends Action {
/**
* 定義一些在struts-config.xml中記錄在案的
* 全局應用中皆可可通用的forward標識
*/
protected static final String SUCCESS = "success";
protected static final String FAILURE = "failure";
protected static final String ERROR = "error";
protected static final String LOGIN = "login";
protected static final String CONFIRM = "confirm";
protected Context jndiContext = null;
/**
* 默認構造方法
*/
public AbstStrutsActionBase() {
}
/**
下面這個查找EJB實例的方法將不會完整實現。
一般來說,Action類應該調用實現了應用的商務邏輯的EJB會話bean(或僅僅普通JavaBean)。在大型項目中,開發人員必須劃清層與層之間的界限。在Action類中,我們應該拿到獲取含有JNDI信息的環境的實例,然后通過EJB的JNDI名字去查詢獲取它的home接口。過程并不簡單,所以下面這個代碼片斷只是個給出了必要實現的小例子。
? 參數類型String,傳入的要查詢JNDI的名字
? 返回類型Object,即查找到的home接口
? 如果查找失敗,拋出NamingException異常
? 如果獲取資源信息失敗,拋出MissingResourceException異常
*/
public Object lookup(String jndiName)
throws NamingException, MissingResourceException {
// 為調用EJB對象,通過構建記錄JNDI信息的Properties對象
// 來獲得初始環境信息
if (jndiContext == null) {
ResourceBundle resource =
ResourceBundle.getBundle("strutssample.properties");
Properties properties = new Properties();
properties.setProperty(
Context.INITIAL_CONTEXT_FACTORY,
resource.getString(Context.INITIAL_CONTEXT_FACTORY));
properties.setProperty(
Context.PROVIDER_URL,
resource.getString(Context.PROVIDER_URL));
properties.setProperty(
Context.SECURITY_PRINCIPAL,
resource.getString(Context.SECURITY_PRINCIPAL));
properties.setProperty(
Context.SECURITY_CREDENTIALS,
resource.getString(Context.SECURITY_CREDENTIALS));
jndiContext = new InitialContext(properties);
}
注意:在真正的產品中,我們應該在此處考慮代碼的健壯性,將代碼加入到try/catch塊內,并記錄所有錯誤或重要信息到系統log中。而本例中,我們僅僅把異常往外拋,并假定一定會找到EJB對象的home接口并返回。
return (jndiContext.lookup(jndiName));
}
由于Action類將是由Struts來調用的。所以它的主要方法應該是一個抽象方法,而由每個繼承的子類來具體實現,或者在其中做一些所有Action都會做的通用機制,例如記錄log信息。在本例中,我們一切從簡,將其抽象之。
? 參數mapping:其類型為ActionMapping,將在本Action做跳轉選擇用
? 參數actionForm:由Struts根據本次HTTP請求數據填充完成的ActionForm對象(可選,如果存在請求數據的話)
? 參數request:此Action所有處理的本次HTTP請求(對象)
? 參數response:此Action輸出數據所要用到的HTTP響應(對象)
? 如果有I/O錯誤出現,則本方法拋出IOException異常
? 如果處理時發生servlet異常,則本方法拋出ServletException異常
? 本方法處理完請求后按照處理邏輯返回相應的頁面導向(對象)
public abstract ActionForward perform(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException;
}
或者讓這個抽象方法更有用一點,那就在里面干點什么吧,比如像下面這樣在其中記錄log。
{
ActionForward forward = null;
// 只是簡單的記錄一些提示信息到servlet log
getServlet().log(
"AbstStrutsActionBase.perform() [Action Class: "
+ this.getClass().getName()
+ " ]");
getServlet().log(
"AbstStrutsActionBase.perform() [Form Class : "
+ (form == null ? "null" : form.getClass().getName())
+ " ]");
}
然后,我們再編寫的每個Action類都應該從AbstStrutsActionBase繼承,并依照處理邏輯編寫各自的perform方法。讓我們用LoginAction為例,看看具體應該怎么應用吧。
package com.oreilly.actions;
import java.io.IOException;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForward;
import com.oreilly.forms.LoginForm;
/*
LoginAction 將演示一個Action將如何被Struts架構所調用
在這個例子中,我們只是簡單的演示perform方法是如何調用、執行并返回的
*/
public class LoginAction extends AbstStrutsActionBase {
接下來這個是驗證用戶的方法,本例中沒有具體實現。但一個典型的應用方案是調用JavaBean或者EJB來完成。用來查找EJB的lookup方法(在基類中完成的)應該在本方法中被調用,其返回一個依據后臺數據庫驗證用戶的接口。
? 參數類型String,要驗證的用戶名
? 參數類型String,密碼
? 返回類型boolean,如果驗證通過為true,否則為false
public boolean authenticate(String username, String password) {
/* 本方法將先做一個查找動作,獲得驗證用戶的EJB對象的接口并調用
* 由于本例只演示Action與商務邏輯層是如何交互的
* 所以具體實現代碼本例中就不提供了:)
*/
return (true);
}
接下來我們在LoginAction中重載基類的perform方法。
? 參數mapping:其類型為ActionMapping,將在本Action做跳轉選擇用
? 參數actionForm:由Struts根據本次HTTP請求數據填充完成的ActionForm對象(可選,如果存在請求數據的話)
? 參數request:此Action所有處理的本次HTTP請求(對象)
? 參數response:此Action輸出數據所要用到的HTTP響應(對象)
? 如果有I/O錯誤出現,則本方法拋出IOException異常
? 如果處理時發生servlet異常,則本方法拋出ServletException異常
? 本方法處理完請求后按照處理邏輯返回相應的頁面導向(對象)
public ActionForward perform(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// 先假定驗證失敗,那么要導向的forward當然是LOGIN了(見基類定義的全局變量)
boolean validLogin = false;
ActionForward actionForward = mapping.findForward(LOGIN);
// 構造出承載ActionError對象的容器——errors,以備錯誤出現時可用
ActionErrors errors = new ActionErrors();
// 從由本次請求構造的ActionForm中提取出所需要的數據
LoginForm loginForm = (LoginForm)form;
String userName = null;
String password = null;
if (loginForm != null) {
userName = loginForm.getUserName();
password = loginForm.getPassword();
validLogin = authenticate(userName, password);
}
if (validLogin) {
// 驗證成功了,導向到struts-config.xml中定義的SUCCESS
actionForward = mapping.findForward(SUCCESS);
// 存點必要的東東到session,以備后用
request.getSession(true).setAttribute("USERNAME", userName);
} else {
errors.add("login", new ActionError("error.login.authenticate"));
}
// 系統如果用戶界面友好一點,我們就應該將錯誤信息存入request對象中
// 然后到頁面,通過在Struts的標簽顯示出來
if (!errors.empty()) {
saveErrors(request, errors);
}
// 本Action處理完成,導向到合適的forward
return (actionForward);
}
}
注意,這個LoginAction類就是在struts-config.xml中定義的用來處理登錄事務的一個具體實現。當這個類被載入并有一個對象實例化后,Struts架構就會調用它的perform方法。這個方法是這樣聲明的:
public ActionForward perform(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
其中,mapping是一個記錄與此Action對應的forward導向的對象,form對象封裝由客戶端提交的此Action要處理的數據,還有標準的HttpServletRequest對象和HttpServletResponse對象。
有了這些對象的輔助,此Action就可以拿到需要的東東順利開工了。我們的例子中,要處理的數據主要是用戶名和密碼,這些都由form對象提供。實現驗證功能是本應用的主要業務邏輯,在方法中的具體實現應該是去取EJB的相應接口來操作或者直接去拿數據庫數據來驗證。前面那個AbstStrutsActionBase類中已經實現了一個簡單的EJB接口查找動作,所以如果我們是在開發一個基于EJB實現的系統,它的可重用性就非常強了。
由驗證方法(authenticate())的返回值,Action要接著做出合理的動作。如果驗證通過,就要讓用戶進入正確的頁面,那么我們就將一些后面可能會用到的信息存入request對象(譯注:準確的講,代碼中是存到了session對象里,當然session對象是和當前request相關的),并向Struts返回success這個forward。這個forward是在struts-config.xml中定義的,然后由ActionMapping封裝起來,在Action處理中可以從中拿出合適的forward做為返回值。如果回頭去看看struts-config.xml中的定義,就會知道success這個forward會將用戶導向至Welcome.jsp這個頁面的。如果驗證失敗,則將一個錯誤信息存起來,然后導向到一個錯誤提示頁面顯示出來。
開發應用的業務邏輯
在一個真實的應用系統中,我們應該將業務邏輯層整合進來了。在我們這個例子里,我們就應該去開發LoginAction中的authenticae方法所調用到的EJB了。但是正如你所見的,我們完全可以把這一層暫時屏蔽掉,而利用Struts把前端部分構建并能夠讓它跑起來的。我其實相當推崇的是方法是先將應用框架搭建并運行起來,然后在開發后臺實際的業務邏輯層。在應用框架完全恰當的構建起來的時候,后臺的開發工作所有做的debug工作也少的多了。而且,業務邏輯的開發也不是本文所要函概的范圍,所以此處我們略過,不過我相信你現在一定對應用的全局有了總體的把握了吧!
開發由ActionMapping定義的系統工作流程,完成對應的JSP頁面
終于可以將所有這些東東整合在一起了。在struts-config.xml配置文件中定義的那些ActionMapping,我們要完成這些ActionMapping定義用到的JSP頁面。本例中,包括Login.jsp、Welcome.jsp和Errorpage.jsp。還有,盡管我們在本例中都是將Action處理完成forward到JSP頁面,這在這個簡單的例子中是再恰當不過的邏輯流程了,而在實際利用Struts開發應用中呢,當然可以從Action forward到其他的Action。我們這個簡單的Login.jsp頁面內容是這樣的:
<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-form.tld" prefix="form" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html>
<head>
<title><bean:message key="login.title"/></title>
</head>
<body>
<html:errors/>
<h3>Enter your username and password to login:</h3>
<html:form action="login.action" focus="userName" >
<html:text property="userName" size="30" maxlength="30"/>
<html:password property="password" size="16" maxlength="16" redisplay="false"/>
<html:submit property="submit" value="Submit"/>
<html:reset/>
</html:form>
</body>
</html>
Struts在JSP自定義標簽庫的基礎上提供了一套綜合各種功能的標簽庫。利用這些標簽庫很容易的構建用戶界面了。使用這些標簽庫的好處之一就是可以利用其提供的很多附加功能。比如在一般的JSP頁面的表單里我們可以看到這樣常見的HTML片斷:
<input type="text" name="userName" value="">
如果我們使用Struts的標簽庫的話,就可以改成這樣子:
<html:text property ="userName">
不過我們得現在頁面中先聲明Struts標簽庫的定義。
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
在這個例子中,我們會用到一些Struts標簽,但我不準備在此詳細講解Struts各種標簽庫的用法。相信在你不斷使用Struts搭建功能復雜的JSP頁面的過程中,你將會對所使用過的標簽越來越熟悉的。到那時,你也將更能體會到Struts標簽的益處,利用它們大大的縮短你的開發時間。目前,你可以從Struts Developers Guides了解到更多的細節。
在我們這個簡單例子中,有兩個重點。其一:
<title><bean:message key="login.title"/></title>
這就是在利用我們前面提到的資源文件ApplicationResource來在頁面顯示信息,而不是將信息文本硬編碼到我們的應用中。
其二:
<html:errors/>
這就是在頁面中顯示出ActionErrors的信息,也就是我們在LoginForm的驗證方法和LoginAction中產生的報錯信息的集合對象。
頁面中的表單,利用Struts,我們將用如下的標簽來定義:
<html:form action="login.action" focus="userName">
這里的login.action,是和struts-config.xml中定義ActionMapping相匹配的。在頁面標簽中這樣的定義,就將相關的Action、ActionForm和ActionForward完整的串了起來。當這個用標簽定義的表單提交的時候,Struts中的ActionServlet就會將其交由login.action來處理。具體的過程我們下面慢慢深入。
在Welcome.jsp中,我們只演示如何將Action中的信息傳遞到頁面加以利用的一般機制:
<html>
<title>Welcome to Struts</title>
<body>
<p>Welcome <%= (String)request.getSession().getAttribute("USERNAME") %></p>
</p>You have logged in successfully!</p>
</body>
</html>
還記得嗎?我們在LoginAction中的perform()方法中將USERNAME放到了session中哦。
完成系統配置文件
我們已經就struts-config.xml談了好多了。通常,這個文件中的信息會在開發過程中逐漸完善。但是到了開發過程的最后一部,我們更應該回頭去檢查這個至關重要的配置文件,以保證萬無一失:Action、JSP頁面還有ActionForm都應該在文件中正確的定義。此外,我們還不得不說到web.xml。這個文件是JSP容器(例如Tomcat)獲取應用相關配置的重要文件。我們這個StrutsSample例子所用到的web.xml大致是這樣的:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
This is the web-app configuration that allow the strutsSample to work under
Apache Tomcat.
-->
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"
http://java.sun.com/j2ee/dtds/web-app_2_2.dtd";>
<web-app>
<servlet>
<servlet-name>oreilly</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>application</param-name>
<param-value>com.oreilly.ApplicationResources</param-value>
</init-param>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>validate</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>oreilly</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>Login.jsp</welcome-file>
</welcome-file-list>
<!-- Struts Tag Library Descriptors -->
<taglib>
<taglib-uri>/WEB-INF/struts.tld</taglib-uri>
<taglib-location>/WEB-INF/struts.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-form.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-form.tld</taglib-location>
</taglib>
</web-app>
這里的<servlet>標簽定義了org.apache.struts.action.ActionServlet,而且在本例中,我們把這個定義的servlet叫作“oreilly”,并傳了兩個初始化參數給它:其一是我們為這個應用所需的顯示字符串定義的資源文件,其二是指明struts-config.xml文件的位置。相信你也注意到了,在<servlet-mapping>中為這個Servlet指明的相應請求處理串是*.action,這是和我們在頁面中的表單定義的提交的URL是吻合的。也就是說,我們通過<servlet-mapping>標簽告訴Tomcat,所有后綴為.action的請求都交給“oreilly”這個Servlet來處理。你當然可以指定你喜歡的后綴。在Struts附帶的例子中,你可能會看到通常以.do做為后綴,不過我認為.action更明確一些。<welcome-file-list>標簽中定義了本應用初始顯示頁面。最后呢,我們還要把會用到的Struts標簽庫列在后面。
編譯/測試/發布
到此為止,編譯/測試/發布應用之前的所有工作都完成了。用Ant來編譯整個應用是相當容易的。如果你以前沒有接觸過Ant,那最好把這個研究一下。其實學習和應用Ant來管理一個應用編譯環境并不難。我把這個編譯應用所要用到的build.xml和例子放到了一起,這篇文章所要用到的所有東東,你都可以點此下載,到時候你到build.xml所在目錄簡單執行ant命令就可以完成編譯,并打包成strutsSample.war包。當然要執行ant,你得先去下載Ant。將Ant下載回來并搭建好環境可能得花十幾分鐘的時間哦。
本應用的目錄結構如下:
StrutsSample根目錄
*.jsp
WEB-INF目錄
Struts配置文件(struts-config.xml, web.xml)
classes目錄(還是以Java程序文件包結構為路徑)
lib目錄(struts.jar)
拿到了應用的war包,我們就將它放到Tomcat的webapps路徑下,然后啟動Tomcat。war包會被自動展開,此應用的上下文環境也會由Tomcat自動建立起來。我們通過web.xml告知Tomcat這個應用所需的其他資源在哪里。現在,我們可以通過
http://localhost:8080/strutsSample來訪問我們的應用了。如果沒有特別指定的話,Tomcat默認的端口是8080,我們定義的默認初始頁面Login.jsp也將顯示出來,現在我們來試試吧。
結論
通過本系列的文章,我們利用Struts從應用需求開始,一步步將整個應用搭建起來。和普通的JSP技術相比,通過Struts開發的應用涉及到更多的與之相關的各類文件,也正是依靠各類文件,我們才可能構建一個適合開發復雜應用的MVC架構。我們的第一個Struts應用花了如此多的時間,是為了要弄清楚Struts的各個部分到底是如何工作的。
希望本系列Struts文章,能夠幫助你了解Struts是由哪些部分構成的,它們能夠完成什么,也希望介紹一個比較好的開發流程可供你參考。Struts才誕生不久,我有信心它將成為我們構建J2EE應用的優秀工具。