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 }