Struts2框架的基本使用


     前面已經介紹過了MVC思想,Struts2是一個優秀的MVC框架,大大降低了各個層之間的耦合度,具有很好的擴展性。從本篇開始我們學習Struts2的基本用法,本篇主要包括以下內容:

  • Struts2的下載安裝
  • 理解整個框架的運行流程
  • 自定義實現Action
  • 自定義配置處理結果

一、下載和安裝Struts2
     登錄Apache官網 http://struts.apache.org/download.cgi#struts23163 下載最新版本的Struts,當然建議下載2.3版本的,因為2.5版本剛出來,有些示例應用並不是很全。解壓壓縮包,得到Struts2的源碼及示例代碼。
這里寫圖片描述

apps目錄中主要是官方提供的Struts2的實例代碼,對於我們的學習是很有用的。docs中主要是有關Struts2的相關文檔內容。lib目錄中主要存放了有關Struts2的核心類庫,以及第三方插件庫。src中包含了Struts2的全部源代碼。

二、理解Struts2的運行流程
     下面演示一個完整的使用Struts2的實例,目的不是具體的代碼,重點在於理解整個框架的運作流程。首先我們需要從apps目錄中的struts2-blank示例項目中拷貝出整個lib目錄。(這是使用Struts2最基本的jar包,沒必要從Struts2的lib中一個一個找,因為你也不知道哪些是必需的),我們將他們導入到我們的項目中。

這里寫圖片描述

這是整個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,下面我們具體看看控制器的相關知識。

三、自定義實現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等對象。具體的大家可以自行研究。

四、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。

限於篇幅,未完待續。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM