對于Struts 如何控制、處理客戶請求,讓我們通過對struts的四個核心組件介紹來具體說明。這幾個組件就是:ActionServlet、Action Classes、Action Mapping(此處包括ActionForward)、ActionForm Bean。
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實例。
ActionServlet把全部提交的請求都被控制器委托到RequestProcessor對象。RequestProcessor使用struts-config.xml文件檢查請求URI找到動作Action標示符。
一個Action 類的角色,就像客戶請求動作和業務邏輯處理之間的一個適配器(Adaptor),其功能就是將請求與業務邏輯分開。這樣的分離,使得客戶請求和Action類之間可以有多個點對點的映射。而且Action類通常還提供了其它的輔助功能,比如:認證(authorization)、日志(logging)和數據驗證(validation)。
Action最為常用的是execute()方法。(注意,以前的perform方法在struts1.1中已經不再支持),還有一個execute()方法,請參考apidoc,在此不在說明。
public ActionForward execute(ActionMapping mapping,
ActionForm form,
javax.servlet.ServletRequest request,
javax.servlet.ServletResponse response)
throws java.io.IOException,javax.servlet.ServletException
當Controller收到客戶的請求的時候,在將請求轉移到一個Action實例時,如果這個實例不存在,控制器會首先創建,然后會調用這個Action實例的execute()方法。Struts Framework為應用系統中的每一個Action類只創建一個實例。因為所有的用戶都使用這一個實例,所以你必須確定你的Action 類運行在一個多線程的環境中。下圖顯示了一個execute()方法如何被訪問:
注意,客戶自己繼承的Action子類,必須重寫execute()方法,因為Action類在默認情況下是返回null的。
上面講到了一個客戶請求是如何被控制器轉發和處理的,但是,控制器如何知道什么樣的信息轉發到什么樣的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>
上面的配置表示:當可以通過/logonAction.do(此處假設配置的控制器映射為*.do)提交請求信息的時候,控制器將信息委托com.test.LogonAction處理。調用LogonAction實例的execute()方法。同時將Mapping實例和所對應的LogonForm Bean信息傳入。其中name=LogonForm,使用的form-bean元素所聲明的ActionForm Bean。有關form-bean的申明如下顯示。
<form-beans>
<form-bean name="LoginForm"
type="com.test.LoginForm"/>
</form-beans>
元素<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>
在上面講解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()方法,并不能實現什么處理功能,所以有必要自己重新覆蓋。
posted on 2006-03-05 15:10
★yesjoy★ 閱讀(351)
評論(0) 編輯 收藏 所屬分類:
Structs學習