国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
STRUTS 2 概述(節(jié)選)

引 言

1、MVC思想概述

1.1  Web應(yīng)用的發(fā)展

1.2  Model 1Model 2

1.3  MVC思想

1.4  MVC模式的優(yōu)勢(shì)

1.5  常用MVC框架及其特征

2、Struts 2的起源和背景

2.1  Struts 1的基本結(jié)構(gòu)及其存在的問題

2.2  WebWork的基本結(jié)構(gòu)

2.3  Struts 2的起源

3Struts 2體系介紹.

   3.1  Struts 2的框架架構(gòu)

3.2  Struts 2的標(biāo)簽庫

3.3  Struts 2的控制器組件

4、Struts 1Struts 2的對(duì)比

5、WebWorkStruts 2對(duì)比

6、總 結(jié) 

 

引 言

Struts 1是全世界第一個(gè)發(fā)布的MVC框架,它由Craig McClanahan2001年發(fā)布,該框架一經(jīng)推出,就得到了世界上Java Web開發(fā)者的擁護(hù),經(jīng)過長(zhǎng)達(dá)6年時(shí)間的錘煉,Struts 1框架更加成熟、穩(wěn)定,性能也有了很好的保證。因此,到目前為止,Struts 1依然是世界上使用最廣泛的MVC框架。

目前,基于WebMVC框架非常多,發(fā)展也很快,每隔一段時(shí)間就有一個(gè)新的MVC框架發(fā)布,例如像JSFTapestrySpring MVC等。除了這些有名的MVC框架外,還有一些邊緣團(tuán)隊(duì)的MVC框架也很有借鑒意義。

對(duì)于企業(yè)實(shí)際使用MVC框架而言,框架的穩(wěn)定性則應(yīng)該是最值得考慮的問題。一個(gè)剛剛起步的框架,可能本身就存在一些隱藏的問題,會(huì)將自身的BUG引入自己的應(yīng)用。

雖然Struts 2號(hào)稱是一個(gè)全新的框架,但這僅僅是相對(duì)Struts 1而言。Struts 2Struts 1相比,確實(shí)有很多革命性的改進(jìn),但它并不是新發(fā)布的新框架,而是在另一個(gè)赫赫有名的框架:WebWork基礎(chǔ)上發(fā)展起來的。從某種程度上來講,Strut2沒有繼承Struts 1的血統(tǒng),而是繼承了WebWork的血統(tǒng)?;蛘哒f,WebWork衍生出了Struts 2,而不是Struts 1衍生了Struts 2。因?yàn)?span>Struts 2WebWork的升級(jí),而不是一個(gè)全新的框架,因此穩(wěn)定性、性能等各方面都有很好的保證;而且吸收了Struts 1WebWork兩者的優(yōu)勢(shì),因此,是一個(gè)非常值得期待的框架。

 

1.  MVC思想概述

今天,我們見到的絕大部分應(yīng)用,都是基于B/S(瀏覽器/服務(wù)器)架構(gòu)的,其中的服務(wù)器就是Web服務(wù)器??梢姡?span>Web應(yīng)用是目前廣泛使用的應(yīng)用模式,而Struts 2是一個(gè)具有很好的實(shí)用價(jià)值的Web MVC框架。介紹Struts MVC框架之前,我們首先介紹Web應(yīng)用的發(fā)展歷史和MVC思想。

1.1 Web技術(shù)的發(fā)展

隨著Internet技術(shù)的廣泛使用,Web技術(shù)已經(jīng)廣泛應(yīng)用于Internet上,但早期的Web應(yīng)用全部是靜態(tài)的HTML頁面,用于將一些文本信息呈現(xiàn)給瀏覽者,但這些信息是固定寫在HTML頁面里的,該頁面不具備與用戶交互的能力,沒有動(dòng)態(tài)顯示的功能。

很自然地,人們希望Web應(yīng)用里應(yīng)該包含一些能動(dòng)態(tài)執(zhí)行的頁面,最早的CGI(通用網(wǎng)關(guān)接口)技術(shù)滿足了該要求,CGI技術(shù)使得Web應(yīng)用可以與客戶端瀏覽器交互,不再需要使用靜態(tài)的HTML頁面。CGI技術(shù)可以從數(shù)據(jù)庫讀取信息,將這些信息呈現(xiàn)給用戶;還可以獲取用戶的請(qǐng)求參數(shù),并將這些參數(shù)保存到數(shù)據(jù)庫里。

CGI技術(shù)開啟了動(dòng)態(tài)Web應(yīng)用的時(shí)代,給了這種技術(shù)無限的可能性。但CGI技術(shù)存在很多缺點(diǎn),其中最大的缺點(diǎn)就是開發(fā)動(dòng)態(tài)Web應(yīng)用難度非常大,而且在性能等各方面也存在限制。到1997年時(shí),隨著Java語言的廣泛使用,Servlet技術(shù)迅速成為動(dòng)態(tài)Web應(yīng)用的主要開發(fā)技術(shù)。

相比傳統(tǒng)的CGI應(yīng)用而言,Servlet具有大量的優(yōu)勢(shì):

?       Servlet是基于Java語言創(chuàng)建的,而Java語言則內(nèi)建了多線程支持,這一點(diǎn)大大提高了動(dòng)態(tài)Web應(yīng)用的性能。

?       Servlet應(yīng)用可以充分利用Java語言的優(yōu)勢(shì),例如JDBCJava DataBase Connection)等。同時(shí),Java語言提供了豐富的類庫,這些都簡(jiǎn)化了Servlet的開發(fā)。

?       除此之外,Servlet運(yùn)行在Web服務(wù)器中,由Web服務(wù)器去負(fù)責(zé)管理Servlet的實(shí)例化,并對(duì)客戶端提供多線程、網(wǎng)絡(luò)通信等功能,這都保證Servlet有更好的穩(wěn)定性和性能。

ServletWeb應(yīng)用中被映射成一個(gè)URL(統(tǒng)一資源定位),該URL可以被客戶端瀏覽器請(qǐng)求,當(dāng)用戶向指定URL對(duì)應(yīng)的Servlet發(fā)送請(qǐng)求時(shí),該請(qǐng)求被Web服務(wù)器接收到,該Web服務(wù)器負(fù)責(zé)處理多線程、網(wǎng)絡(luò)通信等功能,而Servlet的內(nèi)容則決定了服務(wù)器對(duì)客戶端的響應(yīng)內(nèi)容。

 

 

1.1  Servlet的響應(yīng)流程

1.1顯示了Servlet的響應(yīng)流程。

正如圖1.1所顯示的,瀏覽器向Web服務(wù)器內(nèi)指定的Servlet發(fā)送請(qǐng)求,Web服務(wù)器根據(jù)Servlet生成對(duì)客戶端的響應(yīng)。

實(shí)際上,這是后來所有的動(dòng)態(tài)Web編程技術(shù)所使用的模型,這種模型都需要一個(gè)動(dòng)態(tài)的程序,或者一個(gè)動(dòng)態(tài)頁面,當(dāng)客戶端向該動(dòng)態(tài)程序或動(dòng)態(tài)頁面發(fā)送請(qǐng)求時(shí),Web服務(wù)器根據(jù)該動(dòng)態(tài)程序來生成對(duì)客戶端的響應(yīng)。

到了1998年,微軟發(fā)布了ASP 2.0。它是Windows NT 4 Option Pack的一部分,作為IIS 4.0的外接式附件。它與ASP 1.0的主要區(qū)別在于它的外部組件是可以初始化的,這樣,在ASP程序內(nèi)部的所有組件都有了獨(dú)立的內(nèi)存空間,并可以進(jìn)行事務(wù)處理。標(biāo)志著ASP技術(shù)開始真正作為動(dòng)態(tài)Web編程技術(shù)。

當(dāng)ASP技術(shù)在世界上廣泛流行時(shí),人們很快感受到這種簡(jiǎn)單的技術(shù)的魅力:ASP使用VBScript作為腳本語言,它的語法簡(jiǎn)單、開發(fā)效率非常高。而且,世界上已經(jīng)有了非常多的VB程序員,這些VB程序員可以很輕易地過渡成ASP程序員——因此,ASP技術(shù)馬上成為應(yīng)用最廣泛的動(dòng)態(tài)Web開發(fā)技術(shù)。

隨后,由Sun帶領(lǐng)的Java陣營,立即發(fā)布了JSP標(biāo)準(zhǔn),從某種程度上來看,JSPJava陣營為了對(duì)抗ASP推出的一種動(dòng)態(tài)Web編程技術(shù)。

