Struts2 訪問request、session和application對象

Struts2 訪問request、session和application對象

在 傳統的Web開發中,經常會用到Servlet API中的HttpServletRequest、HttpSession和ServletContext。Struts 2框架讓我們可以直接訪問和設置action及模型對象的數據,這降低了對HttpServletRequest對象的使用需求,但在某些應用中,我們可 能會需要在action中去訪問HttpServletRequest對象以及其他兩種對象,例如,用戶登錄成功後,我們應該將用戶信息保存到 Session中。

Struts 2提供了多種方式來訪問上述的三種對象,歸結起來,可以劃分爲兩大類:與Servlet API解耦的訪問方式和與Servlet API耦合的訪問方式。

與Servlet API解耦的訪問方式

爲了避免與Servlet API耦合在一起,方便Action類做單元測試,Struts 2對HttpServletRequest、HttpSession和ServletContext進行了封裝,構造了三個Map對象來替代這三種對象, 在Action中,直接使用HttpServletRequest、HttpSession和ServletContext對應的Map對象來保存和讀取 數據。

要獲取這三個Map對象,可以使用com.opensymphony.xwork2.ActionContext類(參看 4 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對象的操作,等價於對Servlet API中的HttpServletRequest、HttpSession和ServletContext對象的操作。

利用請求對象來傳遞數據還有一種方式,你可以直接使用ActionContex類的put()方法將數據保存到ActionContext中,如下:

ActionContext.getContext().put("greeting", "歡迎您來到http://www. sunxin.org");

然後在結果頁面中,從請求對象中取出greeting屬性,如下:

${requestScope.greeting} 或者 <%=request.getAttribute("greeting")%>

ActionContext 中保存的數據能夠從請求對象中得到,這讓人太不可思議了。其中的奧妙就在於Struts 2中的org.apache.struts2.dispatcher.StrutsRequestWrapper類,這個類是 HttpServletRequest的包裝類,它重寫了getAttribute()方法(在頁面中獲取request對象的屬性就要調用這個方法), 在這個方法中,它首先在請求對象中查找屬性,如果沒有找到(如果你在ActionContext中保存數據,當然就找不到了),則到 ActionContext中去查找。這就是爲什麼在ActionContext中保存的數據能夠從請求對象中得到的原因。

當然具體的實現還有很多細節,感興趣的讀者可以跟蹤一下Struts 2的源代碼。

除了利用ActionContext來獲取request、 session和application對象這種方式外,Action類還可以實現某些特定的接口,讓Struts 2框架在運行時向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對象。在execute()方法中不再需要訪問ActionContext,因此我們刪除了與之 相關的代碼。

雖然利用Struts 2提供的request、session和application對象就可以對HttpServletRequest、HttpSession和 ServletContext對象中的數據進行操作,但它們畢竟是Map類型,如果我們需要調用HttpServletRequest、 HttpSession和ServletContext中的特定操作,例如獲取請求方法的名字(調用HttpServletRequest中的 getMethod()方法),那麼可以使用下一節介紹的方式來獲取Servlet環境中的對象。

與Servlet API耦合的訪問方式

直接訪問Servlet API將使你的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();

 

      /*ActionContext ctx = ActionContext.getContext();

      HttpServletRequest request = (HttpServletRequest)ctx.get(Servlet ActionContext.HTTP_REQUEST);       

      HttpSession session = request.getSession();

      ServletContext context = (ServletContext)ctx.get(ServletAction Context. SERVLET_CONTEXT);*/

 

      //在請求中放置歡迎信息。

      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接口,由Struts 2框架向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;

import org.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對象。在execute()方法中不再需要訪問 ServletActionContext,因此我們刪除了與之相關的代碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章