一、Stuts的元素
1 web.xml
任何一個web應用程序都是基於請求響應模式進行構建的,所以無論采用哪種MVC框架,都離不開web.xml文件的配置.換句話說,web.xml並不是Struts2框架特有的文件,只有在Web應用中配置了web.xml文件,MVC框架才能真正地與Web應用融合起來.因此,web.xml文件是所有JavaWeb應用程序都需要的核心文件.
Struts2框架需要在web.xml中配置其核心控制器—StrutsPrepareAndExecuteFilter,用於對框架進行初始化,以及處理所有的請求.

StrutsPrepareAndExecuteFilter可以包含一些初始化參數,經常使用的如config——要加載的XML形式的配置文件列表(多個配置文件以逗號分隔,) 如果沒有設置這個參數,Struts2框架將默認加載struts-default.xml,struts-plugin.xml和struts.xml.
StrutsPrepareAndExecuteFilter作為一個Filter在Web應用中運行,它負責攔截所有的用戶請求,當用戶請求到達時,該Filter會過濾用戶請求.如果用戶請求以action結尾,該請求將被傳遞到Struts2框架進行處理.
2 Action
實際上,在MVC框架中,控制器是由兩個部分組成,分別如下:
- 核心過濾器(Filter):用於攔截用戶請求,對請求進行處理
- 業務控制器(Action):調用相應的Model類實現業務處理,返回結果.
對於開發人員來說,使用Struts2框架,主要的編碼工作就是編寫Action類,而自定義的Action需要實現com.opensymphony.xwork2.Action接口和繼承com.opensymphony.xwork2.ActionSupport類,Struts2並不要求編寫的Action類一定要實現Action接口,可以編寫一個普通的Java類作為Action類,只要該類含有一個返回字符串的無參的public方法即可.
在實際開發中,Action類通常都繼承自Struts2提供的com.opensymphony.xwork2.ActionSupport類,以便簡化開發.
3 Result
result元素的作用是實現結果視圖的調用,並決定視圖以哪種形式展現給客戶端.簡單地說,就是用來設定在Action處理結束后,系統下一步將要做什么.
Action類在處理完用戶操作后,會返回一個處理結果.這個結果是一個簡單字符串,框架根據這個字符串選擇對應的Result,所以我們又將其稱為邏輯視圖名稱.這個邏輯視圖名由result元素的name屬性來表示.result元素的值用來指定這個邏輯視圖對應的物理視圖資源的位置.需要特別指出的是,邏輯視圖名稱只有與物理視圖資源聯系在一起,才能發揮作用,所以必須要在配置文件中設置二者之間的對應關系.
通過對Struts2執行過程的分析,可以發現Struts2應用的整個過程都是按照請求/響應的過程執行的,如下圖:

1) 當Web服務器接收到請求之后,將請求交由web.xml中配置的struts2框架的核心過濾器StrutsPrepareAndExecuteFilter.
2) 由StrutsPrepareAndExecuteFilter確定請求對應的Action(業務控制器)
3) 框架根據Action返回的結果字符串,由StrutsPrepareAndExecuteFilter選擇對應的result,將結果呈現給用戶.
二、 Struts2的配置文件 struts.xml
1. constant元素
constant元素用於配置常量,通過常量的配置,可以改變Struts2框架的一些行為,從而滿足不同應用的需求.constant元素包含兩個屬性:其中name屬性表示常量的名稱,value表示常量的值.例如:
<constant name="struts.configuration.xml.reload" value="true" />
Struts2默認的常量配置在default.properties文件中,我們可以在struts.xml文件中進行修改:

