http://blog.sina.com.cn/s/blog_6345041c01015fgl.html
訪問request、session和application對象
在傳統的Web開發中,經常會用到ServletAPI中的HttpServletRequest、HttpSession和ServletContext。Struts2框架讓我們可以直接訪問和設置action及模型對象的數據,這降低了對HttpServletRequest對象的使用需求,但在某些應用中,我們可能會需要在action中去訪問HttpServletRequest對象以及其他兩種對象,例如,用戶登錄成功後,我們應該將用戶信息保存到Session中。
Struts 2提供了多種方式來訪問上述的三種對象,歸結起來,可以劃分爲兩大類:與ServletAPI解耦的訪問方式和與Servlet API耦合的訪問方式。
1 與ServletAPI解耦的訪問方式
爲了避免與Servlet API耦合在一起,方便Action類做單元測試,Struts2對HttpServletRequest、HttpSession和ServletContext進行了封裝,構造了三個Map對象來替代這三種對象,在Action中,直接使用HttpServletRequest、HttpSession和ServletContext對應的Map對象來保存和讀取數據。
要獲取這三個Map對象,可以使用com.opensymphony.xwork2.ActionContext類(參看4.2節)。
ActionContext是action執行的上下文,在ActionContext中保存了action執行所需的一組對象,包括parameters、request、session、application和locale等。ActionContext類定義瞭如下方法,用於獲取HttpServletRequest、HttpSession和ServletContext對應的Map對象。
public Object get(Object key) |
public Map getSession() |
public Map getApplication() |
獲取封裝了ServletContext的Map對象。
我們看例3-11。
例3-11通過ActionContext來獲取request、session和application對象的LoginAction1
package org.sunxin.struts2.ch03.action.way1; import java.util.Map; import org.sunxin.struts2.ch03.model.User; import com.opensymphony.xwork2.Action; public class LoginAction1 implements Action public void setUser(User user) @SuppressWarnings("unchecked") |
在成功頁面中,可以使用JSP內置的表達式語言來訪問request、session和application範圍的數據,代碼如例3-12所示。
例3-12 success.jsp
<%@ page contentType="text/html;charset=GBK" %> |
如果頁面能夠正常顯示我們保存在request、session和application對象中的數據(當然是能夠正常顯示的,要不然筆者也不會給出這個例子了。☺),就說明在Action中,對ActionContext返回的Map對象的操作,等價於對ServletAPI中的HttpServletRequest、HttpSession和ServletContext對象的操作。
利用請求對象來傳遞數據還有一種方式,你可以直接使用ActionContex類的put()方法將數據保存到ActionContext中,如下:
ActionContext.getContext().put("greeting", "歡迎您來到http://www. sunxin.org");
然後在結果頁面中,從請求對象中取出greeting屬性,如下:
${requestScope.greeting} 或者 <%=request.getAttribute("greeting")%> |
ActionContext中保存的數據能夠從請求對象中得到,這讓人太不可思議了。其中的奧妙就在於Struts2中的org.apache.struts2.dispatcher.StrutsRequestWrapper類,這個類是HttpServletRequest的包裝類,它重寫了getAttribute()方法(在頁面中獲取request對象的屬性就要調用這個方法),在這個方法中,它首先在請求對象中查找屬性,如果沒有找到(如果你在ActionContext中保存數據,當然就找不到了),則到ActionContext中去查找。這就是爲什麼在ActionContext中保存的數據能夠從請求對象中得到的原因。
當然具體的實現還有很多細節,感興趣的讀者可以跟蹤一下Struts 2的源代碼。
除了利用ActionContext來獲取request、session和application對象這種方式外,Action類還可以實現某些特定的接口,讓Struts2框架在運行時向Action實例注入request、session和application對象。與之對應的三個接口和它們的方法如下所示:
org.apache.struts2.interceptor.RequestAware |
public void setRequest(Map request) |
void setSession(Map session) |
框架利用該接口,向Action實例注入application Map對象。該接口只有一個方法,如下:
void setApplication(Map application) |
我們看例3-13。
例3-13 通過接口注入來獲取request、session和application對象的LoginAction2
package org.sunxin.struts2.ch03.action.way1; import java.util.Map; import org.apache.struts2.interceptor.ApplicationAware; import com.opensymphony.xwork2.Action; public class LoginAction2 implements Action, @SuppressWarnings("unchecked") @Override @Override @Override |
LoginAction2類實現了RequestAware、SessionAware和ApplicationAware接口,框架在運行時會調用這三個接口中的方法,向LoginAction2注入request、session和application對象。
2 與ServletAPI耦合的訪問方式
直接訪問ServletAPI將使你的Action與Servlet環境耦合在一起,我們知道對於HttpServletRequest、HttpServletResponse和ServletContext這些對象,它們都是由Servlet容器來構造的,與這些對象綁定在一起,測試時就需要有Servlet容器,不便於Action的單元測試。但有時候,我們又確實需要直接訪問這些對象,那麼當然是以完成任務需求爲主。
要直接獲取HttpServletRequest和ServletContext對象,可以使用org.apache.struts2.ServletActionContext類,該類是ActionContext的子類,在這個類中定義下面兩個靜態方法:
public static HttpServletRequest getRequest() |
public static ServletContext getServletContext() |
得到ServletContext對象。
此外,ServletActionContext類還給出了獲取HttpServletResponse對象的方法,如下:
public static HttpServletResponse getResponse() |
ServletActionContext類並沒有給出直接得到HttpSession對象的方法,HttpSession對象可以通過HttpServletRequest對象來得到。
除了上述的方法調用得到HttpServletRequest和ServletContext對象外,還可以調用ActionContext對象的get()方法,傳遞ServletActionContext.HTTP_REQUEST和ServletActionContext.SERVLET_CONTEXT鍵值來得到HttpServletRequest和ServletContext對象,如下所示:
ActionContext.getContext().get(ServletActionContext.HTTP_REQUEST); |
ActionContext.getContext().get(ServletActionContext.SERVLET_CONTEXT); |
得到與ServletActionContext.SERVLET_CONTEXT鍵值綁定的ServletContext對象。
同樣的,也可以向ActionContext的get()方法傳遞ServletActionContext.HTTP_RESPONSE鍵值來得到HttpServletResponse對象,如下:
ActionContext.getContext().get(ServletActionContext.HTTP_RESPONSE); |
建議讀者採用第一種方式來獲取HttpServletRequest和ServletContext對象,這樣簡單而又清晰。
我們看例3-14。
例3-14通過ServletActionContext來獲取HttpServletRequest和ServletContext對象的LoginAction3
package org.sunxin.struts2.ch03.action.way2; import javax.servlet.ServletContext; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.Action; public class LoginAction3 implements Action @Override |
除了利用ServletActionContext來獲取HttpServletRequest對象和ServletContext對象這種方式外,Action類還可以實現ServletRequestAware和ServletContextAware接口,由Struts2框架向Action實例注入HttpServletRequest和ServletContext對象。
org.apache.struts2.interceptor.ServletRequestAware接口只有一個方法,如下所示:
void setServletRequest(HttpServletRequest request) |
void setServletContext(ServletContext context) |
ServletRequestAware接口和ServletContextAware接口不屬於同一個包,前者在org.apache.struts2.interceptor包中,後者在org.apache.struts2.util包中,這很讓人迷惑。
我們看例3-15。
例3-15 通過接口注入來獲取HttpServletRequest和ServletContext對象的LoginAction4
package org.sunxin.struts2.ch03.action.way2; import javax.servlet.ServletContext; importorg.apache.struts2.interceptor.ServletRequestAware; import com.opensymphony.xwork2.Action; public class LoginAction4 implements Action,ServletRequestAware, ServletContextAware … @Override //在session中保存user對象 //統計用戶訪問量,在application中保存用戶訪問量數據 return SUCCESS; @Override @Override |