本文將介紹如何利用Struts進(jìn)行應(yīng)用開(kāi)發(fā)的前臺(tái)整合的開(kāi)發(fā)過(guò)程。Struts是一個(gè)為開(kāi)發(fā)基于模型(Model)-視圖(View)-控制器(Controller)(MVC)模式應(yīng)用架構(gòu)的開(kāi)源框架,是利用Java Servlet和JSP構(gòu)建Web應(yīng)用的一項(xiàng)非常有用的技術(shù)。
閱讀本文需要讀者具有以下幾方面的開(kāi)發(fā)經(jīng)驗(yàn):JSP、Servlet、自定義標(biāo)簽庫(kù)(custom tag library)和XML。如果讀者想補(bǔ)一補(bǔ)自定義標(biāo)簽庫(kù)的知識(shí),可以參考作者以前關(guān)于這方面的文章。而本文也是關(guān)于介紹如何使用Struts系列文章的上半部分,本系列暫定分為上下兩部分。
新手上路注意事項(xiàng)
Struts是一個(gè)基于Sun J2EE平臺(tái)的MVC框架,主要是采用Servlet和JSP技術(shù)來(lái)實(shí)現(xiàn)的。其最初萌芽于Craig McClanahan的構(gòu)思,誕生至今也一年有余了?,F(xiàn)在,Struts是Apache軟件基金會(huì)旗下Jakarta項(xiàng)目組的一部分,其官方網(wǎng)站是http://jakarta.apache.org/struts。由于Struts能充分滿足應(yīng)用開(kāi)發(fā)的需求,簡(jiǎn)單易用,敏捷迅速,在過(guò)去的一年中頗受關(guān)注。Struts把Servlet、JSP、自定義標(biāo)簽和信息資源(message resources)整合到一個(gè)統(tǒng)一的框架中,開(kāi)發(fā)人員利用其進(jìn)行開(kāi)發(fā)時(shí)不用再自己編碼實(shí)現(xiàn)全套MVC模式,極大的節(jié)省了時(shí)間,所以說(shuō)Struts是一個(gè)非常不錯(cuò)的應(yīng)用框架。
目前的Struts 1.0修正版包括完整的文檔,既可以說(shuō)是用戶文檔又是開(kāi)發(fā)指導(dǎo)文檔。如果讀者是JSP新手,或者對(duì)MVC設(shè)計(jì)模式不是太熟的話,可能剛上路時(shí)會(huì)比較慢,不過(guò)不用擔(dān)心,要相信自己會(huì)盡快趕上的:)
此外,應(yīng)該注意到盡管當(dāng)前Struts只是1.0版,但已經(jīng)相當(dāng)穩(wěn)定了,作者從Struts 0.9版就在一個(gè)大規(guī)模的項(xiàng)目中應(yīng)用了(最近升級(jí)到1.0版),至今還沒(méi)有遇到什么麻煩問(wèn)題。實(shí)際上,Struts在這個(gè)要開(kāi)發(fā)復(fù)雜用戶界面的項(xiàng)目中,為我們團(tuán)隊(duì)大大的縮短了開(kāi)發(fā)時(shí)間,在此衷心的感謝Struts項(xiàng)目團(tuán)隊(duì)的所有開(kāi)發(fā)人員。
開(kāi)始上路!
Struts框架可分為以下四個(gè)主要部分,其中三個(gè)就和MVC模式緊密相關(guān):
1、模型(Model),本質(zhì)上來(lái)說(shuō)在Struts中Model是一個(gè)Action類(lèi)(這個(gè)會(huì)在后面詳細(xì)討論),開(kāi)發(fā)者通過(guò)其實(shí)現(xiàn)商業(yè)邏輯,同時(shí)用戶請(qǐng)求通過(guò)控制器(Controller)向Action的轉(zhuǎn)發(fā)過(guò)程是基于由struts-config.xml文件描述的配置信息的。
2、視圖(View),View是由與控制器Servlet配合工作的一整套JSP定制標(biāo)簽庫(kù)構(gòu)成,利用她們我們可以快速建立應(yīng)用系統(tǒng)的界面。
3、控制器(Controller),本質(zhì)上是一個(gè)Servlet,將客戶端請(qǐng)求轉(zhuǎn)發(fā)到相應(yīng)的Action類(lèi)。
4、一堆用來(lái)做XML文件解析的工具包,Struts是用XML來(lái)描述如何自動(dòng)產(chǎn)生一些JavaBean的屬性的,此外Struts還利用XML來(lái)描述在國(guó)際化應(yīng)用中的用戶提示信息的(這樣一來(lái)就實(shí)現(xiàn)了應(yīng)用系統(tǒng)的多語(yǔ)言支持)。
好,下一步咱們來(lái)看看構(gòu)成這個(gè)框架的各個(gè)部分以及相互之間是怎樣運(yùn)作的吧!
配置
使用Struts之前,咱們必先設(shè)置好JSP服務(wù)器,以便讓服務(wù)器在用戶請(qǐng)求時(shí),知道該如何將指定后綴的請(qǐng)求轉(zhuǎn)到相應(yīng)的Controller-Struts ActionServlet處理,當(dāng)然,這些配置信息都一般在服務(wù)器啟動(dòng)時(shí)通過(guò)web.xml文件讀入的。我們可以在web.xml定義多個(gè)Controlloer,為每一個(gè)應(yīng)用定義一個(gè)。一個(gè)典型的web.xml文件配置如下,其中有相應(yīng)的注釋?zhuān)芎枚模诤竺嬗懻揂ction的時(shí)候,我們將主要分析strutc-config.xml。
(未完)
控制器(Controller)
Controller是這個(gè)框架中扮演“交通警察”的角色,當(dāng)客戶端與服務(wù)器有交互動(dòng)作時(shí),都由她來(lái)控制。Controller將HTTP請(qǐng)求封包并轉(zhuǎn)發(fā)到框架中相應(yīng)的對(duì)象,這些對(duì)象可能是一個(gè)JSP頁(yè)面或一個(gè)Action。
Controller在web.xml中設(shè)置為org.apache.struts.action.ActionServlet的一個(gè)實(shí)例,在本例中,這個(gè)實(shí)例就是OreillyActionServlet。在一個(gè)完整的控制過(guò)程中,也就是處理一個(gè)HTTP請(qǐng)求時(shí),在控制過(guò)程之初,這個(gè)Servlet會(huì)從一個(gè)配置文件struts-config.xml中獲取請(qǐng)求與控制動(dòng)作向?qū)?yīng)的配置信息,這個(gè)我們會(huì)在后面詳細(xì)討論,Controller通過(guò)這些配置信息來(lái)決定HTTP請(qǐng)求該往何處轉(zhuǎn)發(fā),而這些Action在接收到轉(zhuǎn)發(fā)來(lái)的請(qǐng)求后,實(shí)現(xiàn)真正的商業(yè)邏輯。我們要注意的非常重要的一點(diǎn)是Action對(duì)象要能夠調(diào)用這個(gè)ActionServlet的若干方法,通過(guò)這個(gè)有力的特性,當(dāng)Action對(duì)象在控制過(guò)程中將請(qǐng)求再向別的Action對(duì)象轉(zhuǎn)發(fā)時(shí)(最初的請(qǐng)求是由ActionServlet獲取,向Action對(duì)象轉(zhuǎn)發(fā),而Action對(duì)象還可以再轉(zhuǎn)發(fā)到別的對(duì)象),我們可以將一些需要共享的數(shù)據(jù)對(duì)象通過(guò)調(diào)用一些方法放入這個(gè)Servlet相關(guān)的一些標(biāo)準(zhǔn)容器中捎帶過(guò)去。
模型(Model)
所謂Model就是在對(duì)用戶請(qǐng)求的整個(gè)控制過(guò)程中,真正處理用戶請(qǐng)求并保存處理結(jié)果的對(duì)象,在整個(gè)過(guò)程中,我們一般利用JavaBean來(lái)把一些信息保存起來(lái)以便在各個(gè)對(duì)象之間傳遞。因?yàn)樵诳蚣苤?,Model對(duì)象是真正處理商業(yè)邏輯功能的對(duì)象,因此也就是框架中應(yīng)用需求實(shí)現(xiàn)相關(guān)性最大的部分。在Struts的實(shí)現(xiàn)里,Model的具體表現(xiàn)形式就是ActionForm對(duì)象和與其對(duì)應(yīng)的Action對(duì)象了。對(duì)用戶提交表單的數(shù)據(jù)進(jìn)行校驗(yàn),甚至對(duì)數(shù)據(jù)進(jìn)行預(yù)處理都能在ActionForm中完成。通常的應(yīng)用中,一般是一個(gè)Model對(duì)象和一個(gè)請(qǐng)求頁(yè)面對(duì)應(yīng)的關(guān)系,但也可以一個(gè)Model對(duì)象對(duì)應(yīng)多個(gè)頁(yè)面請(qǐng)求。如果struts-config.xml配置文件沒(méi)有指定一個(gè)Model對(duì)象對(duì)應(yīng)的Action,那么控制器將直接把(通過(guò)Model對(duì)象完成數(shù)據(jù)封裝的)請(qǐng)求轉(zhuǎn)到一個(gè)View對(duì)象。
struts-config.xml
前面多次提到的struts-config.xml配置文件是整個(gè)框架的主心骨。web.xml文件定義了一個(gè)請(qǐng)求到來(lái)應(yīng)向何處轉(zhuǎn)發(fā)后,后面的工作就全權(quán)由struts-config.xml管理控制了??梢哉f(shuō)struts-config.xml就是整個(gè)Struts框架的“扛把子”,只有這位“老大”清楚所有請(qǐng)求與動(dòng)作的映射關(guān)系,要是他哪里沒(méi)有搞定或不爽的話,整個(gè)“社團(tuán)”就什么也擺不平了:)如今的應(yīng)用系統(tǒng),XML形式的配置文件越來(lái)越多,如果整個(gè)系統(tǒng)只使用一個(gè)這樣的配置文件的話,那么保持整個(gè)系統(tǒng)的模塊化和可維護(hù)性都非常的輕松。使用配置文件來(lái)描述請(qǐng)求-動(dòng)作的控制過(guò)程和相互關(guān)系,而不是在代碼中將對(duì)象之間的調(diào)用關(guān)系寫(xiě)死,那么都應(yīng)用系統(tǒng)有變動(dòng)時(shí),我們只用修改配置文件就行了,而不是再重新編譯發(fā)布程序了。
Controller通過(guò)struts-config.xml文件的配置信息確定當(dāng)有請(qǐng)求時(shí)應(yīng)該調(diào)用那個(gè)對(duì)象來(lái)處理,從效率的角度出發(fā),這些信息都是在系統(tǒng)啟動(dòng)時(shí)讀入并存在內(nèi)存中的。下面我們將講解一個(gè)極短小的struts-config.xml文件,文件中定義了一個(gè)與登錄請(qǐng)求對(duì)應(yīng)的登錄動(dòng)作,請(qǐng)求到達(dá)后將被轉(zhuǎn)發(fā)到com.oreilly.ui.authentication.actions.LoginAction這個(gè)Action對(duì)象,該對(duì)象處理的結(jié)果決定向用戶返回的頁(yè)面。這個(gè)例子同時(shí)還示范了一個(gè)Action對(duì)象將請(qǐng)求轉(zhuǎn)發(fā)到別的Action對(duì)象,而例子中另一個(gè)返回的對(duì)象則是一個(gè)View對(duì)象,即我們看到的login.jsp頁(yè)面。
"-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd";>
type - 完整的Action實(shí)現(xiàn)類(lèi)名
name - 該Action要用到的ActionForm名
path - 請(qǐng)求該Action的URI
unknown – 如果將該屬性設(shè)置為true,那么就是聲明這個(gè)Action將處理整個(gè)應(yīng)用中
所有未找到相應(yīng)處理Action的請(qǐng)求,當(dāng)然,一個(gè)應(yīng)用系統(tǒng)中也只會(huì)有一個(gè)Action
的unknown屬性可以設(shè)為true了
validate - 如果本屬性為true則在Action動(dòng)作之前其對(duì)應(yīng)的ActionForm
的validate方法會(huì)自動(dòng)被調(diào)用,一般用以校驗(yàn)用戶輸入的數(shù)據(jù)
-->
type="com.oreilly.ui.authentication.actions.LoginAction">
視圖(View)
View對(duì)象通常來(lái)說(shuō)都是指的JSP頁(yè)面。Struts框架實(shí)際上并沒(méi)有真正的JSP的要求規(guī)范,而是提供了大量的標(biāo)簽庫(kù)來(lái)為開(kāi)發(fā)者更簡(jiǎn)便的將JSP整合到Struts框架中。在Struts中通過(guò)標(biāo)簽定義方式的JSP頁(yè)面能夠?qū)⒂脩敉ㄟ^(guò)表單輸入的數(shù)據(jù)存入一個(gè)JavaBean中,也就是我們前面提到的ActionForm bean。通過(guò)Action類(lèi)調(diào)用(自動(dòng)或手動(dòng))ActionForm的校驗(yàn)方法來(lái)檢查用戶輸入的數(shù)據(jù),如果發(fā)現(xiàn)不合法的數(shù)據(jù),再通過(guò)Struts的一個(gè)通用機(jī)制將錯(cuò)誤信息返回給用戶顯示。
Struts框架提供了若干個(gè)標(biāo)簽庫(kù),它們有各自不同的用途。由于這些庫(kù)還可以脫離Struts框架單獨(dú)使用,這樣我們也可以在其他系統(tǒng)中嘗試使用這些標(biāo)簽庫(kù),它們包括:
* struts-html - 這個(gè)標(biāo)簽庫(kù)用來(lái)創(chuàng)建動(dòng)態(tài)的HTML頁(yè)面和表單?! ?
* struts-bean - 提供了類(lèi)似甚至更強(qiáng)于中的功能。
* struts-logic - 用于在頁(yè)面輸出文本信息時(shí)的條件、循環(huán)等流程的控制。
* struts-template - 用于產(chǎn)生有共同風(fēng)格的動(dòng)態(tài)JSP頁(yè)面模板。
此外,可定制標(biāo)簽庫(kù)在Struts中還有一大用處是,通過(guò)資源文件的方式來(lái)實(shí)現(xiàn)應(yīng)用系統(tǒng)的多語(yǔ)言特性,應(yīng)用Struts的系統(tǒng)若想將系統(tǒng)中的用戶交互信息換一種語(yǔ)言的會(huì)很簡(jiǎn)單,更換一個(gè)不同的資源文件就可以了。
大家都開(kāi)始應(yīng)用Struts吧!
Struts框架可能對(duì)于大多數(shù)開(kāi)發(fā)人員來(lái)說(shuō),是一門(mén)比較新的技術(shù)。但我們現(xiàn)在已經(jīng)可以在不少的應(yīng)用系統(tǒng)中看到Struts的身影了,而我們大可在新的應(yīng)用或正在開(kāi)發(fā)的JSP項(xiàng)目中使用Struts框架。
例如,在作者現(xiàn)在正在為客戶開(kāi)發(fā)的一個(gè)大型數(shù)據(jù)庫(kù)應(yīng)用系統(tǒng)中,商業(yè)邏輯都是通過(guò)EJB來(lái)實(shí)現(xiàn)的,用戶界面則是JSP頁(yè)面。在struts-config.xml文件中定義了用戶輸入表單和對(duì)應(yīng)的Action類(lèi),當(dāng)一個(gè)請(qǐng)求發(fā)生時(shí),即用戶數(shù)據(jù)以ActionForm的形式封裝提交到Action時(shí),Action先調(diào)用ActionForm的校驗(yàn)方法,數(shù)據(jù)檢查校驗(yàn)通過(guò)后,Action再調(diào)用相應(yīng)的EJB中的方法來(lái)完成數(shù)據(jù)操作,操作的結(jié)果以XML的形式返回,XML解析后再放入我們數(shù)據(jù)的封裝傳遞JavaBean - ActionForm中顯示到JSP頁(yè)面里返回用戶。
整個(gè)的控制流程(包括Action調(diào)用后的不同的返回結(jié)果)都盡在struts-config.xml中所掌握,這種“中央集權(quán)”的方式非常便于應(yīng)用流程的調(diào)整。而不管是Servlet還是JSP頁(yè)面中(甚至在一些n層的應(yīng)用架構(gòu))都無(wú)需撰寫(xiě)如何獲取顯示數(shù)據(jù)的代碼。
由于目前作者所開(kāi)發(fā)的是一個(gè)較大型的系統(tǒng),有很多的JSP頁(yè)面和用戶要提交的ActionForm類(lèi)型,因此發(fā)現(xiàn)Struts的一個(gè)麻煩的地方,那就是:我們要為如此多頁(yè)面和ActionForm開(kāi)發(fā)對(duì)應(yīng)的Action類(lèi)來(lái)完成控制,因?yàn)槲覀兡壳癑SP和ActionForm與Action是一對(duì)一的關(guān)系。不過(guò)我認(rèn)為如果在項(xiàng)目前期分析和設(shè)計(jì)時(shí)多下些功夫,做出更完美一些的設(shè)計(jì)方案的話,這樣的情況是可以避免的,當(dāng)然,在新產(chǎn)品的開(kāi)發(fā)過(guò)程中,想一步就把所有需求弄清楚明白那也是不可能的。我們不是都有這樣的經(jīng)歷嗎?在開(kāi)發(fā)中的應(yīng)用系統(tǒng)正一步一步走向成熟的時(shí)候,更新和更明確的需求才會(huì)被提出來(lái)。不過(guò),像我們手里這個(gè)利用Struts開(kāi)發(fā)了六個(gè)月的系統(tǒng)也確實(shí)少見(jiàn)了,呵呵。除去這些非技術(shù)因素不談,Struts框架為我們實(shí)現(xiàn)MVC模式節(jié)省了大量的時(shí)間,并且開(kāi)發(fā)出的系統(tǒng)相當(dāng)?shù)姆€(wěn)定,可以說(shuō)是很成熟的產(chǎn)品了。
在本系列文章的第二部分,我們將把各小段代碼集成起來(lái),完成一個(gè)完整的Struts應(yīng)用的實(shí)例,希望大家繼續(xù)和作者一起學(xué)習(xí)Struts!
注:Sue Spielman是ONJava.com的副編輯,主要擅長(zhǎng)于JSP和Servlet技術(shù),她還是Switchback Software LLC公司的總裁和高級(jí)技術(shù)咨詢專(zhuān)家。
(完)