常用的常量配置:
<!-- 常用的常量設置 --> <!--指定默認編碼,作用於HttpServletRequest的setCharacterEncoding() 方法 --> <constant name="struts.i18n.encoding" value="UTF-8" /> <!--設置瀏覽器是否緩存靜態內容,默認值為true(生產環境下使用),開發階段最好關閉 --> <constant name="struts.serve.static.browserCache" value="false" /> <!--設置struts配置文件修改后,系統是否自動重新加載該文件,,默認為false(生產環境下使用) ,開發階段最好打開 --> <constant name="struts.configuration.xml.reload" value="true" /> <!--開發模式下使用,這樣可以打印詳細的錯誤信息 --> <constant name="struts.devMode" value="true" /> <!--默認的視圖主題, 該Struts標簽的樣式 --> <constant name="struts.ui.theme" value="simple" /> <!--與spring整合時,指定由spring負責action對象的創建 --> <constant name="struts.objectFactory" value="spring" /> <!--該屬性設置Struts2是否支持動態方法調用,該屬性的默認值是true,如果需要關閉動態方法的調用,屬性為false --> <constant name="struts.enable.DynamicMethodInvocation" value="false" /> <!--上傳文件的大小限制 --> <constant name="struts.multipart.maxSize" value="10240000" /> <!-- 指定需要Struts2處理的請求后綴: 設置常量“struts.action.extension”進行修改, 多個后綴名,用逗號隔開 --> <constant name="struts.action.extension" value="do,action" />
2 package元素
<package name="default" namespace="/" extends="struts-default">
Struts2框架會把action,result等元素組織在一個名為package(包)的邏輯單元中.Struts的package很想java中的包,但與java包不同的是,Struts2中的包可以”繼承”已經定義好的包,
我們自定義的package要直接或間接的繼承 struts-default的包.
package的屬性:
- name 屬性:為必需並且唯一的,用來指定包的名稱,便於被其他包繼承
- extends屬性類似Java的extends關鍵字,指定繼承那個包
- namespace是一個可選屬性,該屬性定義該包中action的命名空間,如果沒有設置該屬性,則action被放入默認命名空間中.Struts2空間使用action的名稱和它所在包的命名空間來標識一個action,默認的命名空間用””表示,也可以使用”/”定義一個根命名空間,注意兩者是有區別的.如果請求Web應用程序路徑下的action,則框架在根命名空間中查找對應的action.

3.action元素
對於Struts2應用的開發者而言,Action才是應用的核心,開發者需要提供大量的Action類,並在struts.xml文件中配置Action.Action主要三個作用:
1.action最重要的作用是為給定的請求封裝需要做的實際工作(調用特定的業務處理類);
2.為數據的轉移提供場所
3.Action必須幫助框架決定由哪個結果呈現請求響應
Action元素的屬性:
1.method屬性
在之前的程序中,每實現一個功能都會去創建一個Action.並且完成相應的方法,那么是否可以在同一個Action中實現不同的功能呢?答案是可以的,那我們就需要使用到
action元素的method屬性實現在同一個Action中處理不同的請求。
package org.suke.struts.web.action; import com.opensymphony.xwork2.ActionSupport; /** * 一個Action可以包含多個請求處理方法 * @author Administrator * */ public class UserAction extends ActionSupport { /** * 處理登錄請求的方法 * @return */ public String login(){ return SUCCESS; } /** * 處理注冊請求的方法 * @return */ public String register(){ return SUCCESS; } }
struts.xml的配置

在上面的配置文件中,可以看到配置文件中分別定義了兩個action元素,每個action元素的name屬性是不同的,但是其指向的實現類的引用卻是相同的.那么,Struts2在接收請求后通過method屬性,
確定該執行同一個Action中哪一個方法,也就是說,如果用戶請求的是login.action,那么久調用UserAction的login()方法,如果是register.action,則調用register()方法。
2.動態調用DMI:
不使用method實現統一.
<action name="userAction" class="org.suke.struts.web.action.UserAction"> <result name="success">/index.jsp</result> </action>
然后再在index.jsp中定義如下鏈接:
<a href="<%=path %>/userAction!login.action">登錄</a><br> <a href="<%=path %>/userAction!register.action ">注冊</a><br>
注意查看上面的鏈接地址,它們都是針對UserAction,然后再加地上“!+UserAction中相應的方法名”,最后再寫上.action即可以訪問到統一頁面index.jsp。這樣做雖然能減少頁面,
但是由於它們實質用到的是同一個Action,所以這就意味着我們要使用的攔截器相同,相同的跳轉result。實際中這種方式很少使用,在此略作了解。
如果不想使用動態方法調用,我們可以通過常量來關閉,即在struts.xml中增加如下配置:
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>
3 .Action的通配符的使用
在配置<action../>元素時,需要指定name,class和method屬性,其中name屬性支持通配符,然后可以在method屬性使用表達式,通配符用”* ”表示.表示匹配任意的字符串。
<action name="*User" class="org.suke.struts.web.action.UserAction" method="{1}"> <result name="success">/{1}.jsp</result> </action>
在action元素的name屬性中使用星號,允許這個Action匹配所有以User結束的URI,如loginUser.action.配置該action元素時,還指定了method屬性,該屬性使用一個表達式{1},
該表達式的值就是name屬性值中第一個*的值.例如,當請求為loginUser.action時,通配符匹配的是login,那么這個值將替換{1},最終請求loginUser.action,將由UserAction的login()方法執行。
4. 配置默認的Action
如果請求一個不存在的Action,那么結果將會在頁面上呈現HTTP404錯誤,為了解決這個問題.Struts2框架允許指定一個默認的Action,即如果沒有一個Action匹配請求,那么默認的Action被執行.
<!-- 使用默認的action --> <default-action-ref name="defaultAction"></default-action-ref> <!-- 配置默認的action --> <action name="defaultAction"> <result>/error.jsp</result> </action>
5. Result的配置
1.Result的常用結果類型

