在传统的Web开发中,经常会用到Servlet API中的HttpServletRequest、HttpSession和ServletContext。Struts 2框架让我们可以直接访问和设置action及模型对象的数据,这降低了对HttpServletRequest对象的使用需求,但在某些应用中,我们可能会需要在action中去访问HttpServletRequest对象以及其他两种对象,例如,用户登录成功后,我们应该将用户信息保存到Session中。
Struts 2提供了多种方式来访问上述的三种对象,归结起来,可以划分为两大类:与Servlet API解耦的访问方式和与Servlet API耦合的访问方式.
与Servlet API解耦的访问方式
方法一:通过ActionContext操作
为了避免与Servlet API耦合在一起,方便Action类做单元测试,Struts 2对HttpServletRequest、HttpSession和ServletContext进行了封装,构造了三个Map对象来替代这三种对象,在Action中,直接使用HttpServletRequest、HttpSession和ServletContext对应的Map对象来保存和读取数据。
要获取这三个Map对象,可以使用com.opensymphony.xwork2.ActionContext类。
ActionContext是action执行的上下文,在ActionContext中保存了action执行所需的一组对象,包括parameters、request、session、application和locale等。ActionContext类定义了如下方法,用于获取HttpServletRequest、HttpSession和ServletContext对应的Map对象。
1、public Object get(Object key)
ActionContext类没有提供类似getRequest()这样的方法来获取封装了HttpServletRequest的Map对象。要得到请求Map对象,你需要为get()方法传递参数“request”。
2、public Map getSession()
获取封装了HttpSession的Map对象。
3、 public Map getApplication()
获取封装了ServletContext的Map对象。
通过ActionContext来获取request、session和application对象
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ServletAPI的测试页面</title>
</head>
<body>
<h3>${sessionScope.name},${requestScope.greeting}。<br>
本站的访问量是:${applicationScope.counter}</h3>
<s:form action="servletAPI1" namespace="/">
<table>
<tr>
<td>登录帐号</td>
<td><s:textfield name="name" /></td>
</tr>
<tr>
<td>密码</td>
<td><s:password name="pwd" /></td>
</tr>
<tr>
<td><input type="submit" value="提交" s /></td>
<td><s:reset value="重置" /></td>
</tr>
</table>
<!--显示所有校验失败信息-->
<s:fielderror />
</s:form>
<br>
<s:debug></s:debug>
</body>
</html>
/**
*
*/
package action;
import java.util.Map;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import com.opensymphony.xwork2.ActionContext;
import lombok.Getter;
import lombok.Setter;
/**
* @author Administrator 测试Action中获取request,session,application
*/
@Namespace("/")
@Result(name = "success", location = "/servletAPI.jsp")
public class ServletAPIAction {
@Getter
@Setter
private String name; // 封装帐号(uid)请求参数属性
@Getter
@Setter
private String pwd;
/**
* 通过ActionContext获取
*
* @return
*/
@Action(value = "servletAPI1")
public String actionContex() {
ActionContext actionContext = ActionContext.getContext();
@SuppressWarnings("unchecked")
Map<String, Object> request = (Map<String, Object>) actionContext.get("request");
Map<String, Object> session = actionContext.getSession();
Map<String, Object> application = actionContext.getApplication();
// 在请求中放置欢迎信息。
request.put("greeting", "欢迎您来到影梧的博客");
// 在session中保存password属性
session.put("password", pwd);
// 统计用户访问量,在application中保存用户访问量数据
Integer count = (Integer) application.get("counter");
if (null == count)
count = 1;
else
count++;
application.put("counter", count);
return "success";
}
}
方法二:IOC(控制反转)获取servletAPI
Action类还有另一种获得ServletAPI的解耦方式,这就是我们可以让他实现某些特定的接口,让Struts2框架在运行时向Action实例注入request、session和application对象。这种方式也就是IOC(控制反转)方式,实现RequestAware,SessionAware,ApplicationAware接口即可,这三个接口每个都有一个相关的set方法。
实例如下:
/**
*
*/
package action;
import java.util.Map;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.interceptor.ApplicationAware;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;
import com.opensymphony.xwork2.ActionContext;
import lombok.Getter;
import lombok.Setter;
/**
* @author Administrator 测试Action中获取request,session,application
*/
@Namespace("/")
@Result(name = "success", location = "/servletAPI.jsp")
public class ServletAPIAction implements RequestAware,SessionAware,ApplicationAware{
@Getter
@Setter
private String name; // 封装帐号(uid)请求参数属性
@Getter
@Setter
private String pwd;
private Map<String, Object> request;
private Map<String, Object> session;
private Map<String, Object> application;
/**
* 通过实现接口RequestAware,SessionAware,ApplicationAware来注入
* @return
*/
@Action(value = "servletAPI2")
public String requestAware() {
// 在请求中放置欢迎信息。
request.put("greeting", "欢迎您来到影梧的博客");
// 在session中保存password属性
session.put("name", name);
session.put("password", pwd);
// 统计用户访问量,在application中保存用户访问量数据
Integer count = (Integer) application.get("counter");
if (null == count)
count = 1;
else
count++;
application.put("counter", count);
return "success";
}
@Override
public void setApplication(Map<String, Object> application) {
this.application = application;
}
@Override
public void setSession(Map<String, Object> session) {
this.session = session;
}
@Override
public void setRequest(Map<String, Object> request) {
this.request = request;
}
}
与Servlet API耦合的访问方式
直接访问Servlet API将使你的Action与Servlet环境耦合在一起,我们知道对于HttpServletRequest、HttpServletResponse和ServletContext这些对象,它们都是由Servlet容器来构造的,与这些对象绑定在一起,测试时就需要有Servlet容器,不便于Action的单元测试。但有时候,我们又确实需要直接访问这些对象。
方法一:通过ServletActionContext类获取
ServletActionContext类是ActionContext的子类,在这个类中定义下面静态方法:
1、public static HttpServletRequest getRequest()
得到HttpServletRequest对象。
2、public static ServletContext getServletContext()
得到ServletContext对象。
此外,ServletActionContext类还给出了获取HttpServletResponse对象的方法,如下:
3、public static HttpServletResponse getResponse()
注意:ServletActionContext类并没有给出直接得到HttpSession对象的方法,HttpSession对象可以通过HttpServletRequest对象来得到。
/**
* 通过ServletActionContext类获取
* @return
*/
@Action(value = "servletAPI3")
public String servletActionContext() {
ActionContext actionContext = ActionContext.getContext();
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
ServletContext application = ServletActionContext.getServletContext();
HttpSession session = request.getSession();
// 在请求中放置欢迎信息。
request.setAttribute("greeting", "欢迎您来到影梧的博客");
// 在session中保存password属性
session.setAttribute("name", name);
session.setAttribute("password", pwd);
// 统计用户访问量,在application中保存用户访问量数据
Integer count = (Integer) application.getAttribute("counter");
if (null == count)
count = 1;
else
count++;
application.setAttribute("counter", count);
return "success";
}
方法二:通过ActionContext来获取相关对象:
1、ActionContext.getContext().get(ServletActionContext.HTTP_REQUEST);
得到与ServletActionContext.HTTP_REQUEST键值绑定的HttpServletRequest对象。
2、ActionContext.getContext().get(ServletActionContext.SERVLET_CONTEXT);
得到与ServletActionContext.SERVLET_CONTEXT键值绑定的ServletContext对象。
同样的,也可以向ActionContext的get()方法传递ServletActionContext.HTTP_ RESPONSE键值来得到HttpServletResponse对象,如下:
3、ActionContext.getContext().get(ServletActionContext.HTTP_RESPONSE);
/**
* 通过ActionContext类获取
* @return
*/
@Action(value = "servletAPI4")
public String actionContext() {
ActionContext actionContext = ActionContext.getContext();
HttpServletRequest request = (HttpServletRequest) actionContext.get(ServletActionContext.HTTP_REQUEST);
HttpServletResponse response = (HttpServletResponse) actionContext.get(ServletActionContext.HTTP_RESPONSE);
ServletContext application = (ServletContext) actionContext.get(ServletActionContext.SERVLET_CONTEXT);
HttpSession session = request.getSession();
// 在请求中放置欢迎信息。
request.setAttribute("greeting", "欢迎您来到影梧的博客");
// 在session中保存password属性
session.setAttribute("name", name);
session.setAttribute("password", pwd);
// 统计用户访问量,在application中保存用户访问量数据
Integer count = (Integer) application.getAttribute("counter");
if (null == count)
count = 1;
else
count++;
application.setAttribute("counter", count);
return "success";
}
方法三:通过ServletRequestAware和ServletContextAware接口
实现ServletRequestAware和ServletContextAware接口,由Struts 2框架向Action实例注入HttpServletRequest和ServletContext对象。
public class ServletAPIAction implements ServletRequestAware, ServletContextAware{
private HttpServletRequest reqest;
private ServletContext context;
private HttpServletResponse response;
/**
* 通过ServletRequestAware和ServletContextAware接口进行注入
* @return
*/
@Action(value = "servletAPI5")
public String servletRequestAware() {
// 在请求中放置欢迎信息。
reqest.setAttribute("greeting", "欢迎您来到影梧的博客");
HttpSession session = reqest.getSession();
// 在session中保存password属性
session.setAttribute("name", name);
session.setAttribute("password", pwd);
// 统计用户访问量,在application中保存用户访问量数据
Integer count = (Integer) context.getAttribute("counter");
if (null == count)
count = 1;
else
count++;
context.setAttribute("counter", count);
return "success";
}
@Override
public void setServletContext(ServletContext context) {
this.context = context;
}
@Override
public void setServletRequest(HttpServletRequest request) {
this.reqest = request;
}
@Override
public void setServletResponse(HttpServletResponse response) {
this.response = response;
}
总结
通过上面五种方式的讲解我们可以看出,获得servletAPI的方式基本都差不多,通常我们建议大家采用第一种方式来获取HttpServletRequest和ServletContext对象,这样简单而又清晰,并且降低了和servletAPI的耦合度,这样也方便进行单元测试
获取response方法总结
方法一:
对应以上解耦方法一 actionContext.get(“request”)
对应以上解耦方法二 RequestAware接口
都获得的是struts2对应HTTPServletRequest的Map数据
private HttpServletResponse response;
Set<String>keys=request.keySet();
//枚举所有的key值。实际上只有一个key:struts.valueStack
for(String key:keys)
System.out.println(key);
//获得OgnlValueStack对象
OgnlValueStack stack=(OgnlValueStack)request.get("struts.valueStack");
//获得HttpServletResponse对象
response= (HttpServletResponse)stack.getContext().get(StrutsStatics.HTTP_RESPONSE);
response.getWriter().write("reponse");
方法二:ServletActionContext直接get
HttpServletResponse response = ServletActionContext.getResponse();
方法三:ActionContext直接get
HttpServletResponse response = (HttpServletResponse) actionContext.get(ServletActionContext.HTTP_RESPONSE);
方法四:ServletResponseAware
用其get方法直接注入
@Override
public void setServletResponse(HttpServletResponse response) {
this.response = response;
}