ASPJSP從名稱上如此相似,但它們的運(yùn)行機(jī)制存在一些差別,這主要是因?yàn)?span>VBScript是一種腳本語言,無需編譯,而JSP使用Java作為腳本語句——Java從來就不是解釋型的腳本語言,因此JSP頁面并不能立即執(zhí)行。因此,JSP必須編譯成Servlet,這就是說:JSP的實(shí)質(zhì)還是Servlet。不過,書寫JSP比書寫Servlet簡(jiǎn)單得多。

JSP的運(yùn)行機(jī)理如圖1.2所示。 

 

 1.2  JSP的運(yùn)行機(jī)理

對(duì)比圖1.1和圖1.2,發(fā)現(xiàn)不論是Servlet動(dòng)態(tài)Web技術(shù),還是JSP動(dòng)態(tài)Web技術(shù),它們的實(shí)質(zhì)完全一樣??梢赃@樣理解:JSP是一種更簡(jiǎn)單的Servlet技術(shù),這也是JSP技術(shù)出現(xiàn)的意義——作為一個(gè)和ASP對(duì)抗的技術(shù),簡(jiǎn)單就是JSP的最大優(yōu)勢(shì)。

隨著實(shí)際Web應(yīng)用的使用越來越廣泛,Web應(yīng)用的規(guī)模也越來越大,開發(fā)人員發(fā)現(xiàn)動(dòng)態(tài)Web應(yīng)用的維護(hù)成本越來越大,即使只需要修改該頁面的一個(gè)簡(jiǎn)單按鈕文本,或者一段靜態(tài)的文本內(nèi)容,也不得不打開混雜的動(dòng)態(tài)腳本的頁面源文件進(jìn)行修改——這是一種很大的風(fēng)險(xiǎn),完全有可能引入新的錯(cuò)誤。

這個(gè)時(shí)候,人們意識(shí)到:使用單純的ASP,或者JSP頁面充當(dāng)過多角色是相當(dāng)失敗的選擇,這對(duì)于后期的維護(hù)相當(dāng)不利。慢慢地開發(fā)人員開始在Web開發(fā)中使用MVC模式。

隨后就是Java陣營發(fā)布了一套完整的企業(yè)開發(fā)規(guī)范:J2EE(現(xiàn)在已經(jīng)更名為Java EE),緊跟著微軟也發(fā)布了ASP.NET技術(shù),它們都采用一種優(yōu)秀的分層思想,力圖解決Web應(yīng)用維護(hù)困難的問題。

動(dòng)態(tài)Web編程技術(shù)大致有如圖1.3所示的路線。

 

 圖1.3  動(dòng)態(tài)Web編程技術(shù)的發(fā)展歷史

1.2 Model 1Model 2

對(duì)于Java陣營的動(dòng)態(tài)Web編程技術(shù)而言,則經(jīng)歷了所謂的Model 1Model 2時(shí)代。

所謂Model 1就是JSP大行其道的時(shí)代,在Model 1模式下,整個(gè)Web應(yīng)用幾乎全部由JSP頁面組成,JSP頁面接收處理客戶端請(qǐng)求,對(duì)請(qǐng)求處理后直接做出響應(yīng)。用少量的JavaBean來處理數(shù)據(jù)庫連接、數(shù)據(jù)庫訪問等操作。

1.4顯示了Model 1的程序流程。

 

 1.4  Model 1的程序流程

Model 1模式的實(shí)現(xiàn)比較簡(jiǎn)單,適用于快速開發(fā)小規(guī)模項(xiàng)目。但從工程化的角度看,它的局限性非常明顯:JSP頁面身兼ViewController兩種角色,將控制邏輯和表現(xiàn)邏輯混雜在一起,從而導(dǎo)致代碼的重用性非常低,增加了應(yīng)用的擴(kuò)展性和維護(hù)的難度。

早期有大量ASPJSP技術(shù)開發(fā)出來的Web應(yīng)用,這些Web應(yīng)用都采用了Model 1架構(gòu)。

Model 2已經(jīng)是基于MVC架構(gòu)的設(shè)計(jì)模式。在Model 2架構(gòu)中,Servlet作為前端控制器,負(fù)責(zé)接收客戶端發(fā)送的請(qǐng)求,在Servlet中只包含控制邏輯和簡(jiǎn)單的前端處理;然后,調(diào)用后端JavaBean來完成實(shí)際的邏輯處理;最后,轉(zhuǎn)發(fā)到相應(yīng)的JSP頁面處理顯示邏輯。其具體的實(shí)現(xiàn)方式如圖1.5所示。

1.5顯示了Model 2的程序流程。

 

 1.5  Model 2的程序流程

正如圖1.5中看到的,Model 2JSP不再承擔(dān)控制器的責(zé)任,它僅僅是表現(xiàn)層角色,僅僅用于將結(jié)果呈現(xiàn)給用戶,JSP頁面的請(qǐng)求與Servlet(控制器)交互,而Servlet負(fù)責(zé)與后臺(tái)的JavaBean通信。在Model 2模式下,模型(Model)由JavaBean 充當(dāng),視圖(View)由JSP頁面充當(dāng),而控制器(Controller)則由Servlet充當(dāng)。

由于引入了MVC模式,使Model 2具有組件化的特點(diǎn),更適用于大規(guī)模應(yīng)用的開發(fā),但也增加了應(yīng)用開發(fā)的復(fù)雜程度。原本需要一個(gè)簡(jiǎn)單的JSP頁面就能實(shí)現(xiàn)的應(yīng)用,在Model 2中被分解成多個(gè)協(xié)同工作的部分,需花更多時(shí)間才能真正掌握其設(shè)計(jì)和實(shí)現(xiàn)過程。

Model 2已經(jīng)是MVC設(shè)計(jì)思想下的架構(gòu),下面簡(jiǎn)要介紹MVC設(shè)計(jì)思想的優(yōu)勢(shì)。

      注意:對(duì)于非常小型的Web站點(diǎn),如果后期的更新、維護(hù)工作不是特別大,可以使用Model 1的模式來開發(fā)應(yīng)用,而不是使用Model 2的模式。雖然Model 2提供了更好的可擴(kuò)展性及可維護(hù)性,但增加了前期開發(fā)成本。從某種程度上講,Model 2為了降低系統(tǒng)后期維護(hù)的復(fù)雜度,卻導(dǎo)致前期開發(fā)的更高復(fù)雜度。

1.3 MVC思想及其優(yōu)勢(shì)

MVC并不是Java語言所特有的設(shè)計(jì)思想,也并不是Web應(yīng)用所特有的思想,它是所有面向?qū)ο蟪绦蛟O(shè)計(jì)語言都應(yīng)該遵守的規(guī)范。

MVC思想將一個(gè)應(yīng)用分成三個(gè)基本部分:Model(模型)、View(視圖)和Controller(控制器),這三個(gè)部分以最少的耦合協(xié)同工作,從而提高應(yīng)用的可擴(kuò)展性及可維護(hù)性。

起初,MVC模式是針對(duì)相同的數(shù)據(jù)需要不同顯示的應(yīng)用而設(shè)計(jì)的,其整體的效果如圖1.6所示。

   

    圖1.6  MVC結(jié)構(gòu)

在經(jīng)典的MVC模式中,事件由控制器處理,控制器根據(jù)事件的類型改變模型或視圖,反之亦然。具體地說,每個(gè)模型對(duì)應(yīng)一系列的視圖列表,這種對(duì)應(yīng)關(guān)系通常采用注冊(cè)來完成,即:把多個(gè)視圖注冊(cè)到同一個(gè)模型,當(dāng)模型發(fā)生改變時(shí),模型向所有注冊(cè)過的視圖發(fā)送通知,接下來,視圖從對(duì)應(yīng)的模型中獲得信息,然后完成視圖顯示的更新。

從設(shè)計(jì)模式的角度來看,MVC思想非常類似于一個(gè)觀察者模式,但與觀察者模式存在少許差別:觀察者模式下觀察者和被觀察者可以是兩個(gè)互相對(duì)等的對(duì)象,但對(duì)于MVC思想而言,被觀察者往往只是單純的數(shù)據(jù)體,而觀察者則是單純的視圖頁面。

概括起來,MVC有如下特點(diǎn)。

?       多個(gè)視圖可以對(duì)應(yīng)一個(gè)模型。按MVC設(shè)計(jì)模式,一個(gè)模型對(duì)應(yīng)多個(gè)視圖,可以減少代碼的復(fù)制及代碼的維護(hù)量,一旦模型發(fā)生改變,也易于維護(hù)。

?       模型返回的數(shù)據(jù)與顯示邏輯分離。模型數(shù)據(jù)可以應(yīng)用任何的顯示技術(shù),例如,使用JSP頁面、Velocity模板或者直接產(chǎn)生Excel文檔等。

?       應(yīng)用被分隔為三層,降低了各層之間的耦合,提供了應(yīng)用的可擴(kuò)展性。

