Struts 工作原理

struts framework的工作原理和組件

對於struts 如何控制、處理客戶請求,讓我們通過對struts的四個核心組件介紹來具體說明。這幾個組件就是:actionservlet。action classes,action mapping(此處包括actionforward),actionfrom bean。

struts actionservlet控制器對象

       actionservlet繼承自javax.servlet.http.httpservlet類,其在struts framework中扮演的角色是中心控制器。它提供一箇中心位置來處理全部的終端請求。控制器actionservlet主要負責將http的客戶請求信息組裝後,根據配置文件的指定描述,轉發到適當的處理器。

       按照servelt的標準,所有得servlet必須在web配置文件(web.xml)聲明。同樣,actoinservlet必須在web application配置文件(web.xml)中描述,有關配置信息如下。

<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.actionservlet</servlet-class>
</servlet>

全部的請求uri以*.do的模式存在並映射到這個servlet,其配置如下:

<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

一個該模式的請求uri符合如下格式: 

              http://www.my_site_name.com/mycontext/actionname.do


中心控制器爲所有的表示層請求提供了一個集中的訪問點。這個控制器提供的抽象概念減輕了開發者建立公共應用系統服務的困難,如管理視圖、會話及表單數據。它也提供一個通用機制如錯誤及異常處理,導航,國際化,數據驗證,數據轉換等。

當用戶向服務器端提交請求的時候,實際上信息是首先發送到控制器actionservlet,一旦控制器獲得了請求,其就會將請求信息傳交給一些輔助類(help classes)處理。這些輔助類知道如何去處理與請求信息所對應的業務操作。在struts中,這個輔助類就是org.apache.struts.action.action。通常開發者需要自己繼承aciton類,從而實現自己的action實例。

struts action classes 
       actionservlet把全部提交的請求都被控制器委託到requestprocessor對象。requestprocessor使用struts-config.xml文件檢查請求uri找到動作action標示符。

一個action 類的角色,就像客戶請求動作和業務邏輯處理之間的一個適配器(adaptor),其功能就是將請求與業務邏輯分開。這樣的分離,使得客戶請求和action類之間可以有多個點對點的映射。而且action類通常還提供了其它的輔助功能,比如:認證(authorization)、日誌(logging)和數據驗證(validation)。

public actionforward execute(actionmapping mapping,
                           actionform form,
                             javax.servlet.servletrequest request,
                             javax.servlet.servletresponse response)
                      throws java.io.ioexception,javax.servlet.servletexception

       action最爲常用的是execute()方法。(注意,以前的perform方法在struts1.1中已經不再支持),還有一個execute()方法,請參考apidoc,在此不在說明。
       當controller收到客戶的請求的時候,在將請求轉移到一個action實例時,如果這個實例不存在,控制器會首先創建,然後會調用這個action實例的execute()方法。struts framework爲應用系統中的每一個action類只創建一個實例。因爲所有的用戶都使用這一個實例,所以你必須確定你的action 類運行在一個多線程的環境中。下圖顯示了一個execute()方法如何被訪問:

action實例的execute()方法

注意,客戶自己繼承的action子類,必須重寫execute()方法,因爲action類在默認情況下是返回null的。
struts action mapping


上面講到了一個客戶請求是如何被控制器轉發和處理的,但是,控制器如何知道什麼樣的信息轉發到什麼樣的action類呢?這就需要一些與動作和請求信息相對應的映射配置說明。在struts 中,這些配置映射信息是存儲在特定的xml文件(比如struts-config.xml)。 
這些配置信息在系統啓動的時候被讀入內存,供struts framework在運行期間使用。在內存中,每一個<action>元素都與org.apache.struts.action.actionmapping類的一個實例對應。下表就顯示了一個登陸的配置映射。

<action-mappings>
  <action  path="/logonaction"
           type="com.test.logonaction"
           name="logonform"
           scope="request"
           input="logoncheck.jsp"
validate="false">
<forward name="welcome" path="/welcome.jsp"/>
<forward name="failure" path="/logon_failure.jsp "/>
</action>
</action-mappings>
<form-beans>
  <form-bean  name="loginform"
type="com.test.loginform"/>
</form-beans>

