Struts2是一個優秀的MVC框架,大大下降了各個層之間的耦合度,具備很好的擴展性。從本篇開始咱們學習Struts2的基本用法,本篇主要包括如下內容:html
Struts2的下載安裝web
理解整個框架的運行流程apache
自定義實現Actionsession
自定義配置處理結果app
1、下載和安裝Struts2
登陸Apache官網 htt p:// stru ts.apac he.org /dow nload. cgi#str uts2 31 63 下載最新版本的Struts,固然建議下載2.3版本的,由於2.5版本剛出來,有些示例應用並非很全。解壓壓縮包,獲得Struts2的源碼及示例代碼。框架
apps目錄中主要是官方提供的Struts2的實例代碼,對於咱們的學習是頗有用的。docs中主要是有關Struts2的相關文檔內容。lib目錄中主要存放了有關Struts2的核心類庫,以及第三方插件庫。src中包含了Struts2的所有源代碼。jsp
2、理解Struts2的運行流程
下面演示一個完整的使用Struts2的實例,目的不是具體的代碼,重點在於理解整個框架的運做流程。首先咱們須要從apps目錄中的struts2-blank示例項目中拷貝出整個lib目錄。(這是使用Struts2最基本的jar包,不必從Struts2的lib中一個一個找,由於你也不知道哪些是必需的),咱們將他們導入到咱們的項目中。ide
這是整個Struts2的請求和響應流程,下面看具體代碼中是如何體現的。函數
//web.xml,首先在web.xml中添加以下代碼,攔截全部請求,即全部請求如今所有歸Struts2框架管了<filter> <filter-name>struts</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class></filter><filter-mapping> <filter-name>struts</filter-name> <url-pattern>/*</url-pattern></filter-mapping>
//編寫Action充當控制器public class LoginAction extends ActionSupport { private String username; private String password; public String getUsername(){ return this.username; } public void setUsername(String s){ this.username = s; } public String getPassword(){ return this.password; } public void setPassword(String s){ this.password = s; } public String execute() throws Exception{ if(getUsername().equals("walker")&&getPassword().equals("yam")){ return SUCCESS; } return ERROR; } }
//新建Struts.xml文件用於配置框架<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"><struts> <package name="walker" extends="struts-default"> <action name="login" class="MyPackage.LoginAction"> <result name="error">/error.jsp</result> <result name="success">/index.jsp</result> </action> </package></struts>
/*login.jsp*/<html> <head> <title>login</title> </head> <body> <form method="post" action="login"> 姓名:<input type="text" name="username" /><br /> 密碼:<input type="password" name="password" /><br /> <input type="submit" value="提交"/> </form> </body></html>
咱們訪問login.jsp頁面,工具
提交以後會請求URL爲login的頁面,框架攔截器攔截,搜索Struts.xml中該URL所對應的Action控制器,轉向具體的控制器,在咱們寫的LoginAction控制器中,咱們獲取表單提交的參數並作簡單判斷,返回字符串success或者error給核心攔截器。核心攔截器讀取Struts.xml中的配置查找控制器返回的字符串對應的具體視圖位置,forward視圖頁面響應用戶。
這就是一個簡單的Struts2框架的請求和響應過程,能夠看到整個框架的核心是主攔截器和各類控制器Action,下面咱們具體看看控制器的相關知識。
3、自定義實現Action
在Action中使用實例變量來封裝請求的參數,正如上面的例子所示:咱們在login.jsp頁面提交的username和password兩個參數,對應於LoginAction中的兩個參數,在覈心攔截器跳轉LoginAction時,將兩個請求參數自動賦值給LoginAction的兩個實例變量。須要注意的是,對於LoginAction中的這兩個實例變量,是須要提供setter和geter方法的,咱們的核心攔截器在跳轉LoginAction的時候也是經過setter方法來對具體的實例參數進行賦值的。
咱們想要自定義xxxAction控制器,須要繼承Action接口,並實現其中的方法。
public interface Action { String SUCCESS = "success"; String NONE = "none"; String ERROR = "error"; String INPUT = "input"; String LOGIN = "login"; String execute() throws Exception; }
咱們能夠看到在Action接口中定義了幾個經常使用的字符串,這些字符串會被用於對應物理視圖位置,詳細的內容後文介紹。此處有一個execute方法,這個方法就相似於咱們JavaSE中的main方法,一旦核心攔截器攔截請求跳轉到Action頁面,會默認執行execute方法。細心的讀者可能發現,上述的例子中並無繼承Action接口,而是繼承了ActionSupport類。其實ActionSupport類仍是繼承了Action接口並實現了execute方法,只是ActionSupport類還爲咱們默認的實現了一些其餘的工具函數,方便咱們使用,因此基本上在自定義Action的時候會繼承ActionSupport類來減輕編碼難度。
Struts2中的Action沒有任何和Servlet API耦合的地方,也就是在Action控制器中沒有關於任何可直接操做Servlet API的接口調用。對於各個模塊之間的分離,Struts仍是作的很優秀的。那咱們在Action控制器中無法直接操做Servlet的一些對象,例如:request,response等,可是Struts2框架提供了一個工具類,能夠爲咱們提供這些對象。ActionContext:
static ThreadLocal<ActionContext> actionContext = new ThreadLocal();//經過靜態工廠建立ActionContext實例對象public static ActionContext getContext() { return (ActionContext)actionContext.get(); }//以map的形式設置application範圍內的共享數據public void setApplication(Map<String, Object> application)//獲取application範圍內的共享數據public Map<String, Object> getApplication()//以map的形式設置session範圍內的共享數據public void setSession(Map<String, Object> session)//獲取session範圍內的共享數據public Map<String, Object> getSession()//獲取request範圍內的指定的參數值public Object get(String key)//向request範圍內添加一個key-value的參數public void put(String key, Object value)//獲取request的全部請求參數public Map<String, Object> getParameters()//向request範圍內添加一批請求參數public void setParameters(Map<String, Object> parameters)
咱們每每經過ActionContext的靜態方法,經過本地線程ThreadLocal獲取ActionContext實例,此ActionContext封裝了有關Servlet操做的各類API調用方法。咱們看一個簡單的使用:
public class LoginAction extends ActionSupport { private String username; private String password; public String getUsername(){ return this.username; } public void setUsername(String s){ this.username = s; } public String getPassword(){ return this.password; } public void setPassword(String s){ this.password = s; } public String execute() throws Exception{ if(getUsername().equals("walker")&&getPassword().equals("yam")){ ActionContext ac = ActionContext.getContext(); ac.put("login","登陸成功"); return SUCCESS; } return ERROR; } }
<html> <head> <title></title> </head> <body> <p><%=request.getAttribute("login")%></p> <h1>this is the index page</h1> </body></html>
結果以下:
以上咱們演示瞭如何經過ActionContext 這個工具類來完成對Servlet API的調用。其實還可使用ServletActionContext這個工具類來直接獲取到原Servlet的pageContext,request,response等對象。具體的你們能夠自行研究。
4、Action的配置
以上咱們完成了對xxxAction控制器的編寫,可是若是想要咱們的核心攔截器可以在用戶請求URL時,找到對應的Action控制器,咱們須要學會在Struts.xml中配置。以前咱們介紹過,web.xml是用來配置整個web應用的,那麼咱們的struts.xml就是用來配置整個框架的。struts.xml應該被建立並放置在類的加載文件夾中,使用IDE的話,就建立在src文件夾下,在編譯的時候會被拷貝到WEB-INF/classes中。
對於上述的示例,該struts.xml中的內容以下:
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"><struts> <package name="walker" extends="struts-default"> <action name="login" class="MyPackage.LoginAction"> <result name="error">/error.jsp</result> <result name="success">/index.jsp</result> </action> </package></struts>
這裏的頭部的一些東西不必本身敲,依然從官方給的示例中拷貝便可。至於元素Struts中的內容纔是須要本身添加配置的。除去根元素,咱們看到的第一個元素是package ,在Struts中使用包來配置Action,也就是全部的Action都必須被配置在一個包下面,固然一個包中也是能夠配置多個Action的。
package元素中能夠配置如下屬性:
name:該屬性指定了該包的惟一標識,是必須屬性
extends:該屬性指定了該包能夠繼承別的包,固然別的包中的全部Action這裏都是可用的了,非必須屬性
namespace:該屬性指定了該包下的全部Action的命名空間,主要用於區分同名的Action,非必須屬性
abstract:指定了該包是一個抽象的包,抽象的包中是不能定義Action的,可是能夠有大量的類型定義、攔截器定義等
從上面給出的Struts.xml中,咱們能夠看出來,該包繼承了struts-default包,這是struts2-core-2.3.32.3.jar 中的文件,部份內容以下:
被聲明爲抽象包以後,其中就定義了一堆攔截器和類型,具體的咱們後面介紹,此處只須要知道,咱們能夠經過包的繼承了來繼承其餘包中的一些Action獲取攔截器。因爲該包是配置普通Action的基礎,因此通常咱們在自定義package的時候會繼承該包。
接下來咱們簡單看看namespace的使用,咱們在Struts.xml中能夠定義多個包,每一個包下面也是能夠定義多個Action的,那麼若是某兩個不一樣的包下面出現同名的Action,框架就天然沒法選擇調用哪一個Action來處理請求。若是咱們指定了命名空間,那麼在請求該包下的Action的時候,就須要帶上命名空間的值,這樣就能夠避免這種衝突。具體看以下例子:
<package name="walker" extends="struts-default" namespace="a"> <action name="login" class="MyPackage.LoginAction"> <result name="error">/error.jsp</result> <result name="success">/index.jsp</result> </action> </package>
<package name="yam" extends="struts-default" namespace="b"> <action name="login" class="MyPackage.LoginAction"> <result name="error">/error.jsp</result> <result name="success">/index.jsp</result> </action> </package>
咱們看這兩個包,他們下面配置了相同的Action,可是當時他們具備不一樣的命名空間,因此不會產生衝突。例如:咱們請求walker包下的login action的URL爲:
/a/login
而yam包下的login action的請求URL爲:
/b/login
以上咱們演示package包下的一些屬性的做用,須要注意一點的是:若是沒有指定namespace的值,則該包下的全部Action都處於默認的命名空間下,此處默認的命名空間和 namespace="/" 是有區別的,後者表示該包處於根命名空間下,而前者中則包含了全部沒有指定namespace值的包。若是框架在根命名空間或者別的命名空間下找不到指定的Action,則會前往默認命名空間下查找指定了Action。