?       控制層的概念也很有效,由于它把不同的模型和不同的視圖組合在一起,完成不同的請(qǐng)求。因此,控制層可以說是包含了用戶請(qǐng)求權(quán)限的概念。

?       MVC更符合軟件工程化管理的精神。不同的層各司其職,每一層的組件具有相同的特征,有利于通過工程化和工具化產(chǎn)生管理程序代碼。

相對(duì)于早期的MVC思想,Web模式下的MVC思想則又存在一些變化,因?yàn)閷?duì)于一個(gè)應(yīng)用程序而言,我們可以將視圖注冊(cè)給模型,當(dāng)模型數(shù)據(jù)發(fā)生改變時(shí),即時(shí)通知視圖頁面發(fā)生改變;而對(duì)于Web應(yīng)用而言,即使將多個(gè)JSP頁面注冊(cè)給一個(gè)模型,當(dāng)模型發(fā)生變化時(shí),模型無法主動(dòng)發(fā)送消息給JSP頁面(因?yàn)?span>Web應(yīng)用都是基于請(qǐng)求/響應(yīng)模式的),只有當(dāng)用戶請(qǐng)求瀏覽該頁面時(shí),控制器才負(fù)責(zé)調(diào)用模型數(shù)據(jù)來更新JSP頁面。

      注意:MVC思想與觀察者模式有一定的相似之處,但并不完全相同。經(jīng)典的MVC思想與Web應(yīng)用的MVC思想也存在一定的差別,引起差別的主要原因是因?yàn)?span>Web應(yīng)用是一種請(qǐng)求/響應(yīng)模式下應(yīng)用,對(duì)于請(qǐng)求/響應(yīng)應(yīng)用,如果用戶不對(duì)應(yīng)用發(fā)出請(qǐng)求,視圖無法主動(dòng)更新自己。

1.4 常用的MVC框架

目前常用的MVC框架,除了Struts 2的兩個(gè)前身外,還有一些非常流行的MVC框架,這些框架都提供了較好的層次分隔能力。在實(shí)現(xiàn)良好的MVC 分隔的基礎(chǔ)上,還提供一些輔助類庫,幫助應(yīng)用的開發(fā)。

目前常用的MVC框架還有如下一些。

1)   JSF

準(zhǔn)確地說,JSF是一個(gè)標(biāo)準(zhǔn),而不是一個(gè)產(chǎn)品。目前,JSF已經(jīng)有兩個(gè)實(shí)現(xiàn)產(chǎn)品可供選擇,包含Sun的參考實(shí)現(xiàn)和ApacheMyFaces。大部分的時(shí)候,我們所說的JSF都是指Sun的參考實(shí)現(xiàn)。目前,JSF是作為JEE 5.0的一個(gè)組成部分,與JEE 5.0一起發(fā)布。

JSF的行為方法在POJO中實(shí)現(xiàn),JSFManaged Bean無需繼承任何特別的類。因此,無需在表單和模型對(duì)象之間實(shí)現(xiàn)多余的控制器層。JSF中沒有控制器對(duì)象,控制器行為通過模型對(duì)象實(shí)現(xiàn)。

當(dāng)然,JSF也允許生成獨(dú)立的控制器對(duì)象。在Struts 1中,Form Bean包含數(shù)據(jù),Action Bean包含業(yè)務(wù)邏輯,二者無法融合在一起。在JSF中,既可以將二者分開,也可以合并在一個(gè)對(duì)象中,提供更多靈活的選擇。

JSF的事件框架可以細(xì)化到表單中每個(gè)字段。JSF依然是基于JSP/Servlet的,仍然是JSP/Servlet架構(gòu),因而學(xué)習(xí)曲線相對(duì)簡(jiǎn)單。在實(shí)際使用過程中,JSF也會(huì)存在一些不足

?       作為新興的MVC框架,用戶相對(duì)較少,相關(guān)資源也不是非常豐富。

?       JSF并不是一個(gè)完全組件化的框架,它依然是基于JSP/Servlet架構(gòu)的。

?       JSF的成熟度還有待進(jìn)一步提高。

2)   Tapestry

Tapestry并不是一種單純的MVC框架,它更像MVC框架和模板技術(shù)的結(jié)合,它不僅包含了前端的MVC框架,還包含了一種視圖層的模板技術(shù),使用Tapestry完全可以與Servlet/JSP API分離,是一種非常優(yōu)秀的設(shè)計(jì)。

通過使用Tapestry,開發(fā)者完全不需要使用JSP技術(shù),用戶只需要使用Tapestry提供的模板技術(shù)即可,Tapestry實(shí)現(xiàn)了視圖邏輯和業(yè)務(wù)邏輯的徹底分離。

Tapestry使用組件庫替代了標(biāo)簽庫,沒有標(biāo)簽庫概念,從而避免了標(biāo)簽庫和組件結(jié)合的問題。Tapsetry是完全組件化的框架。Tapestr只有組件或頁面兩個(gè)概念,因此,鏈接跳轉(zhuǎn)目標(biāo)要么是組件,要么是頁面,沒有多余的path概念。組件名,也就是對(duì)象名稱,組件名稱和path名稱合二為一。

Tapestry具有很高的代碼復(fù)用性,在Tapestry中,任何對(duì)象都可看作可復(fù)用的組件。JSP開發(fā)者是真正面向?qū)ο?,而不?span>URL解析。對(duì)于對(duì)頁面要求靈活度相當(dāng)高的系統(tǒng),Tapestry是第一選擇。精確地錯(cuò)誤報(bào)告,可以將錯(cuò)誤定位到源程序中的行,取代了JSP中那種編譯后的提示。

因此,筆者一直對(duì)Tapestry情有獨(dú)鐘:如果技術(shù)允許,使用Tapestry會(huì)帶給整個(gè)應(yīng)用更加優(yōu)雅的架構(gòu),更好的開發(fā)效率。

但是,在實(shí)際開發(fā)過程中,采用Tapestry也面臨著一些問題必須考慮:

?       Tapestry的學(xué)習(xí)曲線相對(duì)陡峭,國內(nèi)開發(fā)群體不是非?;钴S,文檔不是十分豐富。官方的文檔太過學(xué)院派,缺乏實(shí)際的示例程序。

?       Tapestry的組件邏輯比較復(fù)雜,再加上OGNL表達(dá)式和屬性指定機(jī)制,因而難以添加注釋。

3)   Spring MVC

Spring提供了一個(gè)細(xì)致完整的MVC框架。該框架為模型、視圖、控制器之間提供了一個(gè)非常清晰的劃分,各部分耦合極低。SpringMVC是非常靈活的,它完全基于接口編程,真正實(shí)現(xiàn)了視圖無關(guān)。視圖不再強(qiáng)制要求使用JSP,可以使用VelocityXSLT或其他視圖技術(shù)。甚至可以使用自定義的視圖機(jī)制——只需要簡(jiǎn)單地實(shí)現(xiàn)View接口,并且把對(duì)應(yīng)視圖技術(shù)集成進(jìn)來。SpringControllersIoC容器管理。因此,單元測(cè)試更加方便。

Spring MVC框架以DispatcherServlet為核心控制器,該控制器負(fù)責(zé)攔截用戶的所有請(qǐng)求,將請(qǐng)求分發(fā)到對(duì)應(yīng)的業(yè)務(wù)控制器。

Spring MVC還包括處理器映射、視圖解析、信息國際化、主題解析、文件上傳等。所有控制器都必須實(shí)現(xiàn)Controller接口,該接口僅定義ModelAndView handleRequestrequest,response)方法。通過實(shí)現(xiàn)該接口來實(shí)現(xiàn)用戶的業(yè)務(wù)邏輯控制器。

Spring MVC框架有一個(gè)極好的優(yōu)勢(shì),就是它的視圖解析策略:它的控制器返回一個(gè)ModelAndView對(duì)象,該對(duì)象包含視圖名字和ModelModel提供了Bean的名字及其對(duì)象的對(duì)應(yīng)關(guān)系。視圖名解析的配置非常靈活,抽象的Model完全獨(dú)立于表現(xiàn)層技術(shù),不會(huì)與任何表現(xiàn)層耦合:JSP、Velocity或者其他的技術(shù)——都可以和Spring整合。

但相對(duì)于Tapestry框架而言,Spring MVC依然是基于JSP/Servlet API的。

總體上來看,Spring MVC框架致力于一種完美的解決方案,并與Web應(yīng)用緊緊耦合在一起。這都導(dǎo)致了Spring MVC框架的一些缺點(diǎn):

?       SpringMVCServlet API耦合,難以脫離Servlet容器獨(dú)立運(yùn)行,降低了Spring MVC框架的可擴(kuò)展性。