上面的配置表示:當可以通過/logonaction.do(此處假設配置的控制器映射爲*.do)提交請求信息的時候,控制器將信息委託com.test.logonaction處理。調用logonaction實例的execute()方法。同時將mapping實例和所對應的logonform bean信息傳入。其中name=logonform,使用的form-bean元素所聲明的actionform bean。有關form-bean的申明如下顯示。

使用actionforward導航

元素<forward>則表示了當action實例的execute()方法運行完畢或,控制器根據mapping可將響應信息轉到適當的地方。如上面現實,如果客戶登陸成功,則調用welcome forward,將成功信息返回到/welcome.jsp頁面。在你的execute()方法的結尾可以使用下面的實例代碼而返回welcome forward。當然你的welcome forward必須在action元素屬性中定義,正如上面所聲明的那樣。

return (mapping.findforward("welcome"));

       actionforward對象是配置對象。這些配置對象擁有獨一無二的標識以允許它們按照有意義的名稱如“success”,“failure”等來檢索。actionforward對象封裝了向前進的url路徑且被請求處理器用於識別目標視圖。actionforward對象建立自<forward>元素位於struts-config.xml。下面是一個struts中<forward>元素例子,屬於<action>元素範圍。
<action path="/editcustomerprofile"
type="packagename.editcustomerprofileaction"
name="customerprofileform" scope="request">
<forward name="success" path="/mainmenu.jsp"/>
<forward name="failure" path="/customerservice.jsp"/>
</action>

       基於執行請求處理器的execute(…)方法的結果,當傳遞一個值匹配指定於<forward>元素中name屬性的值的時候,下一個視圖可以在execute(…)方法中被開發者用方便的方法org.apache.struts.action.actionmapping.findforward(…)選擇。actionmapping.findforward(…)方法既從它的本地範圍又從全局範圍提供一個actionforward對象,該對象返回至requestprocessor以requestdispatcher.forward(…)或response.sendredirect(…)調用下一個視圖。當<forward>元素有redirect=“false”屬性或redirect屬性不存在的時候,requestdispatcher.forward(…)被執行;當redirect=“true”是,將調用sendredirect(…)方法。下例舉例說明了redirect屬性的用法:

         <forward name="success" path="/catalog.jsp" redirect="true"/>

如果redirect=true, url建立如/contextpath/path因爲httpservletresponse.sendredirect(…)中解釋url採用”/”開頭相對於servlet容器根目錄。
如果redirect=false, uri建立如/path因爲servletcontext.getrequestdisptacher(…)採用虛擬目錄相關url。

在此稍稍說一下有關global-forwards的概念。其在配置文件中描述了整個應用系統可以使用的actionforward,而不是僅僅是一個特定的action。
  <global-forwards>
    <forward name="logout" path="/logout.do"/>
<forward name="error"  path="/error.jsp"/>
  </global-forwards>

struts actionform bean捕獲表單數據

在上面講解actionservlet,action classes和action mapping的時候,我們都提到了actionform bean的概念。一個應用系統的消息轉移(或者說狀態轉移)的非持久性數據存儲,是由actionform bean的負責保持的。
       actionform派生的對象用於保存請求對象的參數,因此它們和用戶緊密聯繫。
       一個actionform類被requestprocessor建立。這是發生在已完成向前進到一個url,該url爲映射到控制器servlet而不是jsp和相應的動作映射指定的表單屬性的。在這個情況下,如果沒有在指定的活動範圍內找到,requestprocessor將嘗試尋找可能導致創建一個新actionform對象的表單bean。該actionform對象在指定的活動範圍內被用<action>元素的name屬性找到;

requestprocessor將隨後重新安排表單屬性,用請求時參數填充表單,隨即調用表單對象的validate(…)方法以履行服務器端用戶輸入驗證。僅當actionmapping對象中validate屬性被設爲true時,validate(…)方法被調用;這就是默認的行爲。request.getparametervalues(parametername)被用於得到一個string[]對象,它用來表單填充;驗證的結果應該是一個actionerrors對象,用org.apache.struts.taglib.html.errorstag來顯示驗證錯誤給用戶。actionform也可以被用於爲當前用戶保存即將被一個視圖引用的中間模型狀態。

