如何獲取request、session和application對象

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)
ActionContext類沒有提供類似getRequest()這樣的方法來獲取封裝了HttpServletRequest的Map對象。要得到請求Map對象,你需要爲get()方法傳遞參數“request”。
public Map getSession()
獲取封裝了HttpSession的Map對象。
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;
import com.opensymphony.xwork2.ActionContext;

public class LoginAction1 implements Action

private User user;

public User getUser()
{
return user;
}

public void setUser(User user)
{
this.user = user;
}

@SuppressWarnings("unchecked")
@Override
public String execute() throws Exception
{
if("zhangsan".equals(user.getUsername()) 
&&"1234".equals(user.getPassword()))
{
ActionContext context =ActionContext.getContext(); 
Map request = (Map)context.get("request");
Map session = context.getSession();
Map application = context.getApplication();

//在請求中放置歡迎信息。
request.put("greeting", "歡迎您來到程序員之家");

//在session中保存user對象
session.put("user", user);

//統計用戶訪問量,在application中保存用戶訪問量數據
Integer count = (Integer)application.get("counter");
if(null == count)
count=1;
else
count++;
application.put("counter", count);

return SUCCESS;
}
else
{
return ERROR;
}
}
}

在成功頁面中,可以使用JSP內置的表達式語言來訪問request、session和application範圍的數據,代碼如例3-12所示。

例3-12 success.jsp

 

<%@ page contentType="text/html;charset=GBK" %>
<html>
<head><title>歡迎頁面</title></head>
<body>
<h3>${sessionScope.user.username},${requestScope.greeting}。<br>
本站的訪問量是:${applicationScope.counter}</h3>
</body>
</html>

如果頁面能夠正常顯示我們保存在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
框架利用該接口,向Action實例注入request Map對象。該接口只有一個方法,如下:
public void setRequest(Map request)
 org.apache.struts2.interceptor.SessionAware
框架利用該接口,向Action實例注入session Map對象。該接口只有一個方法,如下:
void setSession(Map session)
 org.apache.struts2.interceptor.ApplicationAware

框架利用該接口,向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 org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;
import org.sunxin.struts2.ch03.model.User;
import com.opensymphony.xwork2.Action;
public class LoginAction2 implements Action, 
RequestAware, SessionAware, ApplicationAware
{
private Map request;
private Map session;
private Map application;

@SuppressWarnings("unchecked")
@Override
public String execute() throws Exception
{
if("zhangsan".equals(user.getUsername())
&& "1234".equals(user.getPassword()))
{
//在請求中放置歡迎信息。
request.put("greeting", "歡迎您來到程序員之家");

//在session中保存user對象
session.put("user", user);

//統計用戶訪問量,在application中保存用戶訪問量數據
Integer count = (Integer)application.get("counter");
if(null == count)
count=1;
else
count++;
application.put("counter", count);

return SUCCESS;
}
else
{
return ERROR;
}
}
@Override
public void setRequest(Map request)
{
this.request = request;
}
@Override
public void setSession(Map session)
{
this.session = session;
}
@Override
public void setApplication(Map application)
{
this.application = application;
}
}


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()
得到HttpServletRequest對象。
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);
得到與ServletActionContext.HTTP_REQUEST鍵值綁定的HttpServletRequest對象。
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.struts2.ServletActionContext;
import org.sunxin.struts2.ch03.model.User;

import com.opensymphony.xwork2.Action;

public class LoginAction3 implements Action

...

@Override
public String execute() throws Exception
{
if("zhangsan".equals(user.getUsername()) 
&&"1234".equals(user.getPassword()))
{
HttpServletRequest request =ServletActionContext.getRequest();       
HttpSession session = request.getSession();
ServletContext context =ServletActionContext.getServletContext();



//在請求中放置歡迎信息。
request.setAttribute("greeting", "歡迎您來到程序員之家");

//在session中保存user對象
session.setAttribute("user", user);

//統計用戶訪問量,在application中保存用戶訪問量數據
Integer count = (Integer)context.getAttribute("counter");
if(null == count)
count=1;
else
count++;
context.setAttribute("counter", count);

return SUCCESS;
}
else
{
return ERROR;
}
}
}

除了利用ServletActionContext來獲取HttpServletRequest對象和ServletContext對象這種方式外,Action類還可以實現ServletRequestAware和ServletContextAware接口,由Struts2框架向Action實例注入HttpServletRequest和ServletContext對象。

org.apache.struts2.interceptor.ServletRequestAware接口只有一個方法,如下所示:

 

void setServletRequest(HttpServletRequest request)
org.apache.struts2.util.ServletContextAware接口也只有一個方法,如下所示:
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;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

importorg.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.util.ServletContextAware;
import org.sunxin.struts2.ch03.model.User;

import com.opensymphony.xwork2.Action;

public class LoginAction4 implements Action,ServletRequestAware, ServletContextAware
{
private HttpServletRequest request;
private ServletContext context;

@Override
public String execute() throws Exception
{
if("zhangsan".equals(user.getUsername()) 
&&"1234".equals(user.getPassword()))
{
HttpSession session = request.getSession();

//在請求中放置歡迎信息。
request.setAttribute("greeting", "歡迎您來到程序員之家");

//在session中保存user對象
session.setAttribute("user", user);

//統計用戶訪問量,在application中保存用戶訪問量數據
Integer count = (Integer)context.getAttribute("counter");
if (null == count)
count = 1;
else
count++;
context.setAttribute("counter", count);

return SUCCESS;
}
else
{
return ERROR;
}
}

@Override
public void setServletRequest(HttpServletRequest request)
{
this.request = request;
}

@Override
public void setServletContext(ServletContext context)
{
this.context = context;
}
}

LoginAction4類實現了ServletRequestAware和ServletContextAware接口,框架在運行時會調用這兩個接口中的方法,向LoginAction4注入HttpServletRequest和ServletContext對象。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章