?       太過細(xì)化的角色劃分,太過煩瑣,降低了應(yīng)用的開發(fā)效率。

?       過分追求架構(gòu)的完美,有過度設(shè)計(jì)的危險(xiǎn)。

2Struts 2的起源和背景

Struts 2WebWork優(yōu)秀的設(shè)計(jì)思想為核心,吸收了Struts 1的部分優(yōu)點(diǎn),建立了一個(gè)兼容WebWorkStruts 1MVC框架,Struts 2的目標(biāo)是希望可以讓原來使用Struts 1、WebWork的開發(fā)人員,都可以平穩(wěn)過渡到使用Struts 2框架。

2.1 Struts 1簡(jiǎn)介及存在的問題

從過去的歲月來看,Struts 1是所有MVC框架中不容辯駁的勝利者,不管是市場(chǎng)占有率,還是所擁有的開發(fā)人群,Struts 1都擁有其他MVC框架不可比擬的優(yōu)勢(shì)。Struts 1的成功得益于它豐富的文檔、活躍的開發(fā)群體。當(dāng)然,Struts 1是世界上第一個(gè)發(fā)布的MVC框架:Struts 1.020016月發(fā)布,這一點(diǎn)可能是使它得到如此廣泛擁戴的主要原因。

為了使讀者可以明白Struts 1的運(yùn)行機(jī)制,下面將簡(jiǎn)要介紹Struts 1的基本框架。

Struts 1框架以ActionServlet作為核心控制器,整個(gè)應(yīng)用由客戶端請(qǐng)求驅(qū)動(dòng)。當(dāng)客戶端向Web應(yīng)用發(fā)送請(qǐng)求時(shí),請(qǐng)求將被Struts 1的核心控制器ActionServlet攔截,ActionServlet根據(jù)請(qǐng)求決定是否需要調(diào)用業(yè)務(wù)邏輯控制器處理用戶請(qǐng)求(實(shí)際上,業(yè)務(wù)邏輯控制器還是控制器,它只是負(fù)責(zé)調(diào)用模型來處理用戶請(qǐng)求),當(dāng)用戶請(qǐng)求處理完成后,其處理結(jié)果通過JSP呈現(xiàn)給用戶。

對(duì)于整個(gè)Struts 1框架而言,控制器就是它的核心,Struts 1的控制器由兩個(gè)部分組成:核心控制器和業(yè)務(wù)邏輯控制器。其中核心控制器就是ActionServlet,由Struts 1框架提供;業(yè)務(wù)邏輯控制就是用戶自定義的Action,由應(yīng)用開發(fā)者提供。

對(duì)于大部分用戶請(qǐng)求而言,都需要得到服務(wù)器的處理。當(dāng)用戶發(fā)送一個(gè)需要得到服務(wù)器處理的請(qǐng)求時(shí),該請(qǐng)求被ActionServlet攔截到,ActionServlet將該請(qǐng)求轉(zhuǎn)發(fā)給對(duì)應(yīng)的業(yè)務(wù)邏輯控制器,業(yè)務(wù)邏輯控制器調(diào)用模型來處理用戶請(qǐng)求;如果用戶請(qǐng)求只是希望得到某個(gè)URL資源,則由ActionServlet將被請(qǐng)求的資源轉(zhuǎn)發(fā)給用戶。

Struts 1的程序運(yùn)行流程如圖1.7所示。

 圖1.7  Struts 1的程序運(yùn)行流程

下面就Struts 1程序流程具體分析MVC中的三個(gè)角色。

1)   Model部分

Struts 1Model部分主要由底層的業(yè)務(wù)邏輯組件充當(dāng),這些業(yè)務(wù)邏輯組件封裝了底層數(shù)據(jù)庫訪問、業(yè)務(wù)邏輯方法實(shí)現(xiàn)。實(shí)際上,對(duì)于一個(gè)成熟的企業(yè)應(yīng)用而言,Model部分也不是一個(gè)簡(jiǎn)單的JavaBean所能完成的,它可能是一個(gè)或多個(gè)EJB組件,可能是一個(gè)WebService服務(wù)??傊?,Model部分封裝了整個(gè)應(yīng)用的所有業(yè)務(wù)邏輯,但整個(gè)部分并不是由Struts 1提供的,Struts 1也沒有為實(shí)現(xiàn)Model組件提供任何支持。

2)   View部分

Struts 1View部分采用JSP實(shí)現(xiàn)。Struts 1提供了豐富的標(biāo)簽庫,通過這些標(biāo)簽庫可以最大限度地減少腳本的使用。這些自定義的標(biāo)簽庫可以輸出控制器的處理結(jié)果。

雖然Struts 1提供了與Ties框架的整合,但Struts 1所支持的表現(xiàn)層技術(shù)非常單一:既不支持FreeMarker、Velocity等模板技術(shù),也不支持JasperReports等報(bào)表技術(shù)。

3)   Controller部分

Struts 1Controller由兩個(gè)部分組成。

?       系統(tǒng)核心控制器:由Struts 1框架提供,就是系統(tǒng)中的ActionServlet

?       業(yè)務(wù)邏輯控制器:由Struts 1框架提供,就是用戶自己實(shí)現(xiàn)的Action實(shí)例。

Struts 1的核心控制器對(duì)應(yīng)圖1.7中的核心控制器(ActionServlet)。該控制器由Struts 1框架提供,繼承HttpServlet類,因此可以配置成一個(gè)標(biāo)準(zhǔn)的Servlet,該控制器負(fù)責(zé)攔截所有HTTP請(qǐng)求,然后根據(jù)用戶請(qǐng)求決定是否需要調(diào)用業(yè)務(wù)邏輯控制器,如果需要調(diào)用業(yè)務(wù)邏輯控制器,則將請(qǐng)求轉(zhuǎn)發(fā)給Action處理,否則直接轉(zhuǎn)向請(qǐng)求的JSP頁面。

業(yè)務(wù)邏輯控制器負(fù)責(zé)處理用戶請(qǐng)求,但業(yè)務(wù)邏輯控制器本身并不具有處理能力,而是調(diào)用Model來完成處理。

Struts 1提供了系統(tǒng)所需要的核心控制器,也為實(shí)現(xiàn)業(yè)務(wù)邏輯控制器提供了許多支持。因此,控制器部分就是Struts 1框架的核心。有時(shí)候,我們直接將MVC層稱為控制器層。

      提示:對(duì)于任何的MVC框架而言,其實(shí)只實(shí)現(xiàn)了C(控制器)部分,但它負(fù)責(zé)用控制器調(diào)用業(yè)務(wù)邏輯組件,并負(fù)責(zé)控制器與視圖技術(shù)(JSP、FreeMarkerVelocity等)的整合。

對(duì)于Struts 1框架而言,因?yàn)樗cJSP/Servlet耦合非常緊密,因而導(dǎo)致了許多不可避免的缺陷,隨著Web應(yīng)用的逐漸擴(kuò)大,這些缺陷逐漸變成制約Struts 1發(fā)展的重要因素——這也是Struts 2出現(xiàn)的原因。下面具體分析Struts 1中存在的種種缺陷。

1)   支持的表現(xiàn)層技術(shù)單一

Struts 1只支持JSP作為表現(xiàn)層技術(shù),不提供與其他表現(xiàn)層技術(shù),例如Velocity、FreeMarker等技術(shù)的整合。這一點(diǎn)嚴(yán)重制約了Struts 1框架的使用,對(duì)于目前的很多Java EE應(yīng)用而言,并不一定使用JSP作為表現(xiàn)層技術(shù)。

雖然Struts 1處理完用戶請(qǐng)求后,并沒有直接轉(zhuǎn)到特定的視圖資源,而是返回一個(gè)ActionForward對(duì)象(可以理解ActionForward是一個(gè)邏輯視圖名),在struts-config.xml文件中定義了邏輯視圖名和視圖資源之間的對(duì)應(yīng)關(guān)系,當(dāng)ActionServlet得到處理器返回的ActionForword對(duì)象后,可以根據(jù)邏輯視圖名和視圖資源之間的對(duì)應(yīng)關(guān)系,將視圖資源呈現(xiàn)給用戶。

從上面的設(shè)計(jì)來看,不得不佩服Struts 1的設(shè)計(jì)者高度解耦的設(shè)計(jì):控制器并沒有直接執(zhí)行轉(zhuǎn)發(fā)請(qǐng)求,而僅僅返回一個(gè)邏輯視圖名——實(shí)際的轉(zhuǎn)發(fā)放在配置文件中進(jìn)行管理。但因?yàn)?span>Struts 1框架出現(xiàn)的年代太早了,那時(shí)候還沒有FreeMarker、Velocity等技術(shù),因而沒有考慮與這些FreeMarker、Velocity等視圖技術(shù)的整合。

      提示:Struts 1已經(jīng)通過配置文件管理邏輯視圖名和實(shí)際視圖之間的對(duì)應(yīng)關(guān)系,只是沒有做到讓邏輯視圖名可以支持更多的視圖技術(shù)。

