ActionContext

ActionContext

  ActionContext是Action的上下文,Struct2自动在其中保存了一些在Action执行过程中所需的对象,比如session、parameters、locale等。Struts2会根据每个执行HTTp请求的线程来创建对应的ActionContext,即一个线程只有一个唯一的ActionContext。因此,使用者可以使用静态方法ActionContext.getContext()来获取当前线程的ActionContext,也正是由于这个原因,使用者不用去操心让Action是线程安全的。

  无论如何,ActionContext都是用来存放数据的。Struts2本身会在其中放入不少数据,而使用者也可以放入自己想要的数据。ActionContext本身的数据结构是映射结构,即一个Map,用key来映射value。所以使用者完全可以像使用Map一样来使用它,或者直接使用Action.getContextMap()方法来对Map进行操作。

  Struts2本身在其中放入的数据有Actionlnvocation、application(即ServletContext)、conversionErrors、Locale、action的name、request的参数、HTTP的Session以及值栈等。完整的列表请参考它的Javadoc。

  由于ActionContext的线程唯一和静态方法就能获得的特性,使得在非Action类中可以直接获得它,而不需要等待Action传入或注入。需要注意的是,它仅在由于request而创建的线程中有效(因为request时才创建对应的ActionContext),而在服务器启动的线程中(比如fliter的init方法)无效。由于在非Action类中访问其的方便性,ActionContext也可以用来在非Action类中向JSP传递数据(因为JSP也能很方便的访问它)。

ValueStack与ActionContext的联系和区别

  相同点:它们都是在一次HTTP请求的范围内使用的,即它们的生命周期都是一次请求。
  不同点:值栈是栈的结构,ActionContext是映射(Map)的结构。

  联系:ValueStack.getContext()方法得到的Map其实就是ActionContext的Map。查看Struts2的源代码可知(Struts2.3.1.2的org.apache.struts2.dispatcher.ng.PrepareOperations的第79行,createActionContext方法),在创建ActionContext时,就是把ValueStack.getContext()作为ActionContext的构造函数的参数。所以,ValueStack和ActionContext本质上可以互相获得。

  注意:在一些文档中,会出现把对象存入“stack‘s context”的字样,其实就是把值存入了ActionContext。所以在阅读这些文档时,要看清楚,到底是放入了栈结构(即值栈),还是映射结构(值栈的context,即ActionContext)。

如何获得ActionContext

  在自定义的拦截器中:使用ActionInvocation.getInvocationContext()或者使用ActionContext.getContext()。

  在Action类中:让拦截器注入或者使用ActionContext.getContext()。

  在非Action类中:让Action类传递参数、使用注入机制注入或者使用ActionContext.getContext()。

  注意:只有运行在request线程中的代码才能调用ActionContext.getContext(),否则返回的是null。
在JSP中:一般不需要获得ActionContext本身。

如何向ActionContext存入值

  在拦截器、Action类、非Action类等Java类中:使用ActionContext.put(Object key,Object value)方法。

  在JSP中:标签<S:set value=”…”/>默认将值存入ActionContext中(当然,<s:set>标签还可以把值存到其他地方)。

  另外,许多标签都有var属性(以前用的是id属性,现在id属性已被抛弃),这个属性能向ActionContext存入值,key为var属性的值,value为标签的value值。(有些文档写的是向ValueStack的context存入值,其实是一样的)

如何向ActionContext读取值

  在拦截器、Action类、非Action类等Java类中:使用ActionContext.get(Object key)方法。

  在JSP中:使用#开头的Ognl表达式解析,则需要使用%{}把表达式括起来,于是就会出现类似“%{#name}”的表达式。

  在JSP中:总之,在JSP中使用ActionContext一方面由于它是映射结构,另一方面是能读取Action的一些配置。当你需要为许多Action提供通用的值的话,可以让每个Action都提供getXXX()方法,但更好的方法是在拦截器或JSP模板中把这些通用的值存放到ActionC中(因为拦截器或JSP模板往往通用于多个Action)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 本类将演示拦截器中对ActionContext的操作   
publicclass MyInterceptor extends AbstractInterceptor {

public String intercept(ActionInvocation invocation) throws Exception {
// 获得ActionContext
ActionContext actionContext = invocation.getInvocationContext();
// 存入值
Person person = new Person();
actionContext.put("person", person);
// 获取值
Object value = actionContext.get("person");
// 获取HttpServletRequest
HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST);
// 获取request的Map,即HttpServletRequest.getAttribute(...)和HttpServletRequest.setAttribute(...)所操作的值
Map requestMap = (Map) actionContext.get("request");
// 其他代码
// ......
return invocation.invoke();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 本类将演示在Action中对ActionContext进行操作   
publicclass MyAction extends ActionSupport {

@Override
public String execute() throws Exception {
// 获得值栈
ActionContext actionContext = ActionContext.getContext();
// 存入值
Person person = new Person();// 这是之前例子中定义的类
actionContext.put("person", person);
// 获取值
Object object = actionContext.get("person");
// 其他代码
// ......
return SUCCESS;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>  
<html>
<head>
<metahttp-equiv="Content-Type"content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<!-- 本JSP将演示在JSP中对ActionContext的使用 -->
<!-- 本JSP为MyAction对应的JSP -->

<!-- 由于Action中已经向ActionContext存入了key为"person"的值,所以可以使用“#person”来获取它,如下 -->
<s:propertyvalue="#person"/>
<!-- 获得person的name属性,如下 -->
<s:propertyvalue="#person.name"/>
<!-- 获得Struts2在ActionContext中存入的值,比如request的Map,如下 -->
<s:propertyvalue="#request"/>
<!-- 获得Struts2在ActionContext中存入的值,比如session的Map,如下 -->
<s:propertyvalue="#session"/>
<!-- 获得Struts2在ActionContext中存入的值,request请求传递的GET参数或POST参数的Map,如下 -->
<s:propertyvalue="#parameters"/>

<!-- 以下演示在JSP中把值存入ActionContext中 -->
<!-- 存入一个字符串"myName",key为"myKey",如下 -->
<s:setvalue="%{‘myName‘}"var="myKey"/>
<!-- 使用s:bean标签来创建一个对象,并把它存入ActionContext中,key为myObject,如下 -->
<s:beanname="com.example.Person"var="myObject"/>
<!-- 之后就可以用“#”来读取它们,如下 -->
<s:propertyvalue="#myKey"/>
<s:propertyvalue="#myObject"/>
</body>
</html>