當一個表單對象被requestprocessor找到,它被傳遞到請求處理器的execute(…)方法。一個actionform對象也可以被請求處理器建立。表單對象建立目的是提供中間模型狀態給使用請求範圍jsp;這將確保對象不會在有效性過期後仍然存在。默認的,所有的表單都被保存爲會話範圍。會話中表單對象脫離有效性的存在可能導致浪費內存,同樣的,請求處理器必須跟蹤保存在會話中的表單對象的生命週期。一個好的捕獲表單數據的實踐是爲橫跨多用戶交互的相關表單用一個單獨的表單bean。表單bean也可以在反饋的時候用來儲存能夠被自定義標籤改變的中間模型狀態。在視圖中標籤用法避免結合java代碼,因此要成一個好的任務劃分,web生產組主要處理標誌,而應用開發組主要處理java代碼。標籤因素退出訪問中間模型狀態的邏輯;當訪問嵌套的對象或當通過聚集列舉時這個邏輯可能很複雜。
注意:在struts1.1中,actionform的校驗功能,逐漸被剝離出來(當然依然可以使用)。使用了validator framework對整個應用系統的表單數據驗證進行統一管理。相信信息請參考:http://home.earthlink.net/~dwinterfeldt
在actionform的使用中,struts提倡使用到值對象(value object)。這樣將客戶或開發人員,對數據狀態與對象狀態能夠更加清晰的理解和使用。
對於每一個客戶請求,struts framework在處理actionform的時候,一般需要經歷如下幾個步驟:

(1)檢查action的映射,確定action中已經配置了對actionform的映射
(2)根據name屬性,查找form bean的配置信息
(3)檢查action的formbean的使用範圍,確定在此範圍下,是否已經有此form bean的實例。
(4)假如當前範圍下,已經存在了此form bean的實例,而是對當前請求來說,是同一種類型的話,那麼就重用。
(5)否則,就重新構建一個form bean的實例
(6)form bean的reset()方法備調用
(7)調用對應的setter方法,對狀態屬性賦值
(8)如果validatede的屬性北設置爲true,那麼就調用form bean的validate()方法。
(9)如果validate()方法沒有返回任何錯誤,控制器將actionform作爲參數,傳給action實例的execute()方法並執行。

注意:直接從actionfrom類繼承的reset()和validate()方法,並不能實現什麼處理功能,所以有必要自己重新覆蓋。

struts的其他組件

       struts framework本身提供了很多可擴展的組件或sub framework,方便的開發人員在其構架上構建web層的應用系統。比如upload,collections ,logging等等。讓我們來看看兩個比較重要的組件:validationg framework和struts taglib。有關其他組件請參考struts用戶手冊(http://jakarta.apache.org/struts/userguide)。
validation framework for struts
在struts1.1中,新增了validation framework。增加了對form數據提交的驗證。將原本需要在actionfrom bean的validate()進行的驗證通過配置文件的描述進行驗證。
有關其詳細信息,請參考http://home.earthlink.net/~dwinterfeldt 。個人建議對於小型應用系統可以採用這種配置方式,但是對於應用系統中有大量web層表單應用的系統,並且業務需求變動比較大的,使用validation framework 可能會加重開發難度、系統維護難度。可以借鑑validation framework的javascript validator tag。
struts taglib
       struts提供了一組可擴展的自定義標籤庫(taglib),可以簡化創建用戶界面的過程。目前包括:bean tags,html tags,logic tags,nested tags,template tags 這幾個taglib。有關struts taglib的結構和使用,可以參考前面有關cutomer tag lib的介紹,有關起詳細資料,請參考
beanutils 
       這個組件的全稱是bean introspection utilites。是屬於jakarta commons項目組的。主要是幫助構建javabean的屬性操作的(getter,setter),已經提供一種動態定義和訪問bean的屬性。有關詳細信息,請參考。
http://jakarta.apache.org/commons/beanutils.html
       如果各位對這方面有很興趣,可以參考一些有關java反射(reflectio)方面的資料。

collections

       這個組件主要是提供了一些集合或列表對象,在原有的java collections framework的基礎上進行了擴展。詳細資料請參考:
http://jakarta.apache.org/commons/collections.html 以及
http://cvs.apache.org/viewcvs/~checkout~/jakarta-commons/collections/status.html?rev=1.13
digester

     這個組件翻譯成中文的意思是“彙編”。其主要功能是根據xml配置文件,初始化系統的一些java類對象。digester幫助你指定xml與java對象之間映射模型,而且允許客戶話定製映射規則(rules)。詳細資料請參考
http://jakarta.apache.org/commons/digester.html

發佈了0 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章