雖然Struts 1有非常優(yōu)秀的設(shè)計(jì),但由于歷史原因,它沒有提供與更多視圖技術(shù)的整合,這嚴(yán)重限制了Struts 1的使用。

1)   Servlet API嚴(yán)重耦合,難于測(cè)試

因?yàn)?span>Struts 1框架是在Model 2的基礎(chǔ)上發(fā)展起來的,因此它完全是基于Servlet API的,所以在Struts 1的業(yè)務(wù)邏輯控制器內(nèi),充滿了大量的Servlet API

看下面的Action代碼片段:

//業(yè)務(wù)邏輯控制器必須繼承Struts 1提供的Action

public class LoginAction extends Action

{

//處理用戶請(qǐng)求的execute方法

public ActionForward execute(

ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response)

throws     AuctionException  {

//獲取封裝用戶請(qǐng)求參數(shù)的ActionForm對(duì)象

//將其強(qiáng)制類型轉(zhuǎn)換為登錄用的ActionForm

LoginForm loginForm = (LoginForm)form;

//當(dāng)用戶名為scott,密碼為tiger時(shí)返回成功

if (”scott”.equals(loginForm.getUsername()

&& “tiger”.equals(loginForm.getPassword())

{

//處理成功,返回一個(gè)ActionForward對(duì)象

return mapping.findForward(”success”);                                    }

else  

{

//處理失敗,返回一個(gè)ActionForward對(duì)象

return mapping.findForward(”success”);                                    }

    }

}

當(dāng)我們需要測(cè)試上面Action類的execute方法時(shí),該方法有4個(gè)參數(shù):ActionMapping、ActionForm、HttpServletRequestHttpServletResponse,初始化這4個(gè)參數(shù)比較困難,尤其是HttpServletRequestHttpServletResponse兩個(gè)參數(shù),通常由Web容器負(fù)責(zé)實(shí)例化。

因?yàn)?span>HttpServletRequestHttpServletResponse兩個(gè)參數(shù)是Servlet API,嚴(yán)重依賴于Web服務(wù)器。因此,一旦脫離了Web服務(wù)器,Action的測(cè)試非常困難。

2)   代碼嚴(yán)重依賴于Struts 1 API,屬于侵入式設(shè)計(jì)

正如從上面代碼片段中所看到的,Struts 1Action類必須繼承Struts 1Action基類,實(shí)現(xiàn)處理方法時(shí),又包含了大量Struts 1 API:如ActionMapping、ActionFormActionForward類。這種侵入式設(shè)計(jì)的最大弱點(diǎn)在于,一旦系統(tǒng)需要重構(gòu)時(shí),這些Action類將完全沒有利用價(jià)值,成為一堆廢品。

可見,Struts 1Action類這種侵入式設(shè)計(jì)導(dǎo)致了較低的代碼復(fù)用。

2.2 WebWork簡(jiǎn)介

WebWork雖然沒有Struts 1那樣赫赫有名,但也是出身名門,WebWork來自另外一個(gè)優(yōu)秀的開源組織:opensymphony,這個(gè)優(yōu)秀的開源組織同樣開發(fā)了大量?jī)?yōu)秀的開源項(xiàng)目,如Qutarz、OSWorkFlow等。實(shí)際上,WebWork的創(chuàng)始人則是另一個(gè)Java領(lǐng)域的名人:Rickard Oberg(他就是JBossXDoclet的作者)。

相對(duì)于Struts 1存在的那些先天性不足而言,WebWork則更加優(yōu)秀,它采用了一種更加松耦合的設(shè)計(jì),讓系統(tǒng)的Action不再與Servlet API耦合。使單元測(cè)試更加方便,允許系統(tǒng)從B/S結(jié)構(gòu)向C/S結(jié)構(gòu)轉(zhuǎn)換。

相對(duì)于Struts 1僅支持JSP表現(xiàn)層技術(shù)的缺陷而言,WebWork支持更多的表現(xiàn)層技術(shù),如Velocity、FreeMarkerXSLT等。

WebWork可以脫離Web應(yīng)用使用,這一點(diǎn)似乎并沒有太多優(yōu)勢(shì),因?yàn)?,一個(gè)應(yīng)用通常開始已經(jīng)確定在怎樣的環(huán)境下使用。WebWork有自己的控制反轉(zhuǎn)(Inversion of Control)容器,通過控制反轉(zhuǎn),可以讓測(cè)試變得更簡(jiǎn)單,測(cè)試中設(shè)置實(shí)現(xiàn)服務(wù)接口的Mock對(duì)象完成測(cè)試,而不需要設(shè)置服務(wù)注冊(cè)。

WebWork 2使用OGNL這個(gè)強(qiáng)大的表達(dá)式語言,可以訪問值棧。OGNL對(duì)集合和索引屬性的支持非常強(qiáng)大。

WebWork建立在XWork之上,使用ServletDispatcher作為該框架的核心控制器,處理HTTP的響應(yīng)和請(qǐng)求。

從處理流程上來看,WebWorkStruts 1非常類似,它們的核心都由控制器組成,其中控制器都由兩個(gè)部分組成:

?       核心控制器ServletDispatcher,該控制器框架提供。

?       業(yè)務(wù)邏輯控制器Action,該控制器由程序員提供。

相對(duì)Struts 1ActionServlet API緊緊耦合的弱點(diǎn)來說,WebWorkAction則完全與Servlet API分離,因而該Action更容易測(cè)試。

WebWorkAction可以與Servlet API分離,得益于它靈巧的設(shè)計(jì),它使用一個(gè)攔截器鏈,負(fù)責(zé)將用戶請(qǐng)求數(shù)據(jù)轉(zhuǎn)發(fā)到Action,并負(fù)責(zé)將Action的處理結(jié)果轉(zhuǎn)換成對(duì)用戶的響應(yīng)。

當(dāng)用戶向Web應(yīng)用發(fā)送請(qǐng)求時(shí),該請(qǐng)求經(jīng)過ActionContextCleanUp、SiteMesh等過濾器過濾,由WebWork的核心控制器攔截,如果用戶請(qǐng)求需要WebWork的業(yè)務(wù)邏輯控制器處理,該控制器則調(diào)用Action映射器,該映射器將用戶請(qǐng)求轉(zhuǎn)發(fā)到對(duì)應(yīng)的業(yè)務(wù)邏輯控制器。值得注意的是,此時(shí)的業(yè)務(wù)邏輯控制器并不是開發(fā)者實(shí)現(xiàn)的控制器,而是WebWork創(chuàng)建的控制器代理。

創(chuàng)建控制器代理時(shí),WebWork需要得到開發(fā)者定義的xwork.xml配置文件,控制器代理以用戶實(shí)現(xiàn)的控制器作為目標(biāo),以攔截器鏈中的攔截器作為處理(Advice)。

      提示:WebWork中創(chuàng)建控制器代理的方式,就是一種AOP(面向切面編程)編程方式,只是這種AOP中的攔截器由系統(tǒng)提供,因此無需用戶參與。

開發(fā)者自己實(shí)現(xiàn)的業(yè)務(wù)邏輯控制器只是WebWork業(yè)務(wù)控制器的目標(biāo)——這就是為什么開發(fā)者自己實(shí)現(xiàn)的Action可以與Servlet API分離的原因。當(dāng)開發(fā)者自己的Action處理完HTTP請(qǐng)求后,該結(jié)果只是一個(gè)普通字符串,該字符串將對(duì)應(yīng)到指定的視圖資源。

指定的試圖資源經(jīng)過攔截器鏈的處理后,生成對(duì)客戶端的響應(yīng)輸出。

 上面整個(gè)過程的數(shù)據(jù)流圖如圖1.8所示。

 

              1.8  WebWork的數(shù)據(jù)流圖

與前面的Struts 1框架對(duì)比,不難發(fā)現(xiàn)WebWork在很多地方確實(shí)更優(yōu)秀。

相對(duì)Struts 1的種種缺點(diǎn)而言,WebWork存在如下優(yōu)點(diǎn):

?       Action無需與Servlet API耦合,更容易測(cè)試

相對(duì)于Struts 1框架中的Action出現(xiàn)了大量Servlet API而言,WebWorkAction更像一個(gè)普通Java對(duì)象,該控制器代碼中沒有耦合任何Servlet API??聪旅娴?span>WebWorkAction示例:

public class LoginAction implements Action