以上對type類型作簡要的說明,下面來看實例:當一個Action處理后要返回的Result是另一個Action時,作如何配置,關鍵就是配置type類型。
步驟一:建立兩個Action:TestAction、Test2Action
步驟二:web.xml配置省略。struts.xml主要配置內容如下:
<package name="resultTest" extends="struts-default"> <action name="test" class="com.asm.TestAction"> <result name="success" type="chain"> <param name="actionName">test2</param> </result> </action> <action name="test2" class="com.asm.Test2Action"> <result name="success">/test2Suc.jsp</result> </action> </package>
說明:在名為“test”的action中,我們配置result元素的type類型值為chain,意為將繼續把Action傳遞到下一個名為test2的Action中去,在test2.action中會把頁面轉向到test2Suc.jsp中去。
在type類型為chain時,它的param有4個值可配,除了這里用到的name=”actionName”外(必須配置,否則報錯),還有name=namespace|method|skipActions。
其中namespace指定要轉向到action的名字空間,由於此處是轉到Action位於同一個namespace下,而namesapace的默認值the current namespace,
所以可以省略不寫(需要說明的是如果要跳到別的名稱空間的action中去,除了使用namespace指定外,還可以用:/要跳去action所在名稱空間的值/要跳去的action的name值)。
Method用於指定轉向到一個目標action所調用的方法,默認是調用下一個action的execute方法,所以此處仍可以省略。
SkipActions是一個可選的屬性,一般不用。具體可以參看chain所對應類的api幫助。
在本實例中,我們還在TestAction中設定一個username字段,並在execute方法執行為它賦了值,並在test2Suc.jsp中引用了此值。其實這種做法在web開發中還是很有用處,
比如可以代替隱藏域。需要注意的是之所以在action的傳遞中能把設定的這個值保存下去,主要是因為轉向都是服務器跳轉。
如果我們跳轉時采取了客戶端跳轉,也就是重定向,比如在test2 action的result中指定type類型為redirect,要想傳遞參數可以在result指向的jsp頁面中附加參數即可,我們可以在test2 action的result中寫成:
<result name="success" type="redirect">/test2Suc.jsp?username=${username}</result>
隨后在test2Suc.jsp頁面中引用時會出現三個問題:
1.EL表達式引用失效,(EL表達式應該使用${param.username}形式)。我們也可以使用<%=request.getParameter("username")%>獲取參數值。
2.由於在前面的TestAction中設定的值為中文,而附加到這里的uri請求的參數后面時會出現亂碼問題。(可以使用URI編碼再解碼解決此問題)
3.值棧取值失效:因為每一次request共享同一個值棧,所以服務器端的forward跳轉也是能共享同一值棧得。但是着當test action執行后把請求交由test2 action時,
test2 action采取的是redirect重定向到test2Suc.jsp頁面,這時其實就是重發的一次request,所以在test action保存的值棧內容全部失效。這也就是為什么我們要附加參數的原因。
而參數是保存在actionContext中,所以采用了#的方式來取出值。圖示說明:

2. 全局結果
之前我們配置的結果都在action元素的內部,這些結果不能被其他的Action使用,在一些情況下,多個Action可能需要訪問同一個結果,這時需要配置全局結果來滿足多個Action共享一個結果.
<!-- 配置全局的Result --> <global-results> <result name="success">/success.jsp</result> <result name="input" type="redirect">/login.jsp</result> </global-results>
全局結果同樣也使用result元素配置,與action配置result元素的區別在於:全局結果需要在global-results元素中嵌套result元素,如果在Action中的result元素名稱與全局結果的名稱相同時,
Action的result元素將會覆蓋全局result結果.也就是說:Action處理用戶請求結束后,會先在本Action中的result結果中搜索域邏輯視圖名隊員的結果,
只有當在Action中無法匹配與邏輯視圖名對應的結果時,才會去尋找全局結果並執行,
