Struts采用面向對象設計/ 將MVC模式"分離顯示邏輯和業(yè)務(wù)邏輯"的能力發(fā)揮得淋漓盡致/ 剛看完孫衛琴編著(zhù)的《精通structs:基于MVC的Java Web》一書(shū)/ 感覺(jué)寫(xiě)的很不錯/ 于是找了這篇文章貼出來(lái)/ 不過(guò)與那這篇文章像相比那本書(shū)可實(shí)惠的多了/。。。 淺析Struts 體系結構與工作原理 作者:務(wù)實(shí) 基本概念
Struts是Apache 基金會(huì )Jakarta 項目組的一個(gè)Open Source 項目,它采用MVC模式,能夠很好地幫助java 開(kāi)發(fā)者利用J2EE開(kāi)發(fā)Web應用。和其他的java架構一樣,Struts 也是面向對象設計,將MVC模式"分離顯示邏輯和業(yè)務(wù)邏輯"的能力發(fā)揮得淋漓盡致。Structs 框架的核心是一個(gè)彈性的控制層,基于如 Java Servlets,JavaBeans,ResourceBundles與XML等標準技術(shù),以及 Jakarta Commons 的一些類(lèi)庫。Struts有一組相互協(xié)作的類(lèi)(組件)、Serlvet以及jsp tag lib組成?;趕truts構架的web應用程序基本上符合JSP Model2的設計標準,可以說(shuō)是一個(gè)傳統 MVC設計模式的一種變化類(lèi)型。
Struts有其自己的控制器(Controller),同時(shí)整合了其他的一些技術(shù)去實(shí)現模型層(Model)和視圖層(View)。在模型層,Struts可以很容易的與數據訪(fǎng)問(wèn)技術(shù)相結合,如 JDBC / EJB ,以及其它第三方類(lèi)庫,如 Hibernate / iBATIS ,或者 Object Relational Bridge(對象關(guān)系橋)。在視圖層,Struts能夠與JSP,包括 JSTL 與 JSF,以及 Velocity 模板,XSLT 與其它表示層技術(shù)。 Struts 為每個(gè)專(zhuān)業(yè)的 Web 應用程序做背后的支撐,幫助為你的應用創(chuàng )建一個(gè)擴展的開(kāi)發(fā)環(huán)境。
Struts的體系結構與工作原理
MVC即Model-View-Controller的縮寫(xiě),是一種常用的設計模式。MVC 減弱了業(yè)務(wù)邏輯接口和數據接口之間的耦合,以及讓視圖層更富于變化。MVC的工作原理,如下圖1所示:
圖1
Struts 是MVC的一種實(shí)現,它將 Servlet和 JSP 標記(屬于 J2EE 規范)用作實(shí)現的一部分。Struts繼承了MVC的各項特性,并根據J2EE的特點(diǎn),做了相應的變化與擴展。Struts的體系結構與工作原理如下圖2所示:
 圖2