{

//該字符串常量將作為Action的返回值

private final static String LOGINFAIL=”loginfail”;

 //Action封裝的兩個(gè)請(qǐng)求參數(shù)

private String password;

private String username;

//password請(qǐng)求參數(shù)對(duì)應(yīng)的getter方法

public String getPassword()

{

return password;

}

//password請(qǐng)求參數(shù)對(duì)應(yīng)的setter方法

public void setPassword(String password)

{

this.password = password;

                        }

//username請(qǐng)求參數(shù)對(duì)應(yīng)的getter方法

public String getUsername()

{

return username;

               }

//username請(qǐng)求參數(shù)對(duì)應(yīng)的setter方法

public void setUsername(String username)

{

this.username = username;

                        }

 //處理用戶請(qǐng)求的execute方法

public String execute() throws Exception

{

if (”yeeku”.equalsIgnoreCase(getUsername())

&& “password”.equals(getPassword()))

{

ActionContext ctx = ActionContext.getContext();

//將當(dāng)前登錄的用戶名保存到Session

Map session = ctx.getSession();

session.put(”username”,getUsername());

return SUCCESS;

              }

else

{

return LOGINFAIL;

                }

         }

}

在上面的Action代碼中,我們看不到任何的Servlet API,當(dāng)系統(tǒng)需要處理兩個(gè)請(qǐng)求參數(shù):usernamepassword時(shí),Action并未通過HttpServletRequest對(duì)象來獲得請(qǐng)求參數(shù),而是直接調(diào)用訪問該Actionusernamepassword成員屬性——這兩個(gè)屬性由Action攔截器負(fù)責(zé)初始化,以用戶請(qǐng)求參數(shù)為其賦值。

即使Action中需要訪問HTTP Session對(duì)象,依然沒有在代碼中直接出現(xiàn)HttpSession API,而是以一個(gè)Map對(duì)象代表了HTTP Session對(duì)象。

當(dāng)我們將WebWorkActionStruts 1Action進(jìn)行對(duì)比時(shí),不難發(fā)現(xiàn)Struts 1Action確實(shí)太臃腫了,確實(shí)不如WebWorkAction那么優(yōu)雅。

如果需要測(cè)試上面的Action代碼,測(cè)試用例的書寫將非常容易,因?yàn)?span>execute方法中沒有包含任何Servlet API,甚至沒有WebWorkAPI。

?       Action無需與WebWork耦合,代碼重用率高

在上面的Action代碼中,不難發(fā)現(xiàn)WebWork中的Action其實(shí)就是一個(gè)POJO,該Action僅僅實(shí)現(xiàn)了WebWorkAction接口,包含了一個(gè)execute方法。

Struts 1中的Action類需要繼承Struts 1Action類。我們知道,實(shí)現(xiàn)一個(gè)接口和繼承一個(gè)類是完全不同的概念:實(shí)現(xiàn)一個(gè)接口對(duì)類的污染要小得多,該類也可以實(shí)現(xiàn)其他任意接口,還可以繼承一個(gè)父類;但一旦已經(jīng)繼承一個(gè)父類,則意味著該類不能再繼承其他父類。

除此之外,Struts 1Action也包含了一個(gè)execute方法,但該方法需要4個(gè)參數(shù),類型分別是ActionMapping、ActionForm、HttpServletRequestHttpServletResponse,一個(gè)包含了這4個(gè)參數(shù)的方法,除了在Struts 1框架下有用外,筆者難以想象出該代碼還有任何復(fù)用價(jià)值。但WebWorkexecute方法則完全不同,該方法中沒有出現(xiàn)任何Servlet API,也沒有出現(xiàn)任何WebWork API,這個(gè)方法在任何環(huán)境下都有重用的價(jià)值。

得益于WebWork靈巧的設(shè)計(jì),WebWork中的Action無需與任何Servlet API、WebWork API耦合,從而具有更好的代碼重用率。

?       支持更多的表現(xiàn)層技術(shù),有更好的適應(yīng)性。

正如從圖1.8所見到的,WebWork對(duì)多種表現(xiàn)層技術(shù):JSP、VelocityFreeMarker等都有很好的支持,從而給開發(fā)更多的選擇,提供了更好的適應(yīng)性。

2.3  Struts 2起源

經(jīng)過五年多的發(fā)展,Struts 1已經(jīng)成為一個(gè)高度成熟的框架,不管是穩(wěn)定性還是可靠性,都得到了廣泛的證明。但由于它太了,一些設(shè)計(jì)上的缺陷成為它的硬傷。面對(duì)大量新的MVC框架蓬勃興起,Struts 1也開始了血液的更新。

目前,Struts已經(jīng)分化成兩個(gè)框架:第一個(gè)框架就是傳統(tǒng)Struts 1WebWork結(jié)合后的Struts 2框架。Struts 2雖然是在Struts 1的基礎(chǔ)上發(fā)展起來的,但實(shí)質(zhì)上是以WebWork為核心,Struts 2為傳統(tǒng)Struts 1注入了WebWork的設(shè)計(jì)理念,統(tǒng)一了Struts 1WebWork兩個(gè)框架,允許Struts 1WebWork開發(fā)者同時(shí)使用Struts 2框架。

Struts分化出來的另外一個(gè)框架是Shale,這個(gè)框架遠(yuǎn)遠(yuǎn)超出了Struts 1原有的設(shè)計(jì)思想,它與原有的Struts 1的關(guān)聯(lián)很少,它使用全新的設(shè)計(jì)思想。Shale更像一個(gè)新的框架,而不是Struts的升級(jí)。

Shale 在很多方面與Struts存在不同之處,其中有兩點(diǎn)最為突出:

?       StrutsJSF集成,而Shale則是建立在JSF之上。

?       Struts實(shí)質(zhì)上是一個(gè)巨大的、復(fù)雜的請(qǐng)求處理器;而Shale則是一組能以任何方式進(jìn)行組合的服務(wù),簡(jiǎn)單地說,Shale是一種SOA(面向服務(wù)架構(gòu))架構(gòu)。

在后面的介紹中,我們會(huì)發(fā)現(xiàn),Struts 2非常類似于WebWork框架,而不像Struts 1框架,因?yàn)?span>Struts 2是以WebWork為核心,而不是以Struts 1為核心的。正因?yàn)榇耍S多WebWork開發(fā)者會(huì)發(fā)現(xiàn),從WebWork過渡到Struts 2是一件非常簡(jiǎn)單的事情。

當(dāng)然,對(duì)于傳統(tǒng)的Struts 1開發(fā)者,Struts 2也提供了很好的向后兼容性,Struts 2可與Struts 1有機(jī)整合,從而保證Struts 1開發(fā)者能平穩(wěn)過渡到Struts 2。

3Struts 2體系介紹

Struts 2的體系與Struts 1體系的差別非常大,因?yàn)?span>Struts 2使用了WebWork的設(shè)計(jì)核心,而不是使用Struts 1的設(shè)計(jì)核心。Struts 2大量使用攔截器來處理用戶請(qǐng)求,從而允許用戶的業(yè)務(wù)邏輯控制器與Servlet API分離。

3.1 Struts 2框架架構(gòu)

從數(shù)據(jù)流圖上來看,Struts 2WebWork相差不大,Struts 2同樣使用攔截器作為處理(Advice),以用戶的業(yè)務(wù)邏輯控制器為目標(biāo),創(chuàng)建一個(gè)控制器代理。

控制器代理負(fù)責(zé)處理用戶請(qǐng)求,處理用戶請(qǐng)求時(shí)回調(diào)業(yè)務(wù)控制器的execute方法,該方法的返回值將決定了Struts 2將怎樣的視圖資源呈現(xiàn)給用戶。

1.9顯示了Struts 2的體系概圖。

  

    1.9  Struts 2的體系概圖

Struts 2框架的大致處理流程如下:

?       瀏覽器發(fā)送請(qǐng)求,例如請(qǐng)求/mypage.action/reports/myreport.pdf等。

?       核心控制器FilterDispatcher根據(jù)請(qǐng)求決定調(diào)用合適的Action。

?       WebWork的攔截器鏈自動(dòng)對(duì)請(qǐng)求應(yīng)用通用功能,例如workflow、validation或文件上傳等功能。

?       回調(diào)Actionexecute方法,該execute方法先獲取用戶請(qǐng)求參數(shù),然后執(zhí)行某種數(shù)據(jù)庫操作,既可以是將數(shù)據(jù)保存到數(shù)據(jù)庫,也可以從數(shù)據(jù)庫中檢索信息。實(shí)際上,因?yàn)?span>Action只是一個(gè)控制器,它會(huì)調(diào)用業(yè)務(wù)邏輯組件來處理用戶的請(qǐng)求。

