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
来操作数据了。
在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
联动的。
可以再前台获取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
来示例一下
2.3.1 修改Action
修改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.3.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。
上一篇: struts2简单拦截器
下一篇: struts2中#,@,%,$
推荐阅读
-
Struts2中表达式与值栈
-
Struts2中Action由Struts2自己管理与由Spring管理的区别(转自别人)
-
struts2中ActionContext与ServletActionContext
-
Struts2中OGNL、ActionContext和值栈及线程安全浅析
-
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session
-
struts2 ActionContext 和ServletActionContext 小结
-
struts2中ActionContext和各种Context转化
-
Struts2中表达式与值栈
-
struts2中获取request、response,与android客户端进行交互(转载)
-
Spring整合Struts2中拦截链与注解的使用