從圖2中我們可以知道,Struts的體系結構包括模型(Model),視圖(View)和控制器(Controller)三部分。
下面讓我們從MVC角度來(lái)看看struts的體系結構(Model 2)與工作原理:
1)模型(Model)
在Struts的體系結構中,模型分為兩個(gè)部分:系統的內部狀態(tài)和可以改變狀態(tài)的操作(事務(wù)邏輯)。內部狀態(tài)通常由一組ActinForm Bean表示。根據設計或應用程序復雜度的不同,這些Bean可以是自包含的并具有持續的狀態(tài),或只在需要時(shí)才獲得數據(從某個(gè)數據庫)。大型應用程序通常在方法內部封裝事務(wù)邏輯(操作),這些方法可以被擁有狀態(tài)信息的bean調用。比如購物車(chē)bean,它擁有用戶(hù)購買(mǎi)商品的信息,可能還有checkOut()方法用來(lái)檢查用戶(hù)的信用卡,并向倉庫發(fā)定貨信息。 小型程序中,操作可能會(huì )被內嵌在A(yíng)ction類(lèi),它是struts框架中控制器角色的一部分。當邏輯簡(jiǎn)單時(shí)這個(gè)方法很適合。 建議用戶(hù)將事務(wù)邏輯(要做什么)與Action類(lèi)所扮演的角色(決定做什么)分開(kāi)。
2)視圖(View)
視圖主要由JSP建立,struts包含擴展自定義標簽庫(TagLib),可以簡(jiǎn)化創(chuàng )建完全國際化用戶(hù)界面的過(guò)程。目前的標簽庫包括:Bean Tags、HTML tags、Logic Tags、Nested Tags 以及Template Tags等。
3)控制器(Controller)
在struts中,基本的控制器組件是ActionServlet類(lèi)中的實(shí)例servelt,實(shí)際使用的servlet在配置文件中由一組映射(由ActionMapping類(lèi)進(jìn)行描述)進(jìn)行定義。對于業(yè)務(wù)邏輯的操作則主要由Action、ActionMapping、ActionForward這幾個(gè)組件協(xié)調完成的,其中Action扮演了真正的業(yè)務(wù)邏輯的實(shí)現者,ActionMapping與ActionForward則指定了不同業(yè)務(wù)邏輯或流程的運行方向。struts-config.xml 文件配置控制器。
Struts體系結構中的組件
圖3
上圖3顯示了 ActionServlet (Controller)、ActionForm (Form State) 和 Action (Model Wrapper) 之間的最簡(jiǎn)關(guān)系。
體系結構中所使用的組件如下表:
| ActionServlet | 控制器 | | ActionClass | 包含事務(wù)邏輯 | | ActionForm | 顯示模塊數據 | | ActionMapping | 幫助控制器將請求映射到操作 | | ActionForward | 用來(lái)指示操作轉移的對象 | | ActionError | 用來(lái)存儲和回收錯誤 | | Struts標記庫 | 可以減輕開(kāi)發(fā)顯示層次的工作 |
Struts配置文件:struts-config.xml
Struts配置文件struts-config.xml,我們默認可以在目錄\WEB-INF\struts-config.xml找到這個(gè)文件。文件的配置包括全局轉發(fā)、ActionMapping類(lèi)、ActionForm bean 和JDBC數據源四個(gè)部分。
1)配置全局轉發(fā)
全局轉發(fā)用來(lái)在JSP頁(yè)之間創(chuàng )建邏輯名稱(chēng)映射。轉發(fā)都可以通過(guò)對調用操作映射的實(shí)例來(lái)獲得,例如: actionMappingInstace.findForward("logicalName");
全局轉發(fā)的例子:
<global-forwards> ?。糵orward name="bookCreated" path="/BookView.jsp"/> </global-forwards> |
| 屬性 | 描述 | | Name | 全局轉發(fā)的名字 | | Path | 與目標URL的相對路徑 |
2)配置ActionMapping
ActionMapping對象幫助進(jìn)行框架內部的流程控制,它們可將請求URI映射到Action類(lèi),并且將Action類(lèi)與ActionForm bean相關(guān)聯(lián)。ActionServlet在內部使用這些映射,并將控制轉移到特定Action類(lèi)的實(shí)例。所有Action類(lèi)使用perform()方法實(shí)現特定應用程序代碼,返回一個(gè)ActionForward對象,其中包括響應轉發(fā)的目標資源名稱(chēng)。例如:
<action-mappings> ?。糰ction path="/createBook" type="BookAction" name="bookForm" scope="request" input="/CreateBook.jsp"> ?。?action> ?。糵orward name="failure" path="/CreateBook.jsp"/> ?。糵orward name="cancel" path="/index.jsp"/> </action-mappings> |
| 屬性 | 描述 | | Path | Action類(lèi)的相對路徑 | | Name | 與本操作關(guān)聯(lián)的Action bean的名稱(chēng) | | Type | 連接到本映射的Action類(lèi)的全稱(chēng)(可有包名) | | Scope | ActionForm bean的作用域(請求或會(huì )話(huà)) | | Prefix | 用來(lái)匹配請求參數與bean屬性的前綴 | | Suffix | 用來(lái)匹配請求參數與bean屬性的后綴 | | attribute | 作用域名稱(chēng)。 | | className | ActionMapping對象的類(lèi)的完全限定名默認的類(lèi)是org.apache.struts.action.ActionMapping | | input | 輸入表單的路徑,指向bean發(fā)生輸入錯誤必須返回的控制 | | unknown | 設為true,操作將被作為所有沒(méi)有定義的ActionMapping的URI的默認操作 | | validate | 設置為true,則在調用Action對象上的perform()方法前,ActionServlet將調用ActionForm bean的validate()方法來(lái)進(jìn)行輸入檢查 |
通過(guò)<forward>元素,可以定義資源的邏輯名稱(chēng),該資源是Action類(lèi)的響應要轉發(fā)的目標。
| 屬性 | 描述 | | Id | ID | | ClassName | ActionForward類(lèi)的完全限定名,默認是org.apache.struts.action.ActionForward | | Name | 操作類(lèi)訪(fǎng)問(wèn)ActionForward時(shí)所用的邏輯名 | | Path | 響應轉發(fā)的目標資源的路徑 | | redirect | 若設置為true,則ActionServlet使用sendRedirect()方法來(lái)轉發(fā)資源 |
3)配置ActionForm Bean
ActionServlet使用ActionForm來(lái)保存請求的參數,這些bean的屬性名稱(chēng)與HTTP請求參數中的名稱(chēng)相對應,控制器將請求參數傳遞到ActionForm bean的實(shí)例,然后將這個(gè)實(shí)例傳送到Action類(lèi)。例子:
<form-beans> ?。糵orm-bean name="bookForm" type="BookForm"/> </form-beans> |
| 屬性 | 描述 | | Id | ID | | className | ActionForm bean的完全限定名,默認值是org.apache.struts.action.ActionFormBean | | Name | 表單bean在相關(guān)作用域的名稱(chēng),這個(gè)屬性用來(lái)將bean與ActionMapping進(jìn)行關(guān)聯(lián) | | Type | 類(lèi)的完全限定名 |
4)配置JDBC數據源
用<data-sources>元素可以定義多個(gè)數據源:
| 屬性 | 描述 | | Id | ID | | Key | Action類(lèi)使用這個(gè)名稱(chēng)來(lái)尋找連接 | | Type | 實(shí)現JDBC接口的類(lèi)的名稱(chēng) |
下面屬性需要<set-property>元素定義,在Struts 1.1版本中已不在使用,但你可用<data-source>元素。例如:
<data-sources> ?。糳ata-source id="DS1" key="conPool" type="org.apache.struts.util.GenericDataSource" ?。約et-property id="SP1" autoCommit="true" description="Example Data Source Configuration" driverClass="org.test.mm.mysql.Driver" maxCount="4" minCount="2" url="jdbc:mysql://localhost/test" user="struts" password="ghq123" /> ?。糳ata-source/> </data-sources> |
| 屬性 | 描述 | | desciption | 數據源的描述 | | autoCommit | 數據源創(chuàng )建的連接所使用的默認自動(dòng)更新數據庫模式 | | driverClass | 數據源所使用的類(lèi),用來(lái)顯示JDBC驅動(dòng)程序接口 | | loginTimeout | 數據庫登陸時(shí)間的限制,以秒為單位 | | maxCount | 最多能建立的連接數目 | | minCount | 要創(chuàng )建的最少連接數目 | | password | 數據庫訪(fǎng)問(wèn)的密碼 | | readOnly | 創(chuàng )建只讀的連接 | | User | 訪(fǎng)問(wèn)數據庫的用戶(hù)名 | | url | JDBC的URL |
通過(guò)指定關(guān)鍵字名稱(chēng),Action類(lèi)可以訪(fǎng)問(wèn)數據源,例如:
javax.sql.DataSource ds = servlet.findDataSource("conPool"); javax.sql.Connection con = ds.getConnection(); |
從struts的組件來(lái)看Struts 的工作原理
對于Struts 如何控制、處理客戶(hù)請求,讓我們通過(guò)對struts的四個(gè)核心組件介紹來(lái)具體說(shuō)明。這四個(gè)組件就是:ActionServlet、Action Classes,Action Mapping以及ActionFrom Bean。
1) Struts ActionServlet
ActionServlet繼承自javax.servlet.http.HttpServlet類(lèi),其在Struts 體系結構中扮演的角色失控制器,控制器ActionServlet主要負責將HTTP的客戶(hù)請求信息組裝后,根據配置文件的指定描述,轉發(fā)到適當的處理器。
按照Servelt的標準,所有得Servlet必須在web配置文件(web.xml)聲明。同樣,ActoinServlet必須在Web Application配置文件(web.xml)中描述。
當用戶(hù)向服務(wù)器端提交請求的時(shí)候,實(shí)際上信息是首先發(fā)送到控制器ActionServlet,一旦控制器獲得了請求,其就會(huì )將請求信息傳交給一些輔助類(lèi)(help classes)處理。這些輔助類(lèi)知道如何去處理與請求信息所對應的業(yè)務(wù)操作。在Struts中,這個(gè)輔助類(lèi)就是org.apache.struts.action.Action。通常開(kāi)發(fā)者需要自己繼承Aciton類(lèi),從而實(shí)現自己的Action實(shí)例。
2) Struts Action Classes
一個(gè)Action 類(lèi)的角色,就像客戶(hù)請求動(dòng)作和業(yè)務(wù)邏輯處理之間的一個(gè)適配器(Adaptor),其功能就是將請求與業(yè)務(wù)邏輯分開(kāi)。這樣的分離,使得客戶(hù)請求和Action類(lèi)之間可以有多個(gè)點(diǎn)對點(diǎn)的映射。而且Action類(lèi)通常還提供了其它的輔助功能,比如:認證(authorization)、日志(logging)和數據驗證(validation)。
3) Struts ActionMapping 將特定請求映射到特定Action的相關(guān)信息存儲在A(yíng)ctionMapping中,ActionServelt將ActionMapping傳送到Action類(lèi)的perform()方法,Action將使用ActionMapping的findForward()方法,此方法返回一個(gè)指定名稱(chēng)的ActionForward,這樣Action就完成了本地轉發(fā)。若沒(méi)有找到具體的ActionForward,就返回一個(gè)null。
4) Struts ActionForm Bean
一個(gè)應用系統的消息轉移(或者說(shuō)狀態(tài)轉移)的非持久性數據存儲,是由ActionForm Bean的負責保持的。
ActionForm的主要功能就是為Action的操作提供與客戶(hù)表單相映射的數據(如果在客戶(hù)指定的情況下,還包括對數據進(jìn)行校驗)。Action負責對系統數據狀態(tài)的保持,而Action則負責根據業(yè)務(wù)邏輯的需要,對數據狀態(tài)進(jìn)行修改,在改變系統狀態(tài)后,ActionForm則自動(dòng)的回寫(xiě)新的數據狀態(tài)并保持。
在A(yíng)ctionForm的使用中,Struts提倡使用到值對象。這樣將客戶(hù)或開(kāi)發(fā)人員,對數據狀態(tài)與對象狀態(tài)能夠更加清晰的理解和使用。
對于每一個(gè)客戶(hù)請求,Struts 體系結構在處理ActionForm的時(shí)候,一般需要經(jīng)歷如下幾個(gè)步驟:
?、?檢查Action的映射,確定Action中已經(jīng)配置了對ActionForm的映射;
?、?根據name屬性,查找form bean的配置信息;
?、?檢查Action的formbean的使用范圍,確定在此范圍下,是否已經(jīng)有此form bean的實(shí)例;
?、芗偃绠斍胺秶?,已經(jīng)存在了此form bean的實(shí)例,而是對當前請求來(lái)說(shuō),是同一種類(lèi)型的話(huà),那么就重用;
?、?否則,就重新構建一個(gè)form bean的實(shí)例;
?、辠orm bean的reset()方法備調用;
?、?調用對應的setter方法,對狀態(tài)屬性賦值;
?、?如果validatede的屬性北設置為true,那么就調用form bean的validate()方法。
如果validate()方法沒(méi)有返回任何錯誤,控制器將ActionForm作為參數,傳給Action實(shí)例的execute()方法并執行。 |