- Java EE實用教程
- 鄭阿奇編著
- 11191字
- 2018-12-30 08:34:17
2.5 程序文件詳解
流程清楚后,Struts 2運行的縱向概念就清楚了,下面詳細講解橫向知識。主要包括Struts 2中的Action、結果類型、struts.xml及struts.properties。
2.5.1 Action類應用詳解
從2.3 節的例子中的LoginAction類中可以看出,Struts 2 的Action可以是一個簡單的POJO(Plain Ordinary Java Object)類,但其實在實際應用中一般的自定義的Action類都會繼承Struts 2框架提供的ActionSupport類,下面具體介紹該類。
1.使用ActionSupport
繼承ActionSupport類能夠幫助程序員更好地完成一些工作,它實現了5 個接口并包含了一組默認的實現。如果編程中想要用到該類提供的某些功能,只要重寫它提供的方法就可以了,例如,要實現驗證功能,只需在自定義Action類中重寫validate()方法即可。
public class ActionSupport implements Action,Validateable,ValidationAware, TextProvider,LocaleProvider,Serializable{ }
從上面的代碼中可以看出ActionSupport實現了5個接口。下面簡要介紹這5個接口。
(1)Action接口:該接口提供了5個常量及一個execute()方法。代碼如下:
public interface Action{ public static final String SUCCESS="success"; public static final String NONE="none"; public static final String ERROR="error"; public static final String INPUT="input"; public static final String LOGIN="login"; public String execute()throws Exception; }
如果Action類繼承了ActionSupport類,就可以直接應用這幾個常量,比如在2.3 節例子中的Action的代碼:
package org.action; public class LoginAction{ ... public String execute(){ return"success"; //不做任何判斷直接返回“success” } }
就可以改為:
package org.action; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport{ ... public String execute(){ return SUCCESS; //不做任何判斷直接返回“success” } }
兩者具有同樣的效果。因為這幾個是在程序中經常用到的,所以Struts 2框架提供了這幾個常量,如果有需要,完全可以自定義返回值,只要在“struts.xml”的結果中對應就可以了。
(2)Validateable接口:該接口提供了一個validate()方法用于校驗表單數據,在實際應用中只要在Action類中重寫該方法即可。例如2.3 節例子中,并沒有對填入的數據進行任何判斷,即使用戶未輸入任何內容,提交后也會跳轉到歡迎界面,在一般情況下是不會允許的。這時就可以在Action類中重寫validate()方法,然后在該方法中對取得的數據進行判斷,如果為空或其他不允許的情況就可以保存錯誤信息。該方法是在執行execute()方法之前執行的。
(3)ValidationAware接口:該接口定義了一些方法用來對Action執行過程中產生的信息進行處理。例如,該接口中提供了addFieldError(String fieldname,String errorMessage)方法用來在驗證出錯時保存錯誤信息。
(4)TextProvider接口:該接口中提供了一系列getText()方法,用于獲得對應的國際化信息資源。在Struts 2中的國際化信息資源都是以key-value對出現的,通過使用該接口中的getText()方法可以用key來獲得相應的value值(國際化內容會在國際化部分講解)。
(5)LocaleProvider接口:該接口提供了一個getLocale()方法,用于國際化時獲得語言/地區信息。
2.Action傳值
在2.3節例子中的LoginAction代碼如下:
package org.action; public class LoginAction{ private String username; private String password; public String getUsername(){ return username; } public void setUsername(String username){ this.username=username; } public String getPassword(){ return password; } public void setPassword(String password){ this.password=password; } public String execute(){ return"success"; } }
其中有兩個屬性“username”和“password”,并且生成了它們的get和set方法。其實在運行login.jsp的時候,Struts 2框架會根據頁面的文本框名在Action類中尋找其set方法來對其進行賦值,例如,頁面的文本框為“username”的字段就會直接在Action類中找相應的setUsername(String username)方法為其賦值,而不是找其對應的在Action類中的屬性“username”,所以在Action類中的屬性名不一定要和頁面中的文本框名相對應,但是在Action類中必須是頁面的文本框名對應的set和get方法,而不是Action類中屬性的get和set方法。也就是說,在Action類中,username屬性可以不叫username,可以叫“name”或其他,但是里面必須有頁面的文本框名“username”對應的setUsername()方法,而不是setName()方法。但一般情況下,程序員都會把它們統一起來,讓Action類中的屬性就對應頁面中的輸入框名,這樣會方便很多。
前面這種傳值方式稱為字段傳值方式,如果一個表單中字段比較多,而在Action中就要寫很多字段,若在不同的Action中都要用到就要重復寫,這樣就會很麻煩,也不利于維護,所以Struts 2框架提供了另一種傳值方式即模型傳值方式。使用該傳值方式首先要把字段封裝成一個類,并生成其get和set方法,就是通常說的JavaBean了。如上例可把“username”和“password”封裝成一個“User”類,代碼如下:
package org.model; public class User{ private String username; private String password; public String getUsername(){ return username; } public void setUsername(String username){ this.username=username; } public String getPassword(){ return password; } public void setPassword(String password){ this.password=password; } }
然后在Action中就可以改變寫法:
package org.action; public class LoginAction{ private User user; public User getUser(){ return user; } public void setUser(User user){ this.user=user; } public String execute(){ return SUCCESS; } }
可以發現,這樣簡單了很多。還要注意的是,傳值頁面也就是JSP頁面(這里就是login.jsp頁面)的“屬性名”也要做小小的修改,要把以前的“屬性名”改為“模型對象名.屬性名”,例如這里要把以前的“<input type="text" name="username"/>”中的“username”及“<input type="password" name="password"/>”中的name值“password”修改為“user.username”和“user.passoword”,而歡迎界面的取值也要相應地修改為“user.username”。這樣修改后,再重新啟動Tomcat服務器,運行項目會得到相同的結果。
注意:當項目的“.java文件”或者一些配置文件如“*.xml”經過修改后,一定要重新啟動Tomcat服務器,而若修改了JSP頁面則只需刷新頁面即可。
3.在Action類中訪問Servlet API
學過Struts 1.x的都知道,Struts 1.x的Action類中的方法有4 個參數,其中有兩個是“request”及“response”,而Struts 2中卻沒有與任何的Servlet API關聯,這樣大大降低了程序的耦合性,但是有時候在寫程序時需要用到Servlet的一些API,例如“request”、“response”、“application”、“session”等。Struts 2 提供了兩種方式來訪問Servlet API:一種是通過ActionContext訪問Servlet API,另一種是通過實現*Aware()接口來獲得。
(1)通過ActionContext訪問:ActionContext類提供了一個靜態的getContext()方法來獲得ActionContext對象,然后根據其對象來獲得一些Servlet API的對象。例如:
ActionContext ac=ActionContext.getContext(); //獲得ActionContext對象 Map session=ac.getSession(); //獲得session對象 Map application=ac.getApplication(); //獲得application對象 Map request=ac.get(); //獲得request對象
大家可能有些奇怪,這些方法得到的都是Map類型,而不是要求的“HttpSession”或“Application”,其實Struts 2把Map對象模擬成了“HttpSession”等對象,從而將Servlet從Action中分離出來。
由于“request”和“response”比較特殊,也是在開發中經常會用到的,所以Struts 2提供了專門的類來獲取,即“ServletActionContext”。
HttpServletRequest request=ServletActionContext.getRequest(); //獲得HttpServletRequest對象 HttpServletResponse response=ServletActionContext.getResponse(); //獲得HttpServletResponse對象 HttpSession session=request.getSession(); //獲得HttpSession對象
除了這種方法外,還可以用如下方法得到:
ActionContext ac=ActionContext.getContext(); //獲得HttpServletRequest對象 HttpServletRequest request=(HttpServletRequest)ac.get(ServletActionContext.HTTP_REQUEST); //獲得HttpServletResponse對象 HttpServletResponse response=(HttpServletResponse)ac.get(ServletActionContext.HTTP_RESPONSE); //獲得HttpSession對象 HttpSession session=request.getSession();
(2)通過實現*Aware接口獲得:Struts 2中提過了一系列的*Aware接口,如表2.1所示。
表2.1 *Aware接口及獲得對象方法

例如要獲得Application對象,Action類就可以如下編寫:
import java.util.Map; import org.apache.struts2.interceptor.ApplicationAware; public class TestApplication implements ApplicationAware{ private Map application; public void setApplication(Map application){ this.application=application; } public String execute()throws Exception{ //...其他內容,這里可以直接應用application } }
4.Action類中返回多個結果
在一個Action類中,有時會返回多個結果,例如判斷一件事情,如果為真就返回SUCCESS,否則就返回ERROR(或"error")。在2.4 節的例子中,沒有對輸入的“username”和“password”做任何判斷,現在對其進行判斷,然后返回不同結果。
public String execute(){ if(user.getUsername().equals("李方方")&&user.getPassword().equals("123456")){ return SUCCESS; }else{ return ERROR; } }
這里判斷如果輸入的姓名為“李方方”且密碼為“123456”就返回成功,然后根據配置文件的返回跳轉到歡迎界面,如果兩者有一個不符合就返回錯誤頁面,所以還要在“struts.xml”配置文件中配置返回錯誤時跳轉的頁面,比如:
<action name="login"class="org.action.LoginAction"> <result name="success">/welcome.jsp</result> <result name="error">/login.jsp</result> </action>
這里設置如果返回錯誤跳轉到登錄界面。當然,在方法中可以返回很多的值(可以為任意字符串),但不管返回什么值,都要在配置文件中進行對應,而且不能返回兩個或幾個結果相同的值。對于繼承了ActionSupport的Action類可以返回前面提到的5個常量,該5個常量對應的字符串值前面已經講過,這里不再贅述。
5.Action類中定義多個方法
大家可以想象這樣一種情況:有一個用戶登錄,定義了一個LoginAction類,如果現在程序還需有一個注冊功能,是否還要定義一個RegistAction類呢?顯然這樣是可以的,但并不是最好的辦法。如果程序中功能越來越多,那就要定義越來越多的Action類,所以一般不采取這樣的方法,而是利用把相關的功能定義在同一個Action類中,這樣Action類就會有多個方法來實現不同的功能。
例如,在TestAction類中定義兩個方法:
import com.opensymphony.xwork2.ActionSupport; public class TestAction extends ActionSupport{ private String username; private String password; public String login()throws Exception{ if(username.equals("程明")){ return"login"; } else{ return ERROR; } } public String regist()throws Exception{ return"regist"; } }
這里暫時列舉在Action類中定義不同方法,并沒有說明請求時如何映射到具體的方法,不同的請求怎么對應相應的處理方法會在下節的action配置中講解。
2.5.2 <action>配置詳解
Struts 2的核心功能是Action。對于開發人員來說,使用Struts 2框架,主要的編碼工作就是編寫Action類。當開發好Action類后,就需要配置Action映射,以告訴Struts 2框架,針對某個URL的請求應該交由哪一個Action進行處理。這就是struts.xml中action配置要起的作用。在2.3節例子中:
<action name="login"class="org.action.LoginAction"> <result name="success">/welcome.jsp</result> </action>
上例表示請求名為“login”的請求,交由“org.action.LoginAction”這個類來處理,返回結果為“success”時就跳轉到“welcome.jsp”頁面。
1.<action>屬性
<action>有以下屬性:
name:該屬性是必需的,對應請求的Action的名稱。
class:該屬性不是必需的,指明處理類的具體路徑,例如“org.action.LoginAction”。
method:該屬性不是必需的,若Action類中有不同的方法,該屬性指定請求對應應用哪個方法。
converter:該屬性不是必需的,指定Action使用的類型轉換器(類型轉換內容會在類型轉換部分講解)。
在一般情況下,都會為<action>設置name和class屬性,如果沒有設置method屬性,系統會默認調用Action類中的execute方法。若在Action中存在多個方法,請求其某個方法的時候就要通過這里的method屬性來指定所請求的方法名。例如在2.5.1節中的第5點的Action類中有login和regist兩個方法,如果要在請求中應用login方法,就要在相應的action中配置method屬性:
<action name="login"class="org.action.LoginAction"method="login">
...
</action>
黑體部分就是要配置的指定的方法,表示應用LoginAction類中的login方法,如果是:
<action name="login"class="org.action.LoginAction"method="regist">
...
</action>
就應用LoginAction類中的regist方法。
2.在<action>中應用通配符
前面講過,可以在<action>中指定method屬性來決定應用Action類中的哪個方法,但這樣有些麻煩,應用兩個不同的方法就要配置兩個<action>,Struts 2中提供了通配符的使用,可以應用通配符只配置一個Action就可以根據通配符來識別應用Action類中的哪個方法。
<action>配置要修改為:
<action name="*"class="org.action.LoginAction"method="{1}"> ... </action>
其中“{1}”就是取前面的“*”的值。例如,如果要應用Action類中的login方法,請求就為:
<form action="login.action"method="post"> ... </form>
這樣用請求中“login”與action配置中的“*”匹配,得出“*”為“login”,<action>中method的值就為“login”,也就是應用Action類中的login方法。如果要應用regist方法,請求為:
<form action="regist.action"method="post"> ... </form>
“regist”就會與“*”匹配,得出“*”為“regist”,則<action>中method屬性的值就為“regist”,就會應用Action類中的regist方法。
不僅方法可以使用通配符這樣匹配,返回的值也可以。例如,如果應用login方法返回“error”時就讓其跳轉到“login.jsp”界面,而應用regist方法返回“error”時就跳轉到“regist.jsp”界面。<action>配置修改為:
<action name="*"class="org.action.LoginAction"method="{1}"> ... <result name="error">/{1}.jsp</result> </action>
使用通配符可以很大程度地減少struts.xml的配置內容,但是可以發現,在編寫時也會對Action類中的方法命名有限制,必須和請求名稱對應,返回視圖的名稱也同樣要對應。所以在實際開發中,可以根據實際情況來決定是否要使用通配符。
3.訪問Action類中方法的其他實現方式
仍以前面的LoginAction為例,該例中有兩個方法“login”和“regist”。首先訪問login方法,<action>配置可以用正常情況,只需配置name和class:
<action name="login"class="org.action.LoginAction"> ... </action>
在<action>配置中完全不知道要訪問LoginAction類中的哪個方法,但是需要在請求中指明,請求的form表單要改為:
<form action="login!login.action"method="post"> ... </form>
其中,“login!login.action”中“!”前面的“login”對應<action>中name屬性值,“!”后面的“login”對應要使用的LoginAction類中的方法名。例如,如果要使用該類中的regist方法,只需將請求改為:
<form action="login!regist.action"method="post"> ... </form>
該方法是在請求中指定應用Action類中的哪個方法,還有一種方法是在提交按鈕中設置的,<action>不用做任何改變,不過提交按鈕需要用Struts 2的標簽來實現,并且要指定method:
<form action="login.action"method="post"> ... <s:submit value="登錄"method="login"></s:submit> <s:submit value="注冊"method="regist"></s:submit> </form>
該form中有兩個按鈕,一個是登錄按鈕,另一個是注冊按鈕,分別都指定了它們各自要用的方法,不會產生沖突。這里大家只要知道這種方法就行了,Struts 2的標簽庫內容會在后面專門講解。
4.使用默認類
如果未指明class屬性,則系統將會自動引用<default-class-ref>標簽中所指定的類,即默認類。在Struts 2中,系統默認類為ActionSupport,當然也可以自己定義默認類,例如:
<package name="default"extends="struts-default">
<default-class-ref class="org.action.LoginAction"></default-class-ref>
<action name="login">
...
</action>
<action name="regist">
...
</action>
</package>
上面代碼中定義了默認類,則在兩個沒有指定class屬性的請求中都會應用該默認類,若指定了自己的class屬性,則默認類在該action中將不起作用。
2.5.3 <result>配置詳解
<result>是為Action類的返回值指定跳轉方向的,在Struts 2框架中,一個完整的<result>配置為:
<result name="Action類對應返回值"type="跳轉結果類型"> <param name="參數名">參數值</param> </result>
<result>包含兩個屬性name和type。name屬性與Action類中返回的返回值進行匹配,type屬性指定了將要跳轉的結果類型,在實際應用中不一定都要跳轉到一個頁面,有可能會從一個action跳轉到另一個action,這時就要指定type屬性。<param>是為返回結果設置參數的。
Struts 2中支持多種結果類型,在下載的Struts 2的struts-default.xml文件中可以找到所有的支持類型,該文件的位置在“struts-2.0.14\src\core\src\main\resources”下,打開該文件可以發現下面的代碼:
<result-types> <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/> <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult"default="true"/> <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/> <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/> <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/> <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/> <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/> <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/> <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/> <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult"/> <result-type name="redirect-action" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/> <result-type name="plaintext" class="org.apache.struts2.dispatcher.PlainTextResult"/> </result-types>
下面簡要介紹這些類型的作用范圍。
● chain:用來處理Action鏈。
● chart:用于整合JFreeChart的結果類型。
● dispatcher:用來轉向頁面,通常處理JSP,該類型也為默認類型。
● freemaker:處理FreeMarker模板。
● httpheader:控制特殊http行為的結果類型。
● jasper:用于JasperReports整合的結果類型。
● jsf:JSF整合的結果類型。
● redirect:重定向到一個URL。
● redirect-action:重定向到一個Action。
● stream:向瀏覽器發送InputStream對象,通常用來處理文件下載,還可用于返回AJAX數據。
● tiles:與Tiles整合的結果類型。
● velocity:處理Velocity模板。
● xslt:處理XML/XSLT模板。
● plaintext:顯示原始文件內容,例如文件源代碼等。
其實,<result>的兩個屬性都有默認值,如果沒有指明就是默認值,name屬性的默認值為“success”,type屬性的默認值為“dispatcher”,就是跳轉到JSP頁面。下面詳細講解幾個常用的結果類型。
1.dispatcher類型
該結果類型是默認的結果類型,從“struts-default.xml”中也可以看出,其定義為“default="true"”。定義該類型時,物理視圖為JSP頁面,并且該JSP頁面必須和請求信息處于同一個Web應用中。還有一點值得注意的是,請求轉發時地址欄不會改變,也就是說,屬于同一請求,所以請求參數及請求屬性等數據不會丟失,該跳轉類似于JSP中的“forward”。從前面的例子中也可以看出,跳轉到“welcome.jsp”頁面后,仍可以取出“username”的值。在應用該類型時,一般都會省略不寫。配置該類型后,<result>可以指定以下兩個參數。
● location:指定請求處理完成后跳轉的地址,例如“/welcome.jsp”。
● parse:指定是否允許在location參數值中使用表達式,例如“/welcome.jsp?username=${username}”,在實際運行時,這個結果信息會替換為用戶輸入的“username”值,該參數默認值是true。
2.redirect類型
該結果類型可以重定向到JSP頁面,也可以重定向到另一個Action。該類型是與dispatcher類型相對的,當Action處理用戶請求結束后,將重新生成一個請求,轉入另一個界面。例如在2.3 節的例子中,當用默認值“dispatcher”時,請求完成,轉向“welcome.jsp”界面,如圖2.12所示。

圖2.12 dispatcher類型時的跳轉界面
可以發現,請求沒變,還是“login.action”,但頁面已經跳轉到“welcome.jsp”,并且可以取出“username ”的值。如果把< result>中的內容改為:
<result name="success"type="redirect">/welcome.jsp</result>
則請求完成,轉向“welcome.jsp”界面,如圖2.13所示。

圖2.13 redirect類型重定向的界面
可以看出,轉向已經變為“welcome.jsp”界面,而且數據已經不能取出,表明請求參數及請求屬性等數據已經丟失。
配置redirect類型后,<result>也可指定location和parse兩個參數。
3.redirect-action類型
該結果類型與redirect類似,都是重定向而不是轉發,該類型一般都為了重定向到一個新的action請求,而非JSP頁面。配置該類型時,<result>可以配置如下兩個參數。
● actionName:該參數指定重定向的action名。
● namespace:該參數指定需要重定向的action所在的命名空間(命名空間會在后面講解)。
注意:這些參數是可選配置的,不是必需的,在實際情況中可以根據需要配置。
看下面一段代碼:
...
<package name="test1"extends="struts-default">
<action name="regist"class="org.action.LoginAction"method="regist">
<result name="success"type="redirect-action">
<param name="actionName">login</param>
<param name="namespace">/test2</param>
</result>
</action>
</package>
<package name="test2"extends="struts-default"namespace="/test2">
<action name="login"class="org.action.LoginAction"method="login">
<result name="success">/welcome.jsp</result>
</action>
</package>
...
上面代碼就是redirect-action類型應用的體現。首先對“test1”包中的“regist”進行請求,通過LoginAction類中的regist方法來處理請求,完成后用redirect-action結果類型來重新定向到“test2”包中的“login”,然后用LoginAction類中的login方法處理,完成后跳轉到“welcome.jsp”頁面,由于“test2”包指定了命名空間“namespace”,所以必須配置參數指定:
<param name="actionName">login</param> <param name="namespace">/test2</param>
分別指定重定向的action名及該action所在的命名空間。
4.chain類型
前面的redirect及redirect-action雖然都可以重定向到另外的action,但是它們都不能實現數據的傳遞,在重定向過程中,請求屬性等都會丟失,這樣有的時候就不利于編程了。所以,Struts 2又提供了另一種結果類型“chain”,用來實現action之間的跳轉,而非重定向,意思就是可以跳轉到另外的action而且數據不丟失,通過設置chain類型,可以組成一條action鏈,不用擔心數據的丟失,這樣就大大方便了編程。action跳轉可以共享數據的原理是處于同一個action鏈的action都共享同一個值棧,每個action執行完畢后都會把數據壓入值棧,如果需要就可以直接到值棧中取出。
5.全局結果
從前面的例子中可以看出,<result>都是包含在<action>...</action>中的,這配置的是局部結果,只對當前action請求返回的結果起作用。假如都返回到同一頁面,而且在不同的action請求中都會用到,那么配置局部結果就顯得唆了。所以,Struts 2提供了全局結果的配置,例如,如果返回“error”,都跳轉到錯誤頁面:
<?xml version="1.0"encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="default"extends="struts-default"> <global-results> <result name="error">/error.jsp</result> </global-results> <action name="login"class="org.action.LoginAction"> ... </action> <action name="test2"class="org.action.TestAction"> ... </action> </package> </struts>
上面代碼的黑體部分定義了一個全局結果,當用戶請求處理完成以后,如果返回“error”,就會到當前action配置的返回中尋找,如果沒有找到就會到全局結果中尋找。也就是說,局部結果配置的優先級大于全局結果。
2.5.4 <package>配置詳解
從前面的例子也可以看出,Struts 2的action都是放在<package>…</package>中。package元素用于定義struts.xml中的包配置,<package>中可以定義action和攔截器等。用package定義包配置時可以指定下面幾個屬性。
1.name
該屬性必須指定,代表包的名稱,由于struts.xml中可以定義不同的<package>,而且它們之間還可以互相引用,所以必須指定名稱。
2.extends
該屬性是可選的,表示當前定義的包繼承其他的包,繼承了其他包,就可以繼承其他包中的action、攔截器等。由于包信息的獲取是按照配置文件中的先后順序進行的,所以父包必須在子包之前被定義。
在一般情況下,定義包時都會繼承一個名為“struts-default”的包,該包是Struts 2內置的,定義在struts-default.xml這個文件中。這個文件的位置在前面講解<result>結果類型的時候已經說過,打開該文件找到這個包,可以發現該包下定義了一些結果類型、攔截器及攔截器棧,結果類型在前面已經講解,攔截器會在后面詳細講解。
3.namespace
該屬性是可選的,用來指定一個命名空間,例如在前面講redirect-action類型時已經用到了,定義命名空間非常簡單,只要指定“namespace="/*"”就行了,其中“*”是我們自定的,如果直接指定“"/"”,表示設置命名空間為根命名空間。如果不指定任何namespace,則使用默認的命名空間,默認的命名空間為“" "”。
當指定了命名空間后,相應的請求也要改變,例如:
<action name="login"class="org.action.LoginAction"namespace="/user"> ... </action>
請求就不能是“login.action”,而必須改為“user/login.action”。當Struts 2接收到請求后,會將請求信息解析為namespace名和action名兩部分,然后根據namespace名在struts.xml中查找指定命名空間的包,并且在該包中尋找與action名相同的配置,如果沒有找到,就到默認的命名空間中尋找與action名稱相同的配置,如果再沒找到,就給出錯誤信息。看下面的代碼:
<package name="default"> <action name="foo"class="org.TestAction"> <result name="success">/foo.jsp</result> </action> <action name="bar"class="org.TestAction"> <result name="success">/bar.jsp</result> </action> </package> <package name="mypackage1"namespace="/"> <action name="moo"class="org.TestAction"> <result name="success">/moo.jsp</result> </action> </package> <package name="mypackage2"namespace="/barspace"> <action name="bar"class="org.TestAction"> <result name="success">/bar.jsp</result> </action> </package>
如果頁面中請求為barspace/bar.action,框架將首先在命名空間為/barspace的包中查找bar這個action配置,如果找到了,則執行bar.action;如果沒有找到,則到默認的命名空間中繼續查找。在本例中,/barspace命名空間中有名為bar的Action,因此它會被執行。
如果頁面中請求為barspace/foo.action,框架會在命名空間為/barspace的包中查找foo這個action配置。如果找不到,框架會到默認命名空間中去查找。在本例中,/barspace名稱空間中沒有foo這個action,因此默認的命名空間中的/foo.action將會被找到并執行。
如果頁面中請求為moo.action,框架會在根命名空間“/”中查找moo.action,如果沒有找到,再到默認命名空間中查找。
4.abstract
該屬性是可選的,如果定義該包是一個抽象包,則該包不能包含<action>配置信息,但可以被繼承。
<package>主要包含以上4個屬性,<package>下面還可配置以下幾個標簽。
● <action>:action標簽,其作用前面已經詳細講解。
● <default-action-ref>:配置默認action,如果配置了默認action,則若請求的action名在包中找不到與之匹配的名稱就會應用默認action。
● <default-class-ref>:配置默認類。
● <default-interceptor-ref>:配置默認攔截器。
● <global-exception-mappings>:配置發生異常時對應的視圖信息,為全局信息,與之對應還有局部異常配置,局部異常配置要配置在<action>標簽中,局部異常配置用<exception-mapping>進行配置。配置異常信息格式如下:
<package name="default"extends="struts-default"> <global-exception-mappings> <exception-mapping result="邏輯視圖"exception="異常類型"/> </global-exception-mappings> <action name="action名稱"> <exception-mapping result="邏輯視圖"exception="異常類型"></exception-mapping> </action> </package>
<exception-mapping>中可以指定3 個屬性,分別為name:可選屬性,用來標識該異常配置信息;result:該屬性必須指定,指定發生異常時顯示的視圖信息,必須配置為邏輯視圖;exception:該屬性必須指定,用來指定異常類型。
● <global-results>:配置全局結果,前面已經講述。
● <interceptors>:配置攔截器。
● <result-types>:配置結果類型。
攔截器知識會在攔截器部分講解,讀者這里做個了解即可。
2.5.5 struts.xml文件
Struts 2.0.14版本下的struts.xml的大體格式如下:
<?xml version="1.0"encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> ... </struts>
在該版本下,這個格式是不變的,前面是編碼格式及一些頭文件信息,接著是<struts>…</struts>,該文件中的其他配置都包含在其中。該標簽下可以編寫下面幾個標簽。
● include:用于導入其他xml配置文件。
● constant:配置一些常量信息。
● bean:由容器創建并注入的組件。
● package:配置包信息。
這幾個標簽可以并排編寫在<struts>下,而其他一些配置大都配置在<package>中。由于package前面已經詳細講解,這里就不再講述,而bean標簽不常用,所以這節主要講解其他兩個標簽。
1.<include>
在實際開發中,可能大多數情況下會把所有的配置信息都放在一個struts.xml文件下,但這僅限于一些小的項目。如果一個項目很大,需要的配置信息就會很多,有可能成千上萬行的代碼,這么大一個配置文件,無論是管理還是維護都是相當不容易的,所以這時就要“分而治之”,把不同方面的信息分別編寫配置文件,例如在學生信息系統中,把學生信息的配置、課程信息的配置、成績信息的配置分別放入各自的配置文件xs.xml、kc.xml和cj.xml中,然后再用Struts 2提供的<include>標簽把它們導入到struts.xml中。
例如xs.xml為:
<?xml version="1.0"encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="xs"extends="struts-default"> <action name="addXs"class="org.action.XsAction"> ... </action> </package> </struts>
在struts.xml中導入應為:
<?xml version="1.0"encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <include file="xs.xml"></include> ... </struts>
這樣就成功導入了。
注意:這里xs.xml也是放在classes文件夾下的,即在MyEclipse中直接放在src下即可,如果xs.xml放在其他包中,例如放在“xs”包中,那么struts.xml中引入的時候就要加上包名:
<?xml version="1.0"encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <include file="/xs/xs.xml"></include> ... </struts>
2.<constant>
<constant>是用來在struts.xml中定義屬性的,例如設置編碼形式、設置開發模式等。該標簽里面有兩個屬性:name和value。例如,可以做下面的設置:
<struts> <!-- 設置開發模式 --> <constant name="struts.devMode"value="true"></constant> <!-- 設置編碼格式GB2312--> <constant name="struts.il8n.encoding"value="GB2312"></constant> ... </struts>
其中,name的值均為Struts 2的常量信息,這些常量信息并不多,不僅可以在struts.xml中設置,還可以在Struts 2的另一個配置文件struts.properties中單獨設置。下節將介紹該配置文件。
2.5.6 struts.properties文件
struts.properties文件是一個標準的properties文件,該文件中存放一系列的key-value對,每個key就是一個Struts 2屬性,而其對應的value值就是一個Struts 2的屬性值。struts.properties文件和struts.xml一樣,要放在項目的classes文件夾下,Struts 2框架會自動加載該文件。
通常情況下,項目并不需要這個配置文件,因為Struts 2框架已經提供了一個默認的配置文件default.properties,但是在開發中,有時為了方便可以更改默認信息,這時就要應用struts.properties,把要修改的屬性的key-value對放入其中,這樣新的配置信息就會覆蓋系統默認的值。struts.properties文件中所包含的所有屬性都可以在web.xml配置文件中使用“init-param”標簽進行配置,或者在struts.xml文件中使用“constant”標簽進行配置。
下面介紹Struts 2中常量配置信息:
● struts.action.extension:該屬性指定需要Struts 2處理的請求后綴,該屬性的默認值是action,即所有匹配*.action的請求都由Struts 2處理。如果用戶需要指定多個請求后綴,則多個后綴之間以英文逗號(,)隔開。
● struts.configuration:該屬性指定加載Struts 2配置文件的配置文件管理器。該屬性的默認值是org.apache.Struts2.config.DefaultConfiguration,這是Struts 2默認的配置文件管理器。如果需要實現自己的配置管理器,可以編寫一個實現Configuration接口的類,該類可以自己加載Struts 2配置文件。
● struts.configuration.files:該屬性指定Struts 2框架默認加載的配置文件,如果需要指定默認加載多個配置文件,則多個配置文件的文件名之間以英文逗號(,)隔開。該屬性的默認值為struts-default.xml,struts-plugin.xml,struts.xml。前面說過,Struts 2會自動加載struts.xml文件,這里就是最好的解釋。
● struts.configuration.xml.reload:該屬性設置當struts.xml文件改變后,系統是否自動重新加載該文件。該屬性的默認值是false。
● struts.custom.i18n.resources:該屬性指定Struts 2應用所需要的國際化資源文件,如果有多份國際化資源文件,則多個資源文件的文件名以英文逗號(,)隔開。
● struts.custom.properties:該屬性指定Struts 2應用加載用戶自定義的屬性文件,該自定義屬性文件指定的屬性不會覆蓋struts.properties文件中指定的屬性。如果需要加載多個自定義屬性文件,多個自定義屬性文件的文件名以英文逗號(,)隔開。
● struts.devMode:該屬性設置Struts 2應用是否使用開發模式。如果設置該屬性為true,則可以在應用出錯時顯示更多、更友好的出錯提示。該屬性只接受true和flase兩個值,該屬性的默認值是false。通常,應用在開發階段,將該屬性設置為true,當進入產品發布階段后,則該屬性設置為false。
● struts.dispatcher.parametersWorkaround:對于某些Java EE服務器,不支持HttpServlet Request調用getParameterMap()方法,此時可以設置該屬性值為true來解決該問題。該屬性的默認值是false。對于WebLogic、Orion和OC4J服務器,通常應該設置該屬性為true。
● struts.enable.DynamicMethodInvocation:該屬性設置Struts 2是否支持動態方法調用,該屬性的默認值是true。如果需要關閉動態方法調用,則可設置該屬性為false。
● struts.enable.SlashesInActionNames:該屬性設置Struts 2是否允許在Action名中使用斜線,該屬性的默認值是false。如果開發者希望允許在Action名中使用斜線,則可設置該屬性為true。
● struts.freemarker.manager.classname:該屬性指定Struts 2使用的FreeMarker管理器。該屬性的默認值是org.apache.struts2.views.freemarker.FreemarkerManager,這是Struts 2內建的FreeMarker管理器。
● struts.freemarker.wrapper.altMap:該屬性只支持true和false兩個屬性值,默認值是true。通常無須修改該屬性值。
● struts.i18n.encoding:指定Web應用的默認編碼集。一般當獲取中文請求參數值時會將該屬性值設置為GBK或者GB 2312。該屬性默認值為UTF-8。
● struts.i18n.reload:該屬性設置是否每次HTTP請求到達時,系統都重新加載資源文件(允許國際化文件重載)。該屬性默認值是false。在開發階段將該屬性設置為true會更有利于開發,但在產品發布階段應將該屬性設置為false。開發階段將該屬性設置了true,將可以在每次請求時都重新加載國際化資源文件,從而可以看到實時開發效果。產品發布階段將該屬性設置為false,是為了提高響應性能,每次請求都重新加載資源文件會大大降低應用的性能。
● struts.locale:指定Web應用的默認Locale。
● struts.multipart.parser:該屬性指定處理multipart/form-data的MIME類型(文件上傳)請求的框架,該屬性支持cos、pell和jakarta等屬性值, 即分別對應使用cos的文件上傳框架、pell上傳及common-fileupload文件上傳框架。該屬性的默認值為jakarta。
注意:如果需要使用cos或者pell的文件上傳方式,則應該將對應的JAR文件復制到Web應用中。例如,使用cos上傳方式,則需要自己下載cos框架的JAR文件,并將該文件放在WEB-INF/lib路徑下。
● struts.multipart.saveDir:該屬性指定上傳文件的臨時保存路徑,該屬性的默認值是javax.servlet.context.tempdir。
● struts.multipart.maxSize:該屬性指定Struts 2文件上傳中整個請求內容允許的最大字節數。
● struts.mapper.class:指定將HTTP請求映射到指定Action的映射器,Struts 2提供了默認的映射器org.apache.struts2.dispatcher.mapper.DefaultActionMapper。默認映射器根據請求的前綴與<action>配置的name屬性完成映射。
● struts.objectFactory:指定Struts 2默認的ObjectFactoryBean,該屬性默認值是spring。
● struts.objectFactory.spring.autoWire:指定Spring框架的自動裝配模式, 該屬性的默認值是name,即默認根據Bean的name屬性自動裝配。
● struts.objectFactory.spring.useClassCache:該屬性指定整合Spring框架時,是否緩存Bean實例,該屬性只允許使用true和false兩個屬性值,它的默認值是true。通常不建議修改該屬性值。
● struts.objectTypeDeterminer:該屬性指定Struts 2的類型檢測機制,支持tiger和notiger兩個屬性值。
● struts.serve.static:該屬性設置是否通過JAR文件提供靜態內容服務,該屬性只支持true和false屬性值,該屬性的默認屬性值是true。
● struts.serve.static.browserCache:該屬性設置瀏覽器是否緩存靜態內容。當應用處于開發階段時,如果希望每次請求都獲得服務器的最新響應,則可設置該屬性為false。
● struts.tag.altSyntax:該屬性指定是否允許在Struts 2標簽中使用表達式語法,因為通常都需要在標簽中使用表達式語法,故此屬性應該設置為true,該屬性的默認值是true。
● struts.url.http.port:該屬性指定Web應用所在的監聽端口。該屬性通常沒有太大的用戶,只是當Struts 2需要生成URL時(例如Url標簽),該屬性才提供Web應用的默認端口。
● struts.ui.theme:該屬性指定視圖標簽默認的視圖主題,該屬性的默認值是xhtml。
● struts.ui.templateDir:該屬性指定視圖主題所需要模板文件的位置,該屬性的默認值是template,即默認加載template路徑下的模板文件。
● struts.url.https.port:該屬性類似于struts.url.http.port屬性的作用,區別是該屬性指定的是Web應用的加密服務端口。
● struts.url.includeParams:該屬性指定Struts 2生成URL時是否包含請求參數。該屬性接受none、get和all三個屬性值,分別對應于不包含、僅包含GET類型請求參數和包含全部請求參數。
● struts.ui.templateSuffix:該屬性指定模板文件的后綴,該屬性的默認屬性值是ftl。該屬性允許使用ftl、vm或jsp,分別對應FreeMarker、Velocity和JSP模板。
● struts.velocity.configfile:該屬性指定Velocity框架所需的velocity.properties文件的位置。該屬性的默認值為velocity.properties。
● struts.velocity.contexts:該屬性指定Velocity框架的Context位置,如果該框架有多個Context,則多個Context之間以英文逗號(,)隔開。
● struts.velocity.toolboxlocation:該屬性指定Velocity框架的toolbox的位置。
● struts.xslt.nocache:該屬性指定XSLT Result是否使用樣式表緩存。當應用處于開發階段時,該屬性通常被設置為true。當應用處于產品使用階段時,該屬性通常被設置為false。
2.5.7 web.xml文件
在前面開發例子的過程中,首先就配置了web.xml,它是一個正規的xml文件,包括版本及編碼信息,然后就是<web-app>標簽。這里具體講解在<web-app>里面配置的信息。
… <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> …
這里面配置了一個過濾器,那么就先來介紹過濾器的使用。
Filter過濾器是Java項目開發中的一種常用技術。過濾器是用戶請求和處理程序之間的一層處理程序。這層程序可以對用戶請求和處理程序響應的內容進行處理。過濾器可以用于權限控制、編碼轉換等場合。
Servlet過濾器是在Java Servlet規范中定義的,它能夠對過濾器關聯的URL請求和響應進行檢查和修改。Servlet過濾器能夠在Servlet被調用之后檢查response對象,修改response Header對象和response內容。Servlet過濾器過濾的URL資源可以是Servlet、JSP、HTML文件,或者是整個路徑下的任何資源。多個過濾器可以構成一個過濾器鏈,當請求過濾器關聯的URL的時候,過濾器就會逐個發生作用。
所有過濾器必須實現java.Serlvet.Filter接口,這個接口中含有3個過濾器類必須實現的方法:
● init(FilterConfig):這是Servlet過濾器的初始化方法。Servlet容器創建Servlet過濾器實例后將調用這個方法。
● doFilter(ServletRequest,ServletResponse,FilterChain):這個方法完成實際的過濾操作。當用戶請求與過濾器關聯的URL時,Servlet容器將先調用過濾器的doFilter方法,返回響應之前也會調用此方法。FilterChain參數用于訪問過濾器鏈上的下一個過濾器。
● destroy():Servlet容器在銷毀過濾器實例前調用該方法。這個方法可以釋放Servlet過濾器占用的資源。
過濾器類編寫完成后,必須要在web.xml中進行配置,格式如下:
<filter> <!-- 自定義的名稱 --> <filter-name>過濾器名</filter-name> <!-- 自定義的過濾器類,注意,如果類放在指定包下,要加完整包名 --> <filter-class>過濾器對應類</filter-class> <init-param> <!-- 類中參數名稱 --> <param-name>參數名稱</param-name> <!-- 對應參數的值 --> <param-value>參數值</param-value> </init-param> </filter>
過濾器必須和特定的URL關聯才能發揮作用,過濾器的關聯方式有3種:與一個URL關聯、與一個URL目錄下的所有資源關聯、與一個Servlet關聯。
與一個URL資源關聯:
<filter-mapping> <!-- 這里與上面配置所起的名稱要相同 --> <filter-name>過濾器名</filter-name> <!-- 與該url資源關聯--> <url-pattern>xxx.jsp</url-pattern> </filter-mapping>
與一個URL目錄下的所有資源關聯:
<filter-mapping> <filter-name>過濾器名</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
與一個Servlet關聯:
<filter-mapping> <filter-name>過濾器名</filter-name> <url-pattern>Servlet名稱</url-pattern> </filter-mapping>
通過上面的講解,相信大家對web.xml文件中配置的內容已經很清楚了。Struts 2框架中的web.xml文件中配置的就是一個過濾器,其對應的類是Struts 2中的“org.apache.struts2. dispatcher.FilterDispatcher”,“url-pattern”指定為“/*”,表示該URL目錄下的所有請求都交由Struts 2處理,這就把Web應用與Struts 2框架關聯起來了。
- C++ Primer習題集(第5版)
- Elastic Stack應用寶典
- Scratch 3游戲與人工智能編程完全自學教程
- 老“碼”識途
- Hands-On Automation Testing with Java for Beginners
- 劍指Java:核心原理與應用實踐
- Getting Started with Hazelcast(Second Edition)
- Java網絡編程實戰
- 開源項目成功之道
- Learning Splunk Web Framework
- Xamarin Cross-Platform Development Cookbook
- Swift iOS Programming for Kids
- Python High Performance(Second Edition)
- Instant AutoIt Scripting
- 數據分析從入門到進階