ActionContext對象的使用

Struts1的Action必須依賴於web容器,他的extecute方法會自動獲得HttpServletRequest、HttpServletResponse對象,從而可以跟web容器進行交互。

Struts2的Action不用依賴於web容器,本身只是一個普通的java類而已。但是,在web開發中我們往往需要獲得request、session、application等對象。這時候,可以通過ActionContext來處理。

ActionContext正如其名,是Action執行的上下文。他內部有個map屬性,它存放了Action執行時需要用到的對象。

在每次執行Action之前都會創建新的ActionContext對象,所以Actioncontext是線程安全的。新new的ActionContext是保存在一個Threadlocal變量中,即採用Threadlocal模式。Threadlocal變量爲每個線程提供獨立的變量值的副本,使每個線程都可以獨立的使用自己的副本,而不會和其他線程發生衝突。

通過ActionContext獲取的session、request、application並不是真正的HttpServletRequest、HttpServletResponse、ServletContext對象,而是將這三個對象裏面的值重新包裝成了map對象。這樣的封裝,我們及獲取了我們需要的值,同時避免了跟Web容器直接打交道,實現了完全的解耦。

測試代碼:

public class TestActionContextAction extends ActionSupport{
    private String uname;
    public String execute() throws Exception {
        ActionContext ac = ActionContext.getContext();
        System.out.println(ac);    //在此處定義斷點
        return this.SUCCESS;
    }
    //get和set方法省略!
}

我們定義斷點,debug進去,跟蹤ac對象的值。發現他有個table屬性,該屬性內部包含一個map屬性,該map中又有多個map屬性,他們分別是:
request、session、application、action、attr、parameters等。

同時,我們跟蹤request進去,發現屬性attribute又是一個table,再進去發現一個名字叫做”struts.valueStack”屬性。內容如下:
這裏寫圖片描述
這裏寫圖片描述
OgnlValueStack可以簡單看做List,裏面還放了Action對象的引用,通過它可以得到該Action對象的引用。

下圖說明了幾個對象的關係:
這裏寫圖片描述

雖然我們已經從debug中得到上圖的關係。爲了驗證我們的想法,我們寫個代碼進行測試:

    private String uname;

    public String execute() throws Exception {
        ActionContext ac = ActionContext.getContext();
            ac.put("uu", "uuu");
        ac.getSession().put("s", "ss");   //直接使用:${sessionScope.s}即可獲取
        ((Map)ac.get("request")).put("r", "request作用域中的r參數");
        System.out.println(ac);     
return this.SUCCESS;
    }
    request:${requestScope.s} <br/>
    session:${sessionScope.s}  <br/>
    actioncontext中的屬性,會被攔截器處理成request對象的屬性,便於引用:${requestScope.uu}<br/>
    action中的屬性也會攔截器被處理成request對象的屬性,便於引用:${requestScope.uname }<br/>

結果如下:
這裏寫圖片描述

總結:
ActionContext、Action本身和HttpServletRequest對象沒有關係。但是爲了能夠使用EL表達式、JSTL直接操作他們的屬性。會有一個攔截器將ActionContext、Action中的屬性通過類似request.setAttribute()方法置入request中(webwork2.1之前的做法)。這樣,我們也可以通過:${requestScope.uname}即可訪問到ActionContext和Action中的屬性。
注:struts2後,使用裝飾器模式來實現上述功能。
Action的實例,總是放到value stack中。因爲Action放在stack中,而stack是root(根對象),所以對Action中的屬性的訪問就可以省略#標記。



用ActionContext獲取Web容器信息
上面我們已經測試過,通過ActionContext可以獲得session、request、application,但他們並不是真正的HttpServletRequest、HttpServletResponse、ServletContext對象,而是將這三個對象裏面的值重新包裝成了map對象。 Struts框架通過他們來和真正的web容器對象交互。

Action對象需要繼承ActionSupport對象

第一種方法:

//通過ActionContext對象
ActionContext ac = ActionContext.getContext();
//獲取request作用域對象
Map<String, Object> requestMap = (Map<String, Object>) ac.get("request");
//對request作用域存放信息
requestMap.put("requestval", "ActionContext.request");
//同樣session和application作用域操作一樣
Map<String, Object> sessionMap = (Map<String, Object>) ac.get("session");
sessionMap.put("sessionval", "ActionContext.session");
Map<String, Object> applicationMap = (Map<String, Object>) ac.get("application");
applicationMap.put("applicationval", "ActionContext.application");

對應的jsp頁面獲取數據:

第一種方式獲取request:${requestval }<hr>
使用ognl表達式獲取:<s:property value="#request['requestval']"/><hr>

第二種方法:

//通過ActionContext對象獲取對象
ActionContext ac = ActionContext.getContext();
//給request作用域存放信息
ac.put("requestval", "ActionContext.request");
//通過ActionContext對象的get方法給session和application作用域存放信息
Map<String, Object> sessionMap = ac.getSession();
sessionMap.put("sessionval", "ActionContext.session");
Map<String, Object> applicationMap = ac.getApplication();
applicationMap.put("applicationval", "ActionContext.application");

第三種方法:
直接獲取真正的request、session、application對象獲得Servlet API(非耦合):通過ServletActionContext獲得真正的Servlet API

HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("servletrequestval", "request");
//獲取到的作用域對象,用法和servlet中使用的一致
HttpSession session = request.getSession();
session.setAttribute("serveltsessionval", "session");

ServletContext application = request.getServletContext();
application.setAttribute("serveltapplicationval", "application");

第四種方法:(一般不使用)
實現RequestAware,SessionAware,ApplicationAware接口,重寫接口內定義的方法

//定義一個變量來接收信息。
public class TestActionContextAction extends ActionSupport implements RequestAware,SessionAware,ApplicationAware{

Map<String, Object> map;
@Override
public void setRequest(Map<String, Object> map) {
    // TODO Auto-generated method stub
    this.map = map;
}

在jsp頁面中可以通過el表達式獲取數值:

request:${requestval }<br>
    session:${sessionval }<br>
    application:${applicationval }<br>

或者

request:${requestScope.requestval }<br>
session:${sessionScope.sessionval }<br>
application:${applicationScope.applicationval }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章