?       Actionexecute方法處理結(jié)果信息將被輸出到瀏覽器中,可以是HTML頁面、圖像,也可以是PDF文檔或者其他文檔。此時(shí)支持的視圖技術(shù)非常多,既支持JSP,也支持Velocity、FreeMarker等模板技術(shù)。

3.2 Struts 2的配置文件

當(dāng)Struts 2創(chuàng)建系統(tǒng)的Action代理時(shí),需要使用Struts 2的配置文件。

Struts 2的配置文件有兩份:

?       配置Actionstruts.xml文件。

?       配置Struts 2全局屬性的struts.properties文件。

struts.xml文件內(nèi)定義了Struts 2的系列Action,定義Action時(shí),指定該Action的實(shí)現(xiàn)類,并定義該Action處理結(jié)果與視圖資源之間的映射關(guān)系。

下面是struts.xml配置文件的示例:

<struts>

<!– Struts 2Action都必須配置在package –>

<package name=”default” extends=”struts-default”>

<!– 定義一個(gè)LogonAction,實(shí)現(xiàn)類為lee.Logon –>

<action name=”Logon” class=”lee.Logon”>

<!– 配置Action返回input時(shí)轉(zhuǎn)入/pages/Logon.jsp頁面 –>

<result name=”input”>/pages/Logon.jsp</result>

<!– 配置Action返回cancel時(shí)重定向到WelcomeAction–>

<result name=”cancel” type=”redirect-action”>Welcome</result>

<!– 配置Action返回success時(shí)重定向到MainMenuAction –>

<result type=”redirect-action”>MainMenu</result>

<!– 配置Action返回expired時(shí)進(jìn)入ChangePasswordAction –>

<result name=”expired” type=”chain”>ChangePassword</result>

</action>

<!– 定義LogoffAction,實(shí)現(xiàn)類為lee.Logoff –>

<action name=”Logoff” class=” lee.Logoff”>

<!– 配置Action返回success時(shí)重定向到MainMenuAction –>

<result type=”redirect-action”>Welcome</result>

</action>

</package>

</struts>

在上面的struts.xml文件中,定義了兩個(gè)Action。定義Action時(shí),不僅定義了Action的實(shí)現(xiàn)類,而且的定義Action的處理結(jié)果時(shí),指定了多個(gè)result,result元素指定execute方法返回值和視圖資源之間的映射關(guān)系。對(duì)于如下配置片段:

<result name=”cancel” type=”redirect-action”>Welcome</result>

表示當(dāng)execute方法返回cancel的字符串時(shí),跳轉(zhuǎn)到WelcomeAction。定義result元素時(shí),可以指定兩個(gè)屬性:typename。其中name指定了execute方法返回的字符串,而type指定轉(zhuǎn)向的資源類型,此處轉(zhuǎn)向的資源可以是JSP,也可以是FreeMarker等,甚至是另一個(gè)Action——這也是Struts 2可以支持多種視圖技術(shù)的原因。

除此之外,Struts 2還有一個(gè)配置Struts 2全局屬性的Properties文件:struts.properties。該文件的示例如下:

#指定Struts 2處于開發(fā)狀態(tài)

struts.devMode = false

//指定當(dāng)Struts 2配置文件改變后,Web框架是否重新加載Struts 2配置文件struts.configuration.xml.reload=true

正如上面見到的,struts.properties文件的形式是系列的key、value對(duì),它指定了Struts 2應(yīng)用的全局屬性。

3.3 Strut 2的標(biāo)簽庫

Struts 2的標(biāo)簽庫也是Struts 2的重要組成部分,Struts 2的標(biāo)簽庫提供了非常豐富的功能,這些標(biāo)簽庫不僅提供了表現(xiàn)層數(shù)據(jù)處理,而且提供了基本的流程控制功能,還提供了國際化、Ajax支持等功能。

通過使用Struts 2的標(biāo)簽,開發(fā)者可以最大限度地減少頁面代碼的書寫。

看下面的JSP頁面的表單定義片段:

<!–  定義一個(gè)Action –>

<form method=”post” action=”basicvalid.action”>

<!– 下面定義三個(gè)表單域 –>

    名字:<input type=”text” name=”name”/><br>

    年紀(jì):<input type=”text” name=”age”/><br>

    喜歡的顏色:<input type=”text” name=”favorite”/><br>

                                 <!– 定義一個(gè)輸出按鈕 –>

    <input type=”submit” value=”提交“/>

</form>

上面頁面使用了傳統(tǒng)的HTML標(biāo)簽定義表單元素,還不具備輸出校驗(yàn)信息的功能,但如果換成如下使用Struts 2標(biāo)簽的定義方式:

<!– 使用Struts 2標(biāo)簽定義一個(gè)表單 –>

<s:form method=”post” action=”basicvalid.action”>

<!– 下面使用Struts 2標(biāo)簽定義三個(gè)表單域 –>

<s:textfield label=”名字” name=”name”/>

<s:textfield label=”年紀(jì)” name=”age”/>

<s:textfield label=”喜歡的顏色” name=”answer”/>

<!– 定義一個(gè)提交按鈕 –>

<s:submit/>

</s:form>

則頁面代碼更加簡(jiǎn)潔,而且有更簡(jiǎn)單的錯(cuò)誤輸出。圖1.10是上面使用Struts 2標(biāo)簽執(zhí)行數(shù)據(jù)校驗(yàn)后的輸出。

1.10  使用Struts 2標(biāo)簽的效果

      提示:Struts 2的標(biāo)簽庫的功能非常復(fù)雜,該標(biāo)簽庫幾乎可以完全替代JSTL的標(biāo)簽庫。而且Struts 2的標(biāo)簽支持表達(dá)式語言,這種表達(dá)式語言支持一個(gè)強(qiáng)大和靈活的表達(dá)式語言:OGNLObject Graph Notation Language),因此功能非常強(qiáng)大。

3.4 Struts 2的控制器組件

Struts 2的控制器組件是Struts 2框架的核心,事實(shí)上,所有MVC框架都是以控制器組件為核心的。正如前面提到的,Struts 2的控制器由兩個(gè)部分組成:FilterDispatcher和業(yè)務(wù)控制器Action

實(shí)際上,Struts 2應(yīng)用中起作用的業(yè)務(wù)控制器不是用戶定義的Action,而是系統(tǒng)生成的Action代理,但該Action代理以用戶定義的Action為目標(biāo)。

下面是Struts 2Action代碼示例:

public class LoginAction

{

//封裝用戶請(qǐng)求參數(shù)的username屬性

private String username;

//封裝用戶請(qǐng)求參數(shù)的password屬性

private String password;

 //username屬性的getter方法

public String getUsername()

{

return username;

               }

//username屬性的setter方法

public void setUsername(String username)

{

this.username = username;

                        }

//password屬性的getter方法

public String getPassword()

{

return password;

               }

//password屬性的setter方法

public void setPassword(String password)

{

this.password = password;

                        }

//處理用戶請(qǐng)求的execute方法

public String execute() throws Exception

{

//如果用戶名為scott,密碼為tiger,則登錄成功

if (getUsername().equals(”scott” )

&& getPassword().equals(”tiger” ) )

{

return “success”;

                }

else

{

return “error”;

              }

       }

}

通過查看上面的Action代碼,發(fā)現(xiàn)該ActionWebWork中的Action更徹底,該Action無需實(shí)現(xiàn)任何父接口,無需繼承任何Struts 2基類,該Action類完全是一個(gè)POJO(普通、傳統(tǒng)的Java對(duì)象),因此具有很好的復(fù)用性。

歸納起來,該Action類有如下優(yōu)勢(shì):

?       Action類完全是一個(gè)POJO,因此具有很好的代碼復(fù)用性。

?       Action類無需與Servlet API耦合,因此進(jìn)行單元測(cè)試非常簡(jiǎn)單。

?       Action類的execute方法僅返回一個(gè)字符串作為處理結(jié)果,該處理結(jié)果可映射到任何的視圖,甚至是另一個(gè)Action。

4Struts 2Struts 1的對(duì)比

經(jīng)過上面簡(jiǎn)要介紹,不難發(fā)現(xiàn),Struts 2確實(shí)在Struts 1上做出了巨大的改進(jìn),的確是一個(gè)非常具有實(shí)用價(jià)值的MVC框架。          

Struts 1Struts 2在各方面的簡(jiǎn)要對(duì)比。

?       Action實(shí)現(xiàn)類方面的對(duì)比:Struts 1要求Action類繼承一個(gè)抽象基類;Struts 1的一個(gè)具體問題是使用抽象類編程而不是接口。Struts 2 Action類可以實(shí)現(xiàn)一個(gè)Action接口,也可以實(shí)現(xiàn)其他接口,使可選和定制的服務(wù)成為可能。Struts 2提供一個(gè)ActionSupport基類去實(shí)現(xiàn)常用的接口。即使Action接口不是必須實(shí)現(xiàn)的,只有一個(gè)包含execute方法的POJO類都可以用作Struts 2Action

