【struts2】ActionContext与ServletActionContext
1 再探ActionContext
我们知道,ActionContext是Action执行时的上下文,里面存放着Action在执行时需要用到的对象,也称之为广义值栈。Struts2在每次执行Action之前都会创建新的ActionContext,在同一个线程里ActionContext里面的属性是唯一的,这样Action就可以在多线程中使用。
1.1 ActionContext的线程安全性
那么Struts2是如何保证ActionContext的线程安全性呢?看看ActionContext对象的代码,示例如下:
public class ActionContext implements Serializable {
static ThreadLocal actionContext = new ThreadLocal();
……
}
ThreadLocal又称为“线程局部变量”,它为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。存放在ActionContext里的数据都存放在这个ThreadLocal的属性中,而这个属性只会在对应的当前请求线程中可见,从而保证数据是线程安全的。
1.2 访问的是Map
回顾前面在使用ActionContext来访问Session中数据的程序,你会发现,其实在程序里面访问的是一个Map,而非HttpSession对象,这是为什么呢?
原来,Struts2框架将与Web相关的很多对象重新进行了包装,比如将HttpSession对象重新包装成了一个Map对象,里面存放着Session中的数据,提供这个Map给Action使用,而不用Action直接和底层的HttpSession打交道。也正是因为框架的包装,让Action可以完全的和Web层解耦。但是要注意一点,ActionContext不能在普通的Java应用程序中使用。我们知道Action和Servlet API是解耦的,因此可以在Java应用程序中调用Action的execute方法来进行测试。但是如果使用了ActionContext来获取session数据,那么就不能这样运行了。因为ActionContext包装的都是Web的数据,在Java应用程序中运行的时候,没有Web的环境和响应的数据,因而会抛出空指针的异常。访问其它的Web对象的值也是与此类似的,你通过ActionContext去访问的都是包装后的Map。
1.3 使用SessionAware接口
Struts2还提供另外一种简单的方式,使用SessionAware接口来访问存储于ActionContext中的数据,该接口通过使用IoC/DI来为Action注入Session Map,就可以在程序里面直接使用这个Map来操作数据了。
(1)在Action中不再需要访问ActionContext了,取而代之,Action实现SessionAware接口,该接口告知Struts2在Action执行之前要设置Session Map,是通过servletConfig 拦截器来实现的,这个拦截器在defaultStack里面就有。示例代码如下:
public class OgnlAction extends ActionSupport implements SessionAware{
private Map<String, Object> session;
public void setSession(Map<String, Object> session) {
this.session = session;
} public String execute(){
session.put("sessionTestKey", "测试SessionAware");
return this.SUCCESS;
}
}
在上面的代码中:
- Action类实现SessionAware接口
- 这个接口要求Action类实现一个方法setSession(Map<String, Object> session),通过这个方法注入Session的数据
- 在execute方法中,通过这个私有属性就可以操作会话中的数据,注意一点,这个Map中的值也是与HttpSession联动的。
(2)我们可以再前台获取session中的属性,以便看出Action操作session后的效果,示例如下:
<%@ taglib prefix="s" uri="/struts-tags"%>
会话中的值:<s:property value="#session['sessionTestKey']"/>
<br>
通过Servlet的Api获取会话中的值:<%=session.getAttribute("sessionTestKey") %>
为了能够在普通的Java应用中运行并测试Action,推荐大家使用SessionAware的方式来访问HttpSession。因为这样一来,在通过main方法运行或测试的时候,可以直接调用setSession方法,传入模拟的会话数据,就不会出现execute方法中抛出空指针的异常了。因此,推荐大家使用SessionAware的方式来访问HttpSession。
1.4 使用其它包装接口
跟SessionAware类似,你可以使用RequestAware来获取包装请求对象的attribute中的值的Map;使用ApplicationAware来获取包装ServletContext对象的attribute中的值的Map;使用ParameterAware来获取包装请求对象的参数中的值的Map,等等,这里只罗列这几个常见和常用的,还有更多的请参见Struts2的API文档。
2 ServletActionContext
在实际应用开发中,光是获取数据就够了吗?答案显然是否定的,有些时候,根据功能需要,在Action中必须要能获取到Servlet相关的API,比如要操作Cookie。这个时候,就需要用ServletActionContext了。
2.1 ServletActionContext概述
这个类直接继承了ActionContext,当然也继承了它父类的很多功能,比如:对OgnlValueStack、Action名字等的访问。更重要的是,它还提供了直接访问Servlet的相关对象的功能,它可以取得的对象有:
- HttpServletRequest:请求对象
- HttpServletResponse:响应对象
- ServletContext:Servlet上下文信息
- PageContext:Http页面上下文
2.2 基本使用
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
ServletContext servletContext = ServletActionContext.getServletContext();
PageContext pageContext = ServletActionContext.getPageContext();
HttpSession session = ServletActionContext.getRequest().getSession();
这里要注意的是HttpSession对象的获取,是在取得HttpRequest对象过后,通过HttpRequest对象来获取会话对象。当然,取得相应的对象后,就直接使用这些对象的方法来进行开发,这里就不去赘述了。
2.3 通过IoC/DI的方式来获取相应的Servlet对象
还可以通过IoC/DI的方式来获取相应的Servlet对象,对应关系是:
- ServletRequestAware:通过这个接口来获取HttpServletRequest对象
- ServletResponseAware:通过这个接口来获取HttpServletResponse对象
用ServletRequestAware来示例一下。
(1)修改Action,让其实现ServletRequestAware接口,示例代码如下:
public class OgnlAction extends ActionSupport implements ServletRequestAware{
private HttpServletRequest request = null;
public void setServletRequest(HttpServletRequest request) {
this.request = request;
} public String execute(){
request.setAttribute("request", "Request的属性值");
request.getSession().setAttribute("sessionTestKey", "测试SessionAware");
return this.SUCCESS;
}
}
(2)对应的结果页面也需要稍作修改,要把Action中设置的值显示出来,示例如下:
<%@ taglib prefix="s" uri="/struts-tags"%>
Request的属性值:<s:property value="#request['request']"/>
<br>
会话的属性值:<s:property value="#session['sessionTestKey']"/>
当然,你也可以以同样的方式去使用ServletResponseAware,这里就不去赘述了。
3 ActionContext和ServletActionContext
根据前面的讲述,你会发现,ActionContext和ServletActionContext有着一些重复的功能,都能够获取到Web对象的数据,但是又有些不同。通常情况下,可以这么认为:ActionContext主要负责值的操作;ServletActionContext主要负责获取Servlet对象。那么在Action中,该如何去抉择呢?建议的原则是:
- 优先使用ActionContext
- 只有ActionContext不能满足功能要求的时候,才使用ServletActionContext
总之,要尽量让Action与Web无关,这对于Action的测试和复用都是极其有好处的。另外还有一点需要注意:在使用ActionContext时,不要在Action的构造函数里使用ActionContext.getContext(),因为这个时候ActionContext里的一些值也许还没有设置,这时通过ActionContext取得的值也许是null。
参考资料:http://www.iteye.com/topic/1124526
【struts2】ActionContext与ServletActionContext的更多相关文章
- Struts2中ActionContext及ServletActionContext介绍(转载)
1. ActionContext 在Struts2开发中,除了将请求参数自动设置到Action的字段中,我们往往也需要在Action里直接获取请求(Request)或会话(Session)的一些信息, ...
- ActionContext和ServletActionContext区别
1. ActionContext 在Struts2开发中,除了将请求参数自动设置到Action的字段中,我们往往也需要在Action里直接获取请求(Request)或会话(Session)的一些信息, ...
- ActionContext和ServletActionContext小结(转)
ActionContext和ServletActionContext小结 1. ActionContext 在Struts2开发中,除了将请求参数自动设置到Action的字段中,我们往往也需要在Act ...
- Struts中ActionContext和ServletActionContext的比较
一.ActionContext在Struts2开发中除了将请求参数自动设置到Action的字段中,往往也需要在Action里直接获取请求(Request)或会话(Session)的一些信息,甚至需要直 ...
- (转)ActionContext和ServletActionContext
前面已经了解到ActionContext是Action执行时的上下文,里面存放着Action在执行时需要用到的对象,我们也称之为广义值栈. Struts2在每次执行Action之前都会创建新的Acti ...
- ActionContext和ServletActionContext小结
1. ActionContext 在Struts2开发中,除了将请求参数自动设置到Action的字段中,我们往往也需要在Action里直接获取请求(Request)或会话(Session)的一些信息, ...
- ActionContext 与 ServletActionContext获取Session的异同
1. ActionContext 在Struts2开发中,除了将请求参数自动设置到Action的字段中,我们往往也需要在Action里直接获取请求(Request)或会话(Session)的一些信息, ...
- Struts2中ActionContext和ServletActionContext
转自:http://blog.sina.com.cn/s/blog_6c9bac050100y9iw.html 在Web应用程序开发中,除了将请求参数自动设置到Action的字段中,我们往往也需要在A ...
- Actioncontext跟ServletActionContext的区别---未完待续
//public class BaseAction extends ActionSupport{ public static HttpServletRequest getRequest(){ retu ...
随机推荐
- 使用UTF8-CPP转换unicode编码 附录:UTF8和UTF16和UTF32和Unicode编码
本文用于解决如何用C++处理字符串的编码格式.本文采用的是成熟便捷的UTF8库来处理这个问题.首先是下载UTF8库,网址为:http://utfcpp.sourceforge.net/ 为了方便后续使 ...
- jQuery 获取和设置type为hidden的input的值
HTML代码 <input type="hidden" name="type" id="type" value="1&quo ...
- js原生设计模式——2面向对象编程之继承—多继承
1.单对象克隆 <!DOCTYPE html><html lang="en"><head> <meta charset=" ...
- UED大全
http://www.baiduux.com/ 百度UFOhttp://ued.sohu.com/ 搜狐UEDhttp://ued.taobao.com/ 淘宝UEDhttp://www.ued ...
- Java学习之旅基础知识篇:数据类型及流程控制
经过开篇对Java运行机制及相关环境搭建,本篇主要讨论Java程序开发的基础知识点,我简单的梳理一下.在讲解数据类型之前,我顺便提及一下Java注释:单行注释.多行注释以及文档注释,这里重点强调文档注 ...
- 关于异常“The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine”的处理
我们在利用SqlBlukcopy技术倒2010 或者2007格式的文件到SqlServer 数据库的时候,会发生如下错误: 原因如下: 1.在用SQL SERVER 2005访问.xlsx文件(off ...
- puppet的配置清单书写
puppet的配置清单书写 1使用数组,合并同类的 例如你想安装很多软件,如果分开来写的话,很麻烦,不简洁,这时我们可以使用数组来完成 以前我们这样来写 class packages{ package ...
- 测试员浅谈App测试的重点
近年来,手机app也时持续大热.基于安卓和ios的手机app,更是受到众多投资者的青睐.而手机软件测试行业也是如此. 现在听的最多的是web测试和App测试,但实际上两者本质上没有什么区别,性质都一样 ...
- HDU4734(数位dp)
F(x) Time Limit: 1000/500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- 为什么我最终替换掉了NATS
之前公司没有使用msmq/rebbitmq等消息队列,一方面是觉得太重,想避免在引入中间件.另外的原因是公司的业务并不需要消息持久化和确保可送达(at-least-once VS at-more-on ...