声明:本文参考Struts2版本为2.3.1.2,内容仅供参考,限于笔者水平有限,不免有所疏漏,望您能友善指出。本文发表于ITEYE,谢绝转载。css
1. ValueStack
ValueStack在中文版的《Struts2深刻浅出》一书中译做“值栈”。其自己数据结构是一个栈,使用者能够把一些对象(又称做bean)存入值栈中,而后使用动态的表达式来读取bean的属性,或者对bean进行一些其余操做。因为值栈中可能有多个bean,值栈会按bean出栈的顺序依次尝试使用动态的表达式来读取值,直到成功读取值为止。在Struts2中,默认的值栈实现是OgnlValueStack,即默认使用Ognl这个动态表达式语言来读取值。html
在Struts2执行一次请求的过程当中,Struts2会把当前的Action对象自动放入值栈。这样,在渲染JSP时,JSP里的代码使用<s:property value="..."/>之类标签中的Ognl表达式会直接做用于Action对象,从而方便的读取Action的属性。java
如何获得值栈:
- 在自定义的拦截器中,使用ActionInvocation.getStack()方法( ActionInvocation 是拦截器的方法参数)。
- 在Action类中,让拦截器注入ValueStack或者使用ActionContext.getContext().getValueStack()来值栈(ActionContext.getContext()为静态方法)。注意:ActionContext分配context的方式是基于线程的,若是使用这种方法,请确保它不会出错。
- 在JSP中,直接使用标签便可得到值栈里的数据,而通常不用获取值栈自己。
如何将对象存入值栈:
- Struts2自动存入Action:以前已经提到,Struts2在执行一次请求的过程当中会把当前的Action对象自动存入值栈中。
- ModelDrivenInterceptor会存入Action的model属性:若是你使用了Struts2提供的 ModelDrivenInterceptor,则它会把Action对象的getModel()方法获得的对象存入值栈中。此时,值栈最底层为Action类,其次为这个model。
- 在自定义的拦截器中存入值栈:获得值栈对象后调用ValueStack.put(Object object)方法。
- 在Action类中存入值栈:获得值栈对象后调用ValueStack.put(Object object)方法。
- 在JSP中存入值栈:标签<s:push value="..."></s:push>是专门用来在JSP中把指定的value放入值栈的,但value被放入值栈的时间仅在s:push标签内,即程序运行到</s:push>标签处会把value从值栈中移出。另外,还有一些标签好比<s:iterator/>因为其功能的须要也会把一些对象放到值栈中。
让值栈执行表达式来得到值:
- 在自定义的拦截器中,得到值栈后,使用ValueStack.findValue(...)等方法。
- 在Action类中,得到值栈后,使用ValueStack.findVlaue(...)等方法。
- 在JSP中,一些标签的属性是直接在值栈上执行Ognl表达式的,好比<s:property/>的value属性。若是标签的属性不是直接执行Ognl表达式的,则须要使用“%{}”将表达式括起来,这样Struts2就会以Ognl表达式来执行了。至于到底哪些标签是直接执行Ognl而哪些不是,请参考完整的官方文档。
在JSP中跳过栈顶元素直接访问第二层:
- 在JSP中,使用[0]、[1]等表达式来指定从栈的第几层开始执行表达式。[0]表示从栈顶开始,[1]表示从栈的第二层开始。好比表达式“name”等价于“[0].name”。参见此处。
在JSP中访问值栈对象自己(而不是它们的属性)
- 在表示式中使用top关键字来访问对象自己。好比,表达式“name”等价于“top.name”,表达式“[0].top”等价于“top”,表达式“[1].top.name”等价于“[1].name”。
总之,值栈主要目的是为了让JSP内能方便的访问Action的属性。apache
一些例子:
-
- public class Person {
-
- private String name;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
- }
-
- public class Person {
-
- private String name;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
- }
-
- public class MyInterceptor extends AbstractInterceptor {
-
- public String intercept(ActionInvocation invocation) throws Exception {
-
- ValueStack valueStack = invocation.getStack();
-
- Person person = new Person();
- valueStack.push(person);
-
- String name = (String) valueStack.findValue("name");
-
- return invocation.invoke();
- }
- }
-
- public class MyInterceptor extends AbstractInterceptor {
-
- public String intercept(ActionInvocation invocation) throws Exception {
-
- ValueStack valueStack = invocation.getStack();
-
- Person person = new Person();
- valueStack.push(person);
-
- String name = (String) valueStack.findValue("name");
-
- return invocation.invoke();
- }
- }
-
- public class MyAction extends ActionSupport {
-
- @Override
- public String execute() throws Exception {
-
- ValueStack valueStack = ActionContext.getContext().getValueStack();
-
- Person person = new Person();
- valueStack.push(person);
-
- String name = (String) valueStack.findValue("name");
-
-
- return SUCCESS;
- }
-
- private String message;
- private Person person;
- private List<Person> personList;
-
- public String getMessage() {
- return message;
- }
-
- public Person getPerson() {
- return person;
- }
-
- public List<Person> getPersonList() {
- return personList;
- }
- }
-
- public class MyAction extends ActionSupport {
-
- @Override
- public String execute() throws Exception {
-
- ValueStack valueStack = ActionContext.getContext().getValueStack();
-
- Person person = new Person();
- valueStack.push(person);
-
- String name = (String) valueStack.findValue("name");
-
-
- return SUCCESS;
- }
-
- private String message;
- private Person person;
- private List<Person> personList;
-
- public String getMessage() {
- return message;
- }
-
- public Person getPerson() {
- return person;
- }
-
- public List<Person> getPersonList() {
- return personList;
- }
- }
- <%@page contentType="text/html" pageEncoding="UTF-8"%>
- <%@taglib uri="/struts-tags" prefix="s" %>
- <!DOCTYPE html>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>JSP Page</title>
- </head>
- <body>
-
-
-
-
-
- <s:property value="message"/>
-
- <s:property value="getText(message)"/>
-
- <s:div cssClass="%{message}"/>
-
- <s:push value="person">
- <!-- 在此s:push标签内,值栈的栈顶元素为person,栈顶第二层为action
-
- <s:property value="name"/>
-
- <s:property value="message"/>
-
-
- <s:property value="[0].message"/>
-
- <s:property value="[1].message"/>
-
- <s:property value="top"/>
-
- <s:property value="[0].top"/>
-
- <s:property value="[1].top"/>
- </s:push>
-
-
-
- <s:iterator value="personList">
-
- <s:property value="name"/>
- </s:iterator>
- </body>
- </html>
- <%@page contentType="text/html" pageEncoding="UTF-8"%>
- <%@taglib uri="/struts-tags" prefix="s" %>
- <!DOCTYPE html>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>JSP Page</title>
- </head>
- <body>
-
-
-
-
-
- <s:property value="message"/>
-
- <s:property value="getText(message)"/>
-
- <s:div cssClass="%{message}"/>
-
- <s:push value="person">
- <!-- 在此s:push标签内,值栈的栈顶元素为person,栈顶第二层为action
-
- <s:property value="name"/>
-
- <s:property value="message"/>
-
-
- <s:property value="[0].message"/>
-
- <s:property value="[1].message"/>
-
- <s:property value="top"/>
-
- <s:property value="[0].top"/>
-
- <s:property value="[1].top"/>
- </s:push>
-
-
-
- <s:iterator value="personList">
-
- <s:property value="name"/>
- </s:iterator>
- </body>
- </html>
2.ActionContext
ActionContext是Action的上下文,Struts2自动在其中保存了一些在Action执行过程当中所需的对象,好比session, parameters, locale等。Struts2会根据每一个执行HTTP请求的线程来建立对应的ActionContext,即一个线程有一个惟一的ActionContext。所以,使用者可使用静态方法ActionContext.getContext()来获取当前线程的ActionContext,也正是因为这个缘由,使用者不用去操心让Action是线程安全的。api
不管如何,ActionContext都是用来存放数据的。Struts2自己会在其中放入很多数据,而使用者也能够放入本身想要的数据。ActionContext自己的数据结构是映射结构,即一个Map,用key来映射value。因此使用者彻底能够像使用Map同样来使用它,或者直接使用Action.getContextMap()方法来对Map进行操做。浏览器
Struts2自己在其中放入的数据有ActionInvocation、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表达式,好比<s:property value="#name"/>会调用ActionContext.get("name")方法。注意:若是某标签的属性默认不做为Ognl表达式解析,则须要使用%{}把表达式括起来,因而就会出现相似“%{#name}的表达式”。(“#”的更多用途参见这里)
总之,在JSP中使用ActionContext一方面是因为它是映射结构,另外一方面是能读取Action的一些配置。当你须要为许多Action提供通用的值的话,可让每一个Action都提供getXXX()方法,但更好的方法是在拦截器或JSP模板中把这些通用的值存放到ActionContext中(由于拦截器或JSP模板每每通用于多个Action)。
一些例子:
-
- public class MyInterceptor extends AbstractInterceptor {
-
- public String intercept(ActionInvocation invocation) throws Exception {
-
- ActionContext actionContext = invocation.getInvocationContext();
-
- Person person = new Person();
- actionContext.put("person", person);
-
- Object value = actionContext.get("person");
-
- HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST);
-
- Map requestMap = (Map) actionContext.get("request");
-
-
- return invocation.invoke();
- }
- }
-
- public class MyInterceptor extends AbstractInterceptor {
-
- public String intercept(ActionInvocation invocation) throws Exception {
-
- ActionContext actionContext = invocation.getInvocationContext();
-
- Person person = new Person();
- actionContext.put("person", person);
-
- Object value = actionContext.get("person");
-
- HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST);
-
- Map requestMap = (Map) actionContext.get("request");
-
-
- return invocation.invoke();
- }
- }
-
- public class 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;
- }
- }
-
- public class 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;
- }
- }
- <!DOCTYPE html>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>JSP Page</title>
- </head>
- <body>
-
-
-
-
- <s:property value="#person"/>
-
- <s:property value="#person.name"/>
-
- <s:property value="#request"/>
-
- <s:property value="#session"/>
-
- <s:property value="#parameters"/>
-
-
-
- <s:set value="%{'myName'}" var="myKey"/>
-
- <s:bean name="com.example.Person" var="myObject"/>
-
- <s:property value="#myKey"/>
- <s:property value="#myObject"/>
- </body>
- </html>
- <!DOCTYPE html>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>JSP Page</title>
- </head>
- <body>
-
-
-
-
- <s:property value="#person"/>
-
- <s:property value="#person.name"/>
-
- <s:property value="#request"/>
-
- <s:property value="#session"/>
-
- <s:property value="#parameters"/>
-
-
-
- <s:set value="%{'myName'}" var="myKey"/>
-
- <s:bean name="com.example.Person" var="myObject"/>
-
- <s:property value="#myKey"/>
- <s:property value="#myObject"/>
- </body>
- </html>
3. HttpServletRequest类或request的Map
Struts2中提供了两种对request的操做:一种是Web服务器提供的HttpServletRequest类,这和传统Java Web项目中的操做request的方式相同;另外一种是一个“request的Map”,即封装了HttpServletRequest的attributes的映射类,操做该Map至关于操做HttpServletRequest的attributes。之因此提供了Map的操做方式,一是方便操做,二是能方便使用Ognl在JSP标签中读取request。不管如何,这两个request是互通的。至于request的生命周期等概念,与其余的Java Web项目没有区别,本文再也不详述。session
使用HttpServletRequest类仍是request的Map
- 虽然二者是互通的,但就读取request的attributes而言,使用request的Map要方便许多,而且不会暴露没必要要的接口。固然,HttpServletRequest有一些request的Map没有的方法,使用这些方法时固然仍是要用前者。
使用request的Map仍是ActionContext:
- 二者都是Map,二者的生命周期都是一个请求。
- 传统的Java Web项目中,每每是经过request的attributes来向JSP传递值的:先在Servlet里setAttribute(),而后在JSP里getAttribute()。固然在Struts2的项目中,你仍然可使用这个方法,然而抛弃了Struts2提供的传递功能是得不偿失的。虽然笔者没有找到官方文档说必定要用ActionContext替换request的Map,也没有发现程序中有能得到ActionContext却得到不了request的Map的地方,但在Struts2框架下,操做ActionContext要比操做request的Map更加方便。所以,笔者建议:尽可能使用ActionContext而不是request的Map来传递值。
- request的Map有时候会包含其余框架设置的值,好比Spring框架。获取这些值的时候就须要用request的Map了,由于ActionContext里没有。
- 经过ActionContext能够得到HttpServletRequest类:“HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST);”。
- 经过ActionContext也能够得到request的Map:“Map requestMap = (Map) actionContext.get("request");”。所以,在JSP标签中,使用表达式“#request”就能够得到request的Map的数据。
如何得到HttpServletRequest:
- 若是已经有ActionContext,则使用“actionContext.get(StrutsStatics.HTTP_REQUEST)”来得到HttpServletRequest。
- 在自定义的拦截器中,先得到ActionContext,再经过ActionContext来得到。
- 在Action中,先得到ActionContext,再经过ActionContext来得到。或者让Action实现ServletRequestAware接口,并使用ServletConfigInterceptor拦截器,这样这个拦截器就会注入HttpServletRequest。
- 在JSP中,通常不须要得到HttpServletRequest。
如何得到request的Map:
- 若是已经有ActionContext,则使用“actionContext.get("request")”来得到。
- 在自定义的拦截器中,先得到 ActionContext,再经过ActionContext来得到。
- 在Action中,先得到ActionContext,再经过ActionContext来得到。或者让Action实现RequestAware接口,并使用ServletConfigInterceptor拦截器,这样这个拦截器就会注入Map request。
- 在JSP中,用“#request”来得到request的Map,用“#request.key”或者“#request['key']”来读取Map中的值。
总之,request仍然符合Java Web网站的通常规律。不过笔者建议使用者应尽可能避免用request传值。数据结构
一些例子:
-
- public class MyInterceptor extends AbstractInterceptor {
-
- public String intercept(ActionInvocation invocation) throws Exception {
-
- ActionContext actionContext = invocation.getInvocationContext();
-
- HttpServletRequest httpServletRequest=(HttpServletRequest)actionContext.get(StrutsStatics.HTTP_REQUEST);
-
- Map requestMap = (Map) actionContext.get("request");
-
- Person person = new Person();
-
- httpServletRequest.setAttribute("person", person);
- requestMap.put("person", person);
-
-
- return invocation.invoke();
- }
- }
-
- public class MyInterceptor extends AbstractInterceptor {
-
- public String intercept(ActionInvocation invocation) throws Exception {
-
- ActionContext actionContext = invocation.getInvocationContext();
-
- HttpServletRequest httpServletRequest=(HttpServletRequest)actionContext.get(StrutsStatics.HTTP_REQUEST);
-
- Map requestMap = (Map) actionContext.get("request");
-
- Person person = new Person();
-
- httpServletRequest.setAttribute("person", person);
- requestMap.put("person", person);
-
-
- return invocation.invoke();
- }
- }
-
- public class MyAction extends ActionSupport {
-
- @Override
- public String execute() throws Exception {
-
- ActionContext actionContext = ActionContext.getContext();
-
- HttpServletRequest httpServletRequest=(HttpServletRequest)actionContext.get(StrutsStatics.HTTP_REQUEST);
-
- Map requestMap = (Map) actionContext.get("request");
-
- Person person = new Person();
-
- httpServletRequest.setAttribute("person", person);
- requestMap.put("person", person);
-
-
- return SUCCESS;
- }
- }
-
- public class MyAction extends ActionSupport {
-
- @Override
- public String execute() throws Exception {
-
- ActionContext actionContext = ActionContext.getContext();
-
- HttpServletRequest httpServletRequest=(HttpServletRequest)actionContext.get(StrutsStatics.HTTP_REQUEST);
-
- Map requestMap = (Map) actionContext.get("request");
-
- Person person = new Person();
-
- httpServletRequest.setAttribute("person", person);
- requestMap.put("person", person);
-
-
- return SUCCESS;
- }
- }
-
- public class MyAction extends ActionSupport implements ServletRequestAware {
-
- private HttpServletRequest request;
-
-
- public void setServletRequest(HttpServletRequest request) {
- this.request = request;
- }
-
- @Override
- public String execute() throws Exception {
-
-
- return SUCCESS;
- }
- }
-
- public class MyAction extends ActionSupport implements ServletRequestAware {
-
- private HttpServletRequest request;
-
-
- public void setServletRequest(HttpServletRequest request) {
- this.request = request;
- }
-
- @Override
- public String execute() throws Exception {
-
-
- return SUCCESS;
- }
- }
-
- public class MyAction extends ActionSupport implements RequestAware {
-
- Map<String, Object> request;
-
-
- public void setRequest(Map<String, Object> request) {
- this.request = request;
- }
-
- @Override
- public String execute() throws Exception {
-
-
- return SUCCESS;
- }
- }
-
- public class MyAction extends ActionSupport implements RequestAware {
-
- Map<String, Object> request;
-
-
- public void setRequest(Map<String, Object> request) {
- this.request = request;
- }
-
- @Override
- public String execute() throws Exception {
-
-
- return SUCCESS;
- }
- }
- <!DOCTYPE html>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>JSP Page</title>
- </head>
- <body>
- <!-- 本JSP将演示在JSP中对request的Map的使用 -->
- <!-- 本JSP为MyAction对应的JSP -->
-
- <!-- request的Map是Struts2自动在ActionContext中存入的值(key为request),因此使用“#”来访问ActionContext,从中读取request -->
- <s:property value="#request"/>
- <!-- 如下两行均是访问request的Map中key为“name”的值 -->
- <s:property value="#request.name"/>
- <s:property value="#request['name']"/>
- </body>
- </html>
- <!DOCTYPE html>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>JSP Page</title>
- </head>
- <body>
- <!-- 本JSP将演示在JSP中对request的Map的使用 -->
- <!-- 本JSP为MyAction对应的JSP -->
-
- <!-- request的Map是Struts2自动在ActionContext中存入的值(key为request),因此使用“#”来访问ActionContext,从中读取request -->
- <s:property value="#request"/>
- <!-- 如下两行均是访问request的Map中key为“name”的值 -->
- <s:property value="#request.name"/>
- <s:property value="#request['name']"/>
- </body>
- </html>
3. Parameters,即GET请求或POST请求的参数
Parameters为GET或POST等请求时浏览器向服务器传递而来的参数。在传统的Java Web项目中,使用HttpServletRequest.getParameter()等方法来获取参数,而且能够直接使用HttpServletRequest.getParameterMap()来得到一个封装了参数的Map。而在Struts2中,Struts2直接把上述Map存放到了ActionContext中,key为“parameters”。另外,ActionContext还直接提供了ActionContext.getParameters()方法来得到这个Map。所以,在Struts2的各个部件中操做parameters的方法和操做request的Map的方法十分类似,本段再也不详述。
4. HttpServletSession类和session的Map
传统Java Web项目中的session是咱们都熟悉的,咱们用它来记录一个用户的会话状态。Struts2把HttpServletSession封装到了一个Map中,即“session的Map”,这相似对request的处理。然而为了节省系统资源,咱们在不须要session的时候不会建立session。可能正是由于这个缘故,Struts2中没有把HttpServletSession放入ActionContext中,若是你的程序须要使用HttpServletSession,应该先得到HttpServletRequest,而后使用getSession()或getSession(boolean b)来得到它,同时决定是否须要建立session。对于session的Map,Struts2仍然把它放入了ActionContext中(key为"session"),可是不要担忧,这个Map的机制使得只有put新值时才会建立session。总之,Struts2中对HttpServletSession的操做要先经过HttpServletRequest来得到它,而对session的Map的操做与对request的Map的操做一模一样,本段再也不详述。
5. ServletContext和application的Map
传统的Java Web项目中,ServletContext用来存放全局变量,每一个Java虚拟机每一个Web项目只有一个ServletContext。这个ServletContext是由Web服务器建立的,来保证它的惟一性。ServletContext有一些方法能操做它的attributes,这些操做方法和操做一个Map相似。因而,Struts2又来封装了:它把ServletContext的attributes封装到了一个Map中,即“application的Map”,而且也放入的ActionContext中(key为application),所以,对application的Map的操做就若是对request的Map操做,本段再也不详述。
至于对ServletContext的操做,与HttpServletRequest的操做相似:Struts2将ServletContext放到了 ActionContext中,而且ServletConfigInterceptor提供了对ServletContext的注入接口ServletContextAware。所以,本段再也不详述。
注意:在Ognl表达式中使用“#application”能够获得application的Map,而不是ServletContext。然而在JSP嵌入的Java代码中(好比“<% application.getAttribute(""); %>”),application为ServletContext,而不是Map。
用一张表格来总结:
变量 |
从ActionContext中得到 |
生命周期 |
用Ongl来读取值 |
使用ServletConfigInterceptor来注入 |
ActionContext类 |
静态方法ActionContext. getContext() |
一次Http请求 |
使用“#”加上key,如“#name” |
没法注入 |
ValueStack类 |
ActionContext. getValueStack() |
一次Http请求 |
直接填写来访问栈中对象的方法,或者使用top来直接得到栈中对象 |
没法注入 |
HttpServletRequest类 |
ActionContext. get( StrutsStatics. HTTP_REQUEST) |
一次Http请求 |
无方便的方法 |
实现ServletRequestAware接口 |
request的Map |
ActionContext. get("request") |
一次Http请求 |
使用“#request”再加上key,如“#request.name”或者“#request['name']” |
实现RequestAware接口 |
parameters的Map |
ActionContext. get( "parameters") |
一次Http请求 |
使用“# parameters”再加上key,如“#parameters .name”或者“#parameters ['name']” |
实现ParameterAware接口 |
HttpServletSession类 |
无(需经过HttpServletRequest来得到) |
一次Http Session会话 |
无方便的方法 |
没法注入 |
session的Map |
ActionContext. get("session") |
每次请求建立,但在一次Http Session会话中数据都是同样的 |
使用“#session”再加上key,如“# session.name”或者“#session ['name']” |
实现SessionAware接口 |
ServletContext类 |
ActionContext. get( StrutsStatics. SERVLET_CONTEXT) |
网站项目启动后一直存在且惟一 |
无方便的方法 |
使用ServletContextAware接口 |
application的Map |
ActionContext.get( "application") |
每次请求时建立,但其中的数据是网站项目启动后一直存在且共享 |
使用“# application”再加上key,如“#application .name”或者“#application ['name']” |
使用ApplicationAware接口 |
附录1 ActionContext中到底有哪些数据
key |
key的声明处 |
value的类型 |
value.toString() |
com. opensymphony. xwork2. dispatcher. HttpServletRequest |
StrutsStatics. HTTP_REQUEST |
org. apache. struts2. dispatcher. StrutsRequestWrapper |
org. apache. struts2. dispatcher. StrutsRequestWrapper @10984e0 |
application |
无 |
org. apache. struts2. dispatcher. ApplicationMap |
略 |
com. opensymphony. xwork2. ActionContext. locale |
ActionContext. LOCALE |
java. util. Locale |
zh_CN |
com. opensymphony. xwork2. dispatcher. HttpServletResponse |
StrutsStatics. HTTP_RESPONSE |
org. apache. catalina. connector. ResponseFacade |
org. apache. catalina. connector. ResponseFacade @14ecfe8 |
xwork. NullHandler. createNullObjects |
|
Boolean |
false |
com. opensymphony. xwork2. ActionContext. name |
ActionContext. ACTION_NAME |
String |
index |
com.opensymphony. xwork2.ActionContext. conversionErrors |
ActionContext. CONVERSION_ERRORS |
java. util. HashMap |
{} |
com. opensymphony. xwork2. ActionContext. application |
ActionContext. APPLICATION |
org. apache. struts2. dispatcher. ApplicationMap |
略 |
attr |
无 |
org. apache. struts2. util. AttributeMap |
org. apache. struts2. util. AttributeMap @133a2a8 |
com. opensymphony. xwork2. ActionContext. container |
ActionContext. CONTAINER |
com. opensymphony. xwork2. inject. ContainerImpl |
com. opensymphony. xwork2. inject. ContainerImpl @fc02c8 |
com. opensymphony. xwork2. dispatcher. ServletContext |
StrutsStatics. SERVLET_CONTEXT |
org. apache. catalina. core. ApplicationContextFacade |
org. apache. catalina. core. ApplicationContextFacade @11ad78c |
com. opensymphony. xwork2. ActionContext. session |
ActionContext. SESSION |
org.apache.struts2. dispatcher.SessionMap |
{} |
com.opensymphony. xwork2.ActionContext. actionInvocation |
ActionContext. ACTION_INVOCATION |
com. opensymphony. xwork2. DefaultActionInvocation |
com. opensymphony. xwork2. DefaultActionInvocation @13d4497 |
xwork. MethodAccessor. denyMethodExecution |
笔者很懒,没有找 |
Boolean |
false |
report. conversion. errors |
笔者很懒,没有找 |
Boolean |
false |
session |
无 |
org. apache. struts2. dispatcher. SessionMap |
{} |
com. opensymphony. xwork2. util. ValueStack. ValueStack |
ValueStack.VALUE_STACK |
com. opensymphony. xwork2. ognl. OgnlValueStack |
com. opensymphony. xwork2. ognl. OgnlValueStack @16237fd |
request |
无 |
org. apache. struts2. dispatcher. RequestMap |
略 |
action |
笔者很懒,没有找 |
com. example. MyAction |
略 |
struts. actionMapping |
笔者很懒,没有找 |
org. apache. struts2. dispatcher. mapper. ActionMapping |
org. apache. struts2. dispatcher. mapper. ActionMapping @892cc5 |
parameters |
无 |
java. util. HashMap |
{} |
com. opensymphony. xwork2. ActionContext. parameters |
ActionContext.PARAMETERS |
java. util. TreeMap |
{} |
注意:该表格为了排版在某些地方加了空格。
能够看出,有些相同的对象被以不一样的key屡次设置到ActionContext中。若是想看看建立ActionContext的源代码,请看org.apache.struts2.dispatcher.Dispatcher的serviceAction方法和两个createContextMap方法。
附录2 Struts2标签中value属性直接对ActionContext访问的问题
经试验并查看相关源代码后发现,在使用<s:property value="..."/>时,该标签的执行类会先根据value中表达式到值栈中执行表达式来查找值。若是在值栈中找到值,就返回该值;若是没有找到,则把该表达式做为ActionContext的key,到ActionContext中去找值。好比<s:property value="request"/>也会获得ActionContext中的request,等价于<s:property value="#request"/>。可是,因为标签的执行类会认为该值时String类型的,而且会直接进行类型转换。因而,若是直接使用<s:property value="request"/>的话其实会让页面抛出异常:Request类型不能转换成String类型。因此,只能用若是不带#的话只能成功读取ActionContext中String类型的值。这种机制使得某些时候栈顶的属性能够覆盖ActionContext中的key,或许你正须要它。然而,鉴于这种机制的不肯定性,笔者建议访问ActionContext中的数据必定要带上“#”,能够免去一些麻烦。
关于这种转型异常,笔者认为是Struts2的bug,源代码以下,当“value = getValue(expr, asType);”时,是考虑了asType的,但从context中读取时“value = findInContext(expr);”,就没有考虑asType,而且没有在其余地方看到类型检查操做:
-
- private Object tryFindValue(String expr, Class asType) throws OgnlException {
- Object value = null;
- try {
- expr = lookupForOverrides(expr);
- value = getValue(expr, asType);
- if (value == null) {
- value = findInContext(expr);
- }
- } finally {
- context.remove(THROW_EXCEPTION_ON_FAILURE);
- }
- return value;
- }
-
- private Object tryFindValue(String expr, Class asType) throws OgnlException {
- Object value = null;
- try {
- expr = lookupForOverrides(expr);
- value = getValue(expr, asType);
- if (value == null) {
- value = findInContext(expr);
- }
- } finally {
- context.remove(THROW_EXCEPTION_ON_FAILURE);
- }
- return value;
- }