?       線程模式方面的對(duì)比:Struts 1 Action是單例模式并且必須是線程安全的,因?yàn)閮H有Action的一個(gè)實(shí)例來處理所有的請(qǐng)求。單例策略限制了Struts 1 Action能做的事,并且要在開發(fā)時(shí)特別小心。Action資源必須是線程安全的或同步的;Struts 2 Action對(duì)象為每一個(gè)請(qǐng)求產(chǎn)生一個(gè)實(shí)例,因此沒有線程安全問題。

?       Servlet依賴方面的對(duì)比:Struts 1 Action依賴于Servlet API,因?yàn)?span>Struts 1 Actionexecute方法中有HttpServletRequestHttpServletResponse方法。Struts 2 Action不再依賴于Servlet API,從而允許Action脫離Web容器運(yùn)行,從而降低了測(cè)試Action的難度。 當(dāng)然,如果Action需要直接訪問HttpServletRequestHttpServletResponse參數(shù),Struts 2 Action仍然可以訪問它們。但是,大部分時(shí)候,Action都無需直接訪問HttpServetRequestHttpServletResponse,從而給開發(fā)者更多靈活的選擇。

?       可測(cè)性方面的對(duì)比:測(cè)試Struts 1 Action的一個(gè)主要問題是execute方法依賴于Servlet API,這使得Action的測(cè)試要依賴于Web容器。為了脫離Web容器測(cè)試Struts 1Action,必須借助于第三方擴(kuò)展:Struts TestCase,該擴(kuò)展下包含了系列的Mock對(duì)象(模擬了HttpServetRequestHttpServletResponse對(duì)象),從而可以脫離Web容器測(cè)試Struts 1Action類。Struts 2 Action可以通過初始化、設(shè)置屬性、調(diào)用方法來測(cè)試。

?       封裝請(qǐng)求參數(shù)的對(duì)比:Struts 1使用ActionForm對(duì)象封裝用戶的請(qǐng)求參數(shù),所有的ActionForm必須繼承一個(gè)基類:ActionForm。普通的JavaBean不能用作ActionForm,因此,開發(fā)者必須創(chuàng)建大量的ActionForm類封裝用戶請(qǐng)求參數(shù)。雖然Struts 1提供了動(dòng)態(tài)ActionForm來簡(jiǎn)化ActionForm的開發(fā),但依然需要在配置文件中定義ActionForm;Struts 2直接使用Action屬性來封裝用戶請(qǐng)求屬性,避免了開發(fā)者需要大量開發(fā)ActionForm類的煩瑣,實(shí)際上,這些屬性還可以是包含子屬性的Rich對(duì)象類型。如果開發(fā)者依然懷念Struts 1 ActionForm的模式,Struts 2提供了ModelDriven模式,可以讓開發(fā)者使用單獨(dú)的Model對(duì)象來封裝用戶請(qǐng)求參數(shù),但該Model對(duì)象無需繼承任何Struts 2基類,是一個(gè)POJO,從而降低了代碼污染。

?       表達(dá)式語言方面的對(duì)比:Struts 1整合了JSTL,因此可以使用JSTL表達(dá)式語言。這種表達(dá)式語言有基本對(duì)象圖遍歷,但在對(duì)集合和索引屬性的支持上則功能不強(qiáng);Struts 2可以使用JSTL,但它整合了一種更強(qiáng)大和靈活的表達(dá)式語言:OGNLObject Graph Notation Language),因此,Struts 2下的表達(dá)式語言功能更加強(qiáng)大。

?       綁定值到視圖的對(duì)比:Struts 1使用標(biāo)準(zhǔn)JSP機(jī)制把對(duì)象綁定到視圖頁面;Struts 2使用“ValueStack”技術(shù),使標(biāo)簽庫能夠訪問值,而不需要把對(duì)象和視圖頁面綁定在一起。

?       類型轉(zhuǎn)換的對(duì)比:Struts 1 ActionForm 屬性通常都是String類型。Struts 1使用Commons-Beanutils進(jìn)行類型轉(zhuǎn)換,每個(gè)類一個(gè)轉(zhuǎn)換器,轉(zhuǎn)換器是不可配置的;Struts 2使用OGNL進(jìn)行類型轉(zhuǎn)換,支持基本數(shù)據(jù)類型和常用對(duì)象之間的轉(zhuǎn)換。

?       數(shù)據(jù)校驗(yàn)的對(duì)比:Struts 1支持在ActionForm重寫validate方法中手動(dòng)校驗(yàn),或者通過整合Commons alidator框架來完成數(shù)據(jù)校驗(yàn)。Struts 2支持通過重寫validate方法進(jìn)行校驗(yàn),也支持整合XWork校驗(yàn)框架進(jìn)行校驗(yàn)。

?       Action執(zhí)行控制的對(duì)比:Struts 1支持每一個(gè)模塊對(duì)應(yīng)一個(gè)請(qǐng)求處理(即生命周期的概念),但是模塊中的所有Action必須共享相同的生命周期。Struts 2支持通過攔截器堆棧(Interceptor Stacks)為每一個(gè)Action創(chuàng)建不同的生命周期。開發(fā)者可以根據(jù)需要?jiǎng)?chuàng)建相應(yīng)堆棧,從而和不同的Action一起使用。

5WebWorkStruts 2對(duì)比

從某種程度上來看,Struts 2WebWork的升級(jí),而不是Struts 1的升級(jí),甚至在ApacheStruts 2的官方文檔都提到:WebWorkStruts 2是一次平滑的過渡。實(shí)際上,Struts 2.0其實(shí)是WebWork 2.3而已,從WebWork 2.2遷移到Struts 2.0不會(huì)比從WebWork 2.12.2更麻煩。

在很多方面,Struts 2僅僅是改變了WebWork下的名稱,因此,如果開發(fā)者具有WebWork的開發(fā)經(jīng)驗(yàn),將可以更加迅速地進(jìn)入Struts 2的開發(fā)領(lǐng)域。

下面是Struts 2WebWork命名上存在改變(見表1.1):

Struts 2成員

    WebWork成員

com.opensymphony.xwork2.*

    com.opensymphony.xwork.*

org.apache.Struts2.*

    com.opensymphony.webwork.*

struts.xml

    xwork.xml

struts.properties

    webwork.properties

Dispatcher  

    DispatcherUtil

org.apache.Struts2.config.Settings

    com.opensymphony.webwork.config.Configuration

1.1  Struts 2WebWork成員名稱的對(duì)應(yīng)

除此之外,Struts 2也刪除了WebWork中少量特性:

?       AroundInterceptorStruts 2不再支持WebWork中的AroundInterceptor。如果應(yīng)用程序中需要使用AroundInterceptor,則應(yīng)該自己手動(dòng)導(dǎo)入WebWork中的AroundInterceptor類。

?       副文本編輯器標(biāo)簽:Struts 2不再支持WebWork的富文本編輯器,如果應(yīng)用中需要使用富文本編輯器,則應(yīng)該使用Dojo的富文本編輯器。

?       IoC容器支持:Struts 2不再支持內(nèi)建的IoC容器,而改為全面支持SpringIoC容器,以SpringIoC容器作為默認(rèn)的Object工廠。

6. 總 結(jié)

本節(jié)課大致介紹了Web應(yīng)用的開發(fā)歷史,從歷史的角度介紹了Model 1Model 2的簡(jiǎn)要模型和特征,進(jìn)而介紹了MVC模式的主要策略和主要優(yōu)勢(shì)。接著介紹了常用的MVC框架,包括JSFTapestrySpring MVC,以及這些框架的基本知識(shí)和相關(guān)特征。本節(jié)重點(diǎn)介紹了Struts 2的兩個(gè)前身:Struts 1WebWork,以及這兩個(gè)框的架構(gòu)和主要特征,從而引申出對(duì)Struts 2起源的介紹。最后大致介紹了Struts 2框架的體系,包括Struts 2框架的架構(gòu)、標(biāo)簽庫、控制器組件等,并就Struts 1Struts 2的相關(guān)方面進(jìn)行了比較。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
基于mvc模式的struts框架概述
MVC基礎(chǔ)、Model2的MVC和Struts2的MVC
SSH框架總結(jié)(框架分析+環(huán)境搭建+實(shí)例源碼下載)
Struts2入門基礎(chǔ)
WebWork In Action學(xué)習(xí)筆記(一) WebWork的概貌 - 吾將上下而求索...
mayong--淺析struts 體系結(jié)構(gòu)與工作原理
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服