(轉)ActionContext和ServletActionContext

前面已經瞭解到ActionContext是Action執行時的上下文,裏面存放着Action在執行時須要用到的對象,咱們也稱之爲廣義值棧。java

       Struts2在每次執行Action以前都會建立新的ActionContext,在同一個線程裏ActionContext裏面的屬性是惟一的,這樣Action就能夠在多線程中使用。安全

1:ActionContext的線程安全性session

       那麼Struts2是如何保證ActionContext的線程安全性呢?多線程

       看看ActionContext對象的代碼,示例以下:框架

?
1
2
3
4
public class ActionContext implements Serializable { 
static ThreadLocal actionContext = new ThreadLocal(); 
…… 
}



ThreadLocal又稱爲「線程局部變量」,它爲每個使用該變量的線程都提供一個變量值的副本,使每個線程均可以獨立地改變本身的副本,而不會和其它線程的副本衝突。 函數

存放在ActionContext裏的數據都存放在這個ThreadLocal的屬性中,而這個屬性只會在對應的當前請求線程中可見,從而保證數據是線程安全的。 學習

2:訪問的是Map 測試

回顧前面在使用ActionContext來訪問Session中數據的程序,你會發現,其實在程序裏面訪問的是一個Map,而非HttpSession對象,這是爲何呢? this

       原來,Struts2框架將與Web相關的不少對象從新進行了包裝,好比將HttpSession對象從新包裝成了一個Map對象,裏面存放着 Session中的數據,提供這個Map給Action使用,而不用Action直接和底層的HttpSession打交道。也正是由於框架的包裝,讓 Action能夠徹底的和Web層解耦。 spa

       可是要注意一點,ActionContext不能在普通的Java應用程序中使用。

在之前的學習中,介紹了Action和Servlet API是解耦的,所以能夠在Java應用程序中調用Action的execute方法來進行測試。可是若是使用了ActionContext來獲取 session數據,那麼就不能這樣運行了。由於ActionContext包裝的都是Web的數據,在Java應用程序中運行的時候,沒有Web的環境和響應的數據,於是會拋出空指針的異常。

訪問其它的Web對象的值也是與此相似的,你經過ActionContext去訪問的都是包裝後的Map。

3:使用SessionAware接口

Struts2還提供另一種簡單的方式,使用SessionAware接口來訪問存儲於ActionContext中的數據,該接口經過使用IoC/DI來爲Action注入Session Map,就能夠在程序裏面直接使用這個Map來操做數據了。

 (1)在Action中再也不須要訪問ActionContext了,取而代之,Action實現SessionAware接口,該接口告知 Struts2在Action執行以前要設置Session Map,是經過servletConfig 攔截器來實現的,這個攔截器在defaultStack裏面就有。示例代碼以下:

?
1
2
3
4
5
6
7
8
9
10
11
12
public class OgnlAction extends ActionSupport implements SessionAware{ 
     private Map<String, Object> session; 
     @Resource
     public void setSession(Map<String, Object> session) { 
         this .session = session; 
    
       
     public String execute(){ 
         session.put( "sessionTestKey" , "測試SessionAware" ); 
         return this .SUCCESS; 
    
}



在上面的代碼中:

  • Action類實現SessionAware接口
  • 這個接口要求Action類實現一個方法setSession(Map<String, Object> session),經過這個方法注入Session的數據
  • 在execute方法中,經過這個私有屬性就能夠操做會話中的數據,注意一點,這個Map中的值也是與HttpSession聯動的。


爲了可以在普通的Java應用中運行並測試Action,推薦你們使用SessionAware的方式來訪問HttpSession。由於這樣一來,在通 過main方法運行或測試的時候,能夠直接調用setSession方法,傳入模擬的會話數據,就不會出現execute方法中拋出空指針的異常了。

       所以,推薦你們使用SessionAware的方式來訪問HttpSession。

4:使用其它包裝接口

跟SessionAware相似,你可使用RequestAware來獲取包裝請求對象的attribute中的值的Map; 使用ApplicationAware來獲取包裝ServletContext對象的attribute中的值的Map;使用 ParameterAware來獲取包裝請求對象的參數中的值的Map,等等,這裏只羅列這幾個常見和經常使用的,還有更多的請參見Struts2的API文 檔。



在實際應用開發中,光是獲取數據就夠了嗎?答案顯然是否認的,有些時候,根據功能須要,在Action中必需要能獲取到Servlet相關的API,好比要操做Cookie。這個時候,就須要用ServletActionContext了。

1:ServletActionContext概述

這個類直接繼承了ActionContext,固然也繼承了它父類的不少功能,好比:對OgnlValueStack、Action名字等的訪問。更重要的是,它還提供了直接訪問Servlet的相關對象的功能,它能夠取得的對象有:

  • HttpServletRequest:請求對象
  • HttpServletResponse:響應對象
  • ServletContext:Servlet上下文信息
  • PageContext:Http頁面上下文


2:基本使用

       直接使用ServletActionContext的靜態方法就能夠獲取到相應的對象。示例以下:

 

java代碼:
?
1
2
3
4
5
HttpServletRequest request = ServletActionContext.getRequest(); 
HttpServletResponse response = ServletActionContext.getResponse(); 
ServletContext servletContext = ServletActionContext.getServletContext(); 
PageContext pageContext = ServletActionContext.getPageContext(); 
HttpSession session = ServletActionContext.getRequest().getSession();


這裏要注意的是HttpSession對象的獲取,是在取得HttpRequest對象事後,經過HttpRequest對象來獲取會話對象。固然,取得相應的對象後,就直接使用這些對象的方法來進行開發,這裏就不去贅述了。

3:經過IoC/DI的方式來獲取相應的Servlet對象

       還能夠經過IoC/DI的方式來獲取相應的Servlet對象,對應關係是:

  • ServletRequestAware:經過這個接口來獲取HttpServletRequest對象
  • ServletResponseAware:經過這個接口來獲取HttpServletResponse對象

用ServletRequestAware來示例一下。

(1)修改Action,讓其實現ServletRequestAware接口,示例代碼以下:

 java代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class OgnlAction extends ActionSupport implements ServletRequestAware{ 
     private HttpServletRequest request = null
     @Resource
     public void setServletRequest(HttpServletRequest request) { 
         this .request = request; 
    
       
     public String execute(){         
         request.setAttribute( "request" , "Request的屬性值" ); 
         request.getSession().setAttribute( "sessionTestKey" , "測試SessionAware" ); 
         return this .SUCCESS; 
     }    
}



 


ActionContext和ServletActionContext

根據前面的講述,你會發現,ActionContext和ServletActionContext有着一些重複的功能,都可以獲取到Web對象的數據,可是又有些不一樣。

       一般狀況下,能夠這麼認爲:ActionContext主要負責值的操做;ServletActionContext主要負責獲取Servlet對象。

那麼在Action中,該如何去抉擇呢?建議的原則是:

  • 優先使用ActionContext
  • 只有ActionContext不能知足功能要求的時候,才使用ServletActionContext

總之,要儘可能讓Action與Web無關,這對於Action的測試和複用都是極其有好處的。

       另外還有一點須要注意:在使用ActionContext時,不要在Action的構造函數裏使用ActionContext.getContext(),由於這個時候ActionContext裏的一些值也許尚未設置,這時經過ActionContext取得的值也許是null。

相關文章
相關標籤/搜索