在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等 .

  public class TopicAction extends ActionSupport {
private Long forumId;
private Topic topic;
private Reply reply;
private Forum forum;
public String show() throws Exception {
ActionContext.getContext().put("topic", topic);
ActionContext.getContext().getValueStack().push(pageBean);
}

ActionContext.getContext().getValueStack().push(pageBean);和ACTION里有get,set方法的会放进值栈。

Value Stack Contents

Object




Property Name



Property Value



cn.itcastoa.oa.domain.PageBeanrecordCount15
pageCount5
endPageIndex5
recordList[cn.itcastoa.oa.domain.Reply@1c3892, cn.itcastoa.oa.domain.Reply@c611eb, cn.itcastoa.oa.domain.Reply@1c261da]
beginPageIndex1
pageSize3
currentPage1
cn.itcastoa.oa.view.TopicActiontopiccn.itcastoa.oa.domain.Topic@9fce4a
textsnull
forumnull
errorMessages[]
forumServicecn.itcastoa.oa.service.impl.ForumServiceImpl@5456ed
localezh_CN
actionMessages[]
pageSize3
pageNum1
actionErrors[]
errors{}
fieldErrors{}
forumIdnull
containerThere is no read method for container
replynull
topicServicecn.itcastoa.oa.service.impl.TopicServiceImpl@187c18
com.opensymphony.xwork2.DefaultTextProvidertextsnull

=======

Stack Context

These items are available using the #key notation







Key
Value





com.opensymphony.xwork2.dispatcher.HttpServletRequestorg.apache.struts2.dispatcher.StrutsRequestWrapper@126a9cc
com.opensymphony.xwork2.ActionContext.localezh_CN
com.opensymphony.xwork2.dispatcher.HttpServletResponseorg.apache.catalina.connector.ResponseFacade@15595cc
com.opensymphony.xwork2.ActionContext.nametopic_show
com.opensymphony.xwork2.ActionContext.application{org.apache.catalina.WELCOME_FILES=[Ljava.lang.String;@17187ea, org.apache.jasper.runtime.JspApplicationContextImpl=org.apache.jasper.runtime.JspApplicationContextImpl@11e4e2a, org.directwebremoting.WebContextFactory$WebContextBuilder=org.directwebremoting.impl.DefaultWebContextBuilder@836c07, javax.servlet.http.HttpServlet=org.directwebremoting.servlet.DwrServlet@18c262c, org.directwebremoting.impl.ServerContext=org.directwebremoting.impl.DefaultServerContext@125c043, org.directwebremoting.ContainerList=[org.directwebremoting.impl.DefaultContainer@295b86], topPriviledgeList=[cn.itcastoa.oa.domain.Priviledge@c9fb2b, cn.itcastoa.oa.domain.Priviledge@142d6c7, cn.itcastoa.oa.domain.Priviledge@122cf92], contextConfigLocation=classpath:beans.xml, org.directwebremoting.Container=org.directwebremoting.impl.DefaultContainer@295b86, org.apache.AnnotationProcessor=org.apache.catalina.util.DefaultAnnotationProcessor@2d1076, allPriviledgeUrls=[null, /role_list, /department_list, /user_list, /role_edit, /role_add, /role_delete, /department_edit, /department_add, /department_delete, /user_edit, /user_add, /user_delete, /user_initPassword, /forumManage_list, /forum_list, /processDefinition_list, /template_list, /flow_templateList, /flow_myTaskList, /flow_myApplicationList], javax.servlet.context.tempdir=G:\tomcat\work\Catalina\localhost\ItcastOA, .freemarker.Application=freemarker.ext.servlet.ServletContextHashModel@137f2ea, org.apache.catalina.jsp_classpath=/G:/tomcat/webapps/ItcastOA/WEB-INF/classes/;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/antlr-2.7.6.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/aspectjrt.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/aspectjweaver.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/c3p0-0.9.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/cglib-nodep-2.1_3.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/common-annotations.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-codec.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-collections-3.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-dbcp.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-fileupload-1.2.2.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-io-2.0.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-lang3-3.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-logging-1.1.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-logging.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-pool.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/dom4j-1.6.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/dwr.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/ejb3-persistence.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/freemarker-2.3.19.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/hibernate-annotations.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/hibernate-commons-annotations.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/hibernate3.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/javassist-3.9.0.GA.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/jta-1.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/junit.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/log4j-1.2.14.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/mysql-connector-java-3.1.13-bin.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/ognl-3.0.5.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/ojdbc14.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/org.hamcrest.core_1.1.0.v20090501071000.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/slf4j-api-1.5.8.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/slf4j-log4j12-1.5.8.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/spring.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/struts2-core-2.3.4.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/struts2-spring-plugin-2.3.4.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/xwork-core-2.3.4.1.jar;/G:/tomcat/lib/;/G:/tomcat/lib/annotations-api.jar;/G:/tomcat/lib/catalina-ant.jar;/G:/tomcat/lib/catalina-ha.jar;/G:/tomcat/lib/catalina-tribes.jar;/G:/tomcat/lib/catalina.jar;/G:/tomcat/lib/ecj-3.3.1.jar;/G:/tomcat/lib/el-api.jar;/G:/tomcat/lib/jasper-el.jar;/G:/tomcat/lib/jasper.jar;/G:/tomcat/lib/jsp-api.jar;/G:/tomcat/lib/servlet-api.jar;/G:/tomcat/lib/tomcat-coyote.jar;/G:/tomcat/lib/tomcat-dbcp.jar;/G:/tomcat/lib/tomcat-i18n-es.jar;/G:/tomcat/lib/tomcat-i18n-fr.jar;/G:/tomcat/lib/tomcat-i18n-ja.jar;/G:/tomcat/bin/bootstrap.jar;/C:/Program%20Files/Java/jdk1.7.0/lib/tools.jar;/C:/Program%20Files/Java/jdk1.7.0/jre/lib/ext/dnsns.jar;/C:/Program%20Files/Java/jdk1.7.0/jre/lib/ext/localedata.jar;/C:/Program%20Files/Java/jdk1.7.0/jre/lib/ext/sunec.jar;/C:/Program%20Files/Java/jdk1.7.0/jre/lib/ext/sunjce_provider.jar;/C:/Program%20Files/Java/jdk1.7.0/jre/lib/ext/sunmscapi.jar;/C:/Program%20Files/Java/jdk1.7.0/jre/lib/ext/sunpkcs11.jar;/C:/Program%20Files/Java/jdk1.7.0/jre/lib/ext/zipfs.jar, .freemarker.JspTaglibs=freemarker.ext.jsp.TaglibFactory@1e49dd, org.springframework.web.context.WebApplicationContext.ROOT=org.springframework.web.context.support.XmlWebApplicationContext@376e79: display name [Root WebApplicationContext]; startup date [Sun Jun 16 22:15:08 CST 2013]; root of context hierarchy, javax.servlet.ServletConfig=org.apache.catalina.core.StandardWrapperFacade@9226da, org.apache.catalina.resources=org.apache.naming.resources.ProxyDirContext@9dac13, freemarker.Configuration=freemarker.template.Configuration@134d354}
com.opensymphony.xwork2.ActionContext.conversionErrors{}
__component_stack[org.apache.struts2.components.Debug@1dd900b]
last.property.accessednull
com.opensymphony.xwork2.dispatcher.ServletContextorg.apache.catalina.core.ApplicationContextFacade@f5ba4b
com.opensymphony.xwork2.dispatcher.PageContextorg.apache.jasper.runtime.PageContextImpl@5c48ad
__requestWrapper.getAttributefalse
request{javax.servlet.forward.request_uri=/ItcastOA/topic_show.action, javax.servlet.forward.query_string=topic.id=13, openSessionInView.FILTERED=true, struts.valueStack=com.opensymphony.xwork2.ognl.OgnlValueStack@50b809, struts.view_uri=/WEB-INF/jsp/topicAction/show.jsp, struts.request_uri=/ItcastOA/topic_show.action, javax.servlet.forward.servlet_path=/topic_show.action, struts.actionMapping=org.apache.struts2.dispatcher.mapper.ActionMapping@ffec96, .freemarker.RequestParameters=freemarker.ext.servlet.HttpRequestParametersHashModel@56d63, __cleanup_recursion_counter=1, .freemarker.Request=freemarker.ext.servlet.HttpRequestHashModel@a6b623, .freemarker.TemplateModel={Parameters=freemarker.ext.servlet.HttpRequestParametersHashModel@56d63, tag=org.apache.struts2.components.Debug@1dd900b, Request=freemarker.ext.servlet.HttpRequestHashModel@a6b623, .freemarker.RequestParameters=freemarker.ext.servlet.HttpRequestParametersHashModel@56d63, JspTaglibs=freemarker.ext.jsp.TaglibFactory@1e49dd, struts=org.apache.struts2.util.StrutsUtil@1629287, response=org.apache.catalina.connector.ResponseFacade@15595cc, s=org.apache.struts2.views.freemarker.tags.StrutsModels@820dfd, themeProperties={}, ognl=org.apache.struts2.views.jsp.ui.OgnlTool@89279c, session=org.apache.catalina.session.StandardSessionFacade@878581, Session=freemarker.ext.servlet.HttpSessionHashModel@647e21, Application=freemarker.ext.servlet.ServletContextHashModel@137f2ea, request=org.apache.struts2.dispatcher.StrutsRequestWrapper@126a9cc, action=cn.itcastoa.oa.view.TopicAction@194b610, base=/ItcastOA, stack=com.opensymphony.xwork2.ognl.OgnlValueStack@50b809}, javax.servlet.forward.context_path=/ItcastOA}
last.bean.accessednull
actioncn.itcastoa.oa.view.TopicAction@194b610
parameters{topic.id=[Ljava.lang.String;@3cf2ff}
topiccn.itcastoa.oa.domain.Topic@9fce4a
application{org.apache.catalina.WELCOME_FILES=[Ljava.lang.String;@17187ea, org.apache.jasper.runtime.JspApplicationContextImpl=org.apache.jasper.runtime.JspApplicationContextImpl@11e4e2a, org.directwebremoting.WebContextFactory$WebContextBuilder=org.directwebremoting.impl.DefaultWebContextBuilder@836c07, javax.servlet.http.HttpServlet=org.directwebremoting.servlet.DwrServlet@18c262c, org.directwebremoting.impl.ServerContext=org.directwebremoting.impl.DefaultServerContext@125c043, org.directwebremoting.ContainerList=[org.directwebremoting.impl.DefaultContainer@295b86], topPriviledgeList=[cn.itcastoa.oa.domain.Priviledge@c9fb2b, cn.itcastoa.oa.domain.Priviledge@142d6c7, cn.itcastoa.oa.domain.Priviledge@122cf92], contextConfigLocation=classpath:beans.xml, org.directwebremoting.Container=org.directwebremoting.impl.DefaultContainer@295b86, org.apache.AnnotationProcessor=org.apache.catalina.util.DefaultAnnotationProcessor@2d1076, allPriviledgeUrls=[null, /role_list, /department_list, /user_list, /role_edit, /role_add, /role_delete, /department_edit, /department_add, /department_delete, /user_edit, /user_add, /user_delete, /user_initPassword, /forumManage_list, /forum_list, /processDefinition_list, /template_list, /flow_templateList, /flow_myTaskList, /flow_myApplicationList], javax.servlet.context.tempdir=G:\tomcat\work\Catalina\localhost\ItcastOA, .freemarker.Application=freemarker.ext.servlet.ServletContextHashModel@137f2ea, org.apache.catalina.jsp_classpath=/G:/tomcat/webapps/ItcastOA/WEB-INF/classes/;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/antlr-2.7.6.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/aspectjrt.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/aspectjweaver.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/c3p0-0.9.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/cglib-nodep-2.1_3.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/common-annotations.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-codec.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-collections-3.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-dbcp.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-fileupload-1.2.2.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-io-2.0.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-lang3-3.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-logging-1.1.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-logging.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/commons-pool.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/dom4j-1.6.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/dwr.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/ejb3-persistence.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/freemarker-2.3.19.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/hibernate-annotations.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/hibernate-commons-annotations.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/hibernate3.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/javassist-3.9.0.GA.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/jta-1.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/junit.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/log4j-1.2.14.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/mysql-connector-java-3.1.13-bin.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/ognl-3.0.5.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/ojdbc14.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/org.hamcrest.core_1.1.0.v20090501071000.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/slf4j-api-1.5.8.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/slf4j-log4j12-1.5.8.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/spring.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/struts2-core-2.3.4.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/struts2-spring-plugin-2.3.4.1.jar;/G:/tomcat/webapps/ItcastOA/WEB-INF/lib/xwork-core-2.3.4.1.jar;/G:/tomcat/lib/;/G:/tomcat/lib/annotations-api.jar;/G:/tomcat/lib/catalina-ant.jar;/G:/tomcat/lib/catalina-ha.jar;/G:/tomcat/lib/catalina-tribes.jar;/G:/tomcat/lib/catalina.jar;/G:/tomcat/lib/ecj-3.3.1.jar;/G:/tomcat/lib/el-api.jar;/G:/tomcat/lib/jasper-el.jar;/G:/tomcat/lib/jasper.jar;/G:/tomcat/lib/jsp-api.jar;/G:/tomcat/lib/servlet-api.jar;/G:/tomcat/lib/tomcat-coyote.jar;/G:/tomcat/lib/tomcat-dbcp.jar;/G:/tomcat/lib/tomcat-i18n-es.jar;/G:/tomcat/lib/tomcat-i18n-fr.jar;/G:/tomcat/lib/tomcat-i18n-ja.jar;/G:/tomcat/bin/bootstrap.jar;/C:/Program%20Files/Java/jdk1.7.0/lib/tools.jar;/C:/Program%20Files/Java/jdk1.7.0/jre/lib/ext/dnsns.jar;/C:/Program%20Files/Java/jdk1.7.0/jre/lib/ext/localedata.jar;/C:/Program%20Files/Java/jdk1.7.0/jre/lib/ext/sunec.jar;/C:/Program%20Files/Java/jdk1.7.0/jre/lib/ext/sunjce_provider.jar;/C:/Program%20Files/Java/jdk1.7.0/jre/lib/ext/sunmscapi.jar;/C:/Program%20Files/Java/jdk1.7.0/jre/lib/ext/sunpkcs11.jar;/C:/Program%20Files/Java/jdk1.7.0/jre/lib/ext/zipfs.jar, .freemarker.JspTaglibs=freemarker.ext.jsp.TaglibFactory@1e49dd, org.springframework.web.context.WebApplicationContext.ROOT=org.springframework.web.context.support.XmlWebApplicationContext@376e79: display name [Root WebApplicationContext]; startup date [Sun Jun 16 22:15:08 CST 2013]; root of context hierarchy, javax.servlet.ServletConfig=org.apache.catalina.core.StandardWrapperFacade@9226da, org.apache.catalina.resources=org.apache.naming.resources.ProxyDirContext@9dac13, freemarker.Configuration=freemarker.template.Configuration@134d354}
xwork.NullHandler.createNullObjectsfalse
statusnull
current.property.pathnull
attrorg.apache.struts2.util.AttributeMap@17553e2
com.opensymphony.xwork2.ActionContext.containercom.opensymphony.xwork2.inject.ContainerImpl@23df4
com.opensymphony.xwork2.ActionContext.session{user=cn.itcastoa.oa.domain.User@1a10625}
num5
com.opensymphony.xwork2.ActionContext.actionInvocationcom.opensymphony.xwork2.DefaultActionInvocation@a39522
com.opensymphony.xwork2.util.ValueStack.ValueStackcom.opensymphony.xwork2.ognl.OgnlValueStack@50b809
session{user=cn.itcastoa.oa.domain.User@1a10625}
report.conversion.errorsfalse
xwork.MethodAccessor.denyMethodExecutionfalse
struts.actionMappingorg.apache.struts2.dispatcher.mapper.ActionMapping@ffec96
com.opensymphony.xwork2.ActionContext.parameters{topic.id=[Ljava.lang.String;@3cf2ff}

ActionContext.getContext().put("topic", topic);的和request,session里的在stack context里,需要用#取


======================================================================================

若是action的属性,页面若用OGNL表达式直接用%{topic.forum.id}。若是acion里ActionContext.getContext().put("topic", topic); 进的要加#取%{#topic.forum.id}。J2EE标准,这两个都可以用${topic.forum.name}取得。一个是action对象(放在值栈里),一个是actioncontext里。

因为Action在值栈中,而值栈又是OGNL中的根,所以引用Action的属性可以省略“#”标记。

Struts2还提供了一些命名对象,这些对象没有保存在值栈中,而是保存在 ActionContext中,因此访问这些对象需要使用“#”标记。这些命名对象都是Map类型。访问OGNL上下文和Action上下文,#相当于ActionContext.getContext();

ActionContext.getContext().getValueStack().push("user",user)放MAP进值栈。对于值栈中的任何对象都可以直接访问,而不需要使用“#”。中的根,并且user里面的属性如name要直接写成name而不是user.name

综上:从User里取name


Action中的属性User user

OGNL    J2EE

 user.name  ${user.name}

ActionContext.getContext().getValueStack().push("user",user)

OGNL    J2EE

name${name}

ActionContext.getContext().put("user",user);

OGNL    J2EE

#user.name ${name}


笔者不知道该用哪个词来形容ValueStack、ActionContext等可以在Struts2中用来存放数据的类。这些类使用的范围不同,得到的方法也不同,下面就来一一介绍。

    声明:本文参考Struts2版本为2.3.1.2,内容仅供参考,限于笔者水平有限,难免有所疏漏,望您能友善指出。本文发表于ITEYE,谢绝转载。

1. ValueStack

    ValueStack在中文版的《Struts2深入浅出》一书中译作“值栈”。其本身数据结构是一个栈,使用者可以把一些对象(又称作bean)存入值栈中,然后使用动态的表达式来读取bean的属性,或者对bean进行一些其他操作。由于值栈中可能有多个bean,值栈会按bean出栈的顺序依次尝试使用动态的表达式来读取值,直到成功读取值为止。在Struts2中,默认的值栈实现是OgnlValueStack,即默认使用Ognl这个动态表达式语言来读取值。

   在Struts2执行一次请求的过程中,Struts2会把当前的Action对象自动放入值栈。这样,在渲染JSP时,JSP里的代码使用<s:property value="..."/>之类标签中的Ognl表达式会直接作用于Action对象,从而方便的读取Action的属性。

     如何得到值栈:
  • 在自定义的拦截器中,使用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的属性。


    一些例子:

Java代码  复制代码  收藏代码
  1. // 此类为一个封装数据的简单类,在下面的例子会用到   
  2. public class Person {   
  3.   
  4.     private String name;   
  5.   
  6.     public String getName() {   
  7.         return name;   
  8.     }   
  9.   
  10.     public void setName(String name) {   
  11.         this.name = name;   
  12.     }   
  13. }  
[java]  view plain copy
  1. // 此类为一个封装数据的简单类,在下面的例子会用到  
  2. public class Person {  
  3.   
  4.     private String name;  
  5.   
  6.     public String getName() {  
  7.         return name;  
  8.     }  
  9.   
  10.     public void setName(String name) {  
  11.         this.name = name;  
  12.     }  
  13. }  
 

Java代码  复制代码  收藏代码
  1. // 本类将演示拦截器中对值栈的操作   
  2. public class MyInterceptor extends AbstractInterceptor {   
  3.   
  4.     public String intercept(ActionInvocation invocation) throws Exception {   
  5.         // 获得值栈   
  6.         ValueStack valueStack = invocation.getStack();   
  7.         // 存入值   
  8.         Person person = new Person();   
  9.         valueStack.push(person);   
  10.         // 执行表达式获取值   
  11.         String name = (String) valueStack.findValue("name");   
  12.         // 其他代码   
  13.         return invocation.invoke();   
  14.     }   
  15. }  
[java]  view plain copy
  1. // 本类将演示拦截器中对值栈的操作  
  2. public class MyInterceptor extends AbstractInterceptor {  
  3.   
  4.     public String intercept(ActionInvocation invocation) throws Exception {  
  5.         // 获得值栈  
  6.         ValueStack valueStack = invocation.getStack();  
  7.         // 存入值  
  8.         Person person = new Person();  
  9.         valueStack.push(person);  
  10.         // 执行表达式获取值  
  11.         String name = (String) valueStack.findValue("name");  
  12.         // 其他代码  
  13.         return invocation.invoke();  
  14.     }  
  15. }  
 
Java代码  复制代码  收藏代码
  1. // 本类将演示在Action中对值栈进行操作   
  2. public class MyAction extends ActionSupport {   
  3.   
  4.     @Override  
  5.     public String execute() throws Exception {   
  6.         // 获得值栈   
  7.         ValueStack valueStack = ActionContext.getContext().getValueStack();   
  8.         // 存入值   
  9.         Person person = new Person();// 这是之前例子中定义的类  
  10.         valueStack.push(person);   
  11.         // 执行表达式获取值   
  12.         String name = (String) valueStack.findValue("name");   
  13.         // 其他代码   
  14.         // ......   
  15.         return SUCCESS;   
  16.     }   
  17.     // 以下定义的属性供接下来的JSP例子使用   
  18.     private String message;   
  19.     private Person person;   
  20.     private List<Person> personList;   
  21.   
  22.     public String getMessage() {   
  23.         return message;   
  24.     }   
  25.   
  26.     public Person getPerson() {   
  27.         return person;   
  28.     }   
  29.   
  30.     public List<Person> getPersonList() {   
  31.         return personList;   
  32.     }   
  33. }  
[java]  view plain copy
  1. // 本类将演示在Action中对值栈进行操作  
  2. public class MyAction extends ActionSupport {  
  3.   
  4.     @Override  
  5.     public String execute() throws Exception {  
  6.         // 获得值栈  
  7.         ValueStack valueStack = ActionContext.getContext().getValueStack();  
  8.         // 存入值  
  9.         Person person = new Person();// 这是之前例子中定义的类  
  10.         valueStack.push(person);  
  11.         // 执行表达式获取值  
  12.         String name = (String) valueStack.findValue("name");  
  13.         // 其他代码  
  14.         // ......  
  15.         return SUCCESS;  
  16.     }  
  17.     // 以下定义的属性供接下来的JSP例子使用  
  18.     private String message;  
  19.     private Person person;  
  20.     private List<Person> personList;  
  21.   
  22.     public String getMessage() {  
  23.         return message;  
  24.     }  
  25.   
  26.     public Person getPerson() {  
  27.         return person;  
  28.     }  
  29.   
  30.     public List<Person> getPersonList() {  
  31.         return personList;  
  32.     }  
  33. }  

  
Html代码  复制代码  收藏代码
  1. <%@page contentType="text/html" pageEncoding="UTF-8"%>  
  2. <%@taglib uri="/struts-tags" prefix="s" %>  
  3. <!DOCTYPE html>  
  4. <html>  
  5.     <head>  
  6.         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  7.         <title>JSP Page</title>  
  8.     </head>  
  9.     <body>  
  10.         <!-- 本JSP将演示在JSP中对值栈的使用 -->  
  11.         <!-- 本JSP为MyAction对应的JSP -->  
  12.   
  13.         <!-- 由于Action已经被存入的值栈,所以可以调用Action的属性  -->  
  14.         <!-- 使用下面的标签和表达式来显示MyAction的message属性 -->  
  15.         <s:property value="message"/>  
  16.         <!-- 使用下面的标签和表达式来调用Action的getText(...)方法,参数为MyAction的message属性  -->  
  17.         <s:property value="getText(message)"/>  
  18.         <!-- 默认情况下传递给cssClass的是字符串常量。可以使用“%{}”来启用Ognl,这样,传递给cssClass的就不是字符串常量"message",而是上面所说的message的值  -->  
  19.         <s:div cssClass="%{message}"/>  
  20.         <!-- 使用s:push标签来将对象放入值栈,如下 -->  
  21.         <s:push value="person">  
  22.             <!-- 在此s:push标签内,值栈的栈顶元素为person,栈顶第二层为action   
  23.             <!-- 在标签内直接调用person的属性(而不是Action的属性),如下 -->  
  24.             <s:property value="name"/>  
  25.             <!-- 在标签内也可以使用MyAction的属性,值栈会依次先查找Person是否有该属性,由于没找到,会再MyAction中再查找,如下  -->  
  26.             <s:property value="message"/>  
  27.             <!-- 可以使用“[0]”、“[1]”等指定从值栈的哪一层开始查找  -->  
  28.             <!-- 此时,使用“[0]”表示从Person开始查找,当然还是找不到,值栈就接着到MyAction中查找,如下  -->  
  29.             <s:property value="[0].message"/>  
  30.             <!-- 此时,使用“[1]”将从MyAction开始查找,而跳过了person,如下  -->  
  31.             <s:property value="[1].message"/>  
  32.             <!-- 想要访问栈顶元素本身使用关键字“top”,比如,下面的top就代表栈顶的person,如下 -->  
  33.             <s:property value="top"/>  
  34.             <!-- 或者如下  -->  
  35.             <s:property value="[0].top"/>  
  36.             <!-- 想要访问MyAction本身的话使用如下写法  -->  
  37.             <s:property value="[1].top"/>  
  38.         </s:push>  
  39.         <!-- 此时person已被移出值栈,再使用如下标签和表达式将无法得到值 -->  
  40.         <!--<s:property value="name"/>-->  
  41.         <!-- iterator标签会把list的每个元素依次存入栈顶,如下 -->  
  42.         <s:iterator value="personList">  
  43.             <!-- 获得List每个元素中的name属性  -->  
  44.             <s:property value="name"/>  
  45.         </s:iterator>  
  46.     </body>  
  47. </html>  
[html]  view plain copy
  1. <%@page contentType="text/html" pageEncoding="UTF-8"%>  
  2. <%@taglib uri="/struts-tags" prefix="s" %>  
  3. <!DOCTYPE html>  
  4. <html>  
  5.     <head>  
  6.         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  7.         <title>JSP Page</title>  
  8.     </head>  
  9.     <body>  
  10.         <!-- 本JSP将演示在JSP中对值栈的使用 -->  
  11.         <!-- 本JSP为MyAction对应的JSP -->  
  12.   
  13.         <!-- 由于Action已经被存入的值栈,所以可以调用Action的属性  -->  
  14.         <!-- 使用下面的标签和表达式来显示MyAction的message属性 -->  
  15.         <s:property value="message"/>  
  16.         <!-- 使用下面的标签和表达式来调用Action的getText(...)方法,参数为MyAction的message属性  -->  
  17.         <s:property value="getText(message)"/>  
  18.         <!-- 默认情况下传递给cssClass的是字符串常量。可以使用“%{}”来启用Ognl,这样,传递给cssClass的就不是字符串常量"message",而是上面所说的message的值  -->  
  19.         <s:div cssClass="%{message}"/>  
  20.         <!-- 使用s:push标签来将对象放入值栈,如下 -->  
  21.         <s:push value="person">  
  22.             <!-- 在此s:push标签内,值栈的栈顶元素为person,栈顶第二层为action  
  23.             <!-- 在标签内直接调用person的属性(而不是Action的属性),如下 -->  
  24.             <s:property value="name"/>  
  25.             <!-- 在标签内也可以使用MyAction的属性,值栈会依次先查找Person是否有该属性,由于没找到,会再MyAction中再查找,如下  -->  
  26.             <s:property value="message"/>  
  27.             <!-- 可以使用“[0]”、“[1]”等指定从值栈的哪一层开始查找  -->  
  28.             <!-- 此时,使用“[0]”表示从Person开始查找,当然还是找不到,值栈就接着到MyAction中查找,如下  -->  
  29.             <s:property value="[0].message"/>  
  30.             <!-- 此时,使用“[1]”将从MyAction开始查找,而跳过了person,如下  -->  
  31.             <s:property value="[1].message"/>  
  32.             <!-- 想要访问栈顶元素本身使用关键字“top”,比如,下面的top就代表栈顶的person,如下 -->  
  33.             <s:property value="top"/>  
  34.             <!-- 或者如下  -->  
  35.             <s:property value="[0].top"/>  
  36.             <!-- 想要访问MyAction本身的话使用如下写法  -->  
  37.             <s:property value="[1].top"/>  
  38.         </s:push>  
  39.         <!-- 此时person已被移出值栈,再使用如下标签和表达式将无法得到值 -->  
  40.         <!--<s:property value="name"/>-->  
  41.         <!-- iterator标签会把list的每个元素依次存入栈顶,如下 -->  
  42.         <s:iterator value="personList">  
  43.             <!-- 获得List每个元素中的name属性  -->  
  44.             <s:property value="name"/>  
  45.         </s:iterator>  
  46.     </body>  
  47. </html>  
 

2.ActionContext

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

    无论如何,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)。

    一些例子:
Java代码  复制代码  收藏代码
  1. // 本类将演示拦截器中对ActionContext的操作   
  2. public class MyInterceptor extends AbstractInterceptor {   
  3.   
  4.     public String intercept(ActionInvocation invocation) throws Exception {   
  5.         // 获得ActionContext   
  6.         ActionContext actionContext = invocation.getInvocationContext();   
  7.         // 存入值   
  8.         Person person = new Person();   
  9.         actionContext.put("person", person);   
  10.         // 获取值   
  11.         Object value = actionContext.get("person");   
  12.         // 获取HttpServletRequest   
  13.         HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST);   
  14.         // 获取request的Map,即HttpServletRequest.getAttribute(...)和HttpServletRequest.setAttribute(...)所操作的值  
  15.         Map requestMap = (Map) actionContext.get("request");   
  16.         // 其他代码   
  17.         // ......   
  18.         return invocation.invoke();   
  19.     }   
  20. }  
[java]  view plain copy
  1. // 本类将演示拦截器中对ActionContext的操作  
  2. public class MyInterceptor extends AbstractInterceptor {  
  3.   
  4.     public String intercept(ActionInvocation invocation) throws Exception {  
  5.         // 获得ActionContext  
  6.         ActionContext actionContext = invocation.getInvocationContext();  
  7.         // 存入值  
  8.         Person person = new Person();  
  9.         actionContext.put("person", person);  
  10.         // 获取值  
  11.         Object value = actionContext.get("person");  
  12.         // 获取HttpServletRequest  
  13.         HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST);  
  14.         // 获取request的Map,即HttpServletRequest.getAttribute(...)和HttpServletRequest.setAttribute(...)所操作的值  
  15.         Map requestMap = (Map) actionContext.get("request");  
  16.         // 其他代码  
  17.         // ......  
  18.         return invocation.invoke();  
  19.     }  
  20. }  
 
Java代码  复制代码  收藏代码
  1. // 本类将演示在Action中对ActionContext进行操作   
  2. public class MyAction extends ActionSupport {   
  3.   
  4.     @Override  
  5.     public String execute() throws Exception {   
  6.         // 获得值栈   
  7.         ActionContext actionContext = ActionContext.getContext();   
  8.         // 存入值   
  9.         Person person = new Person();// 这是之前例子中定义的类  
  10.         actionContext.put("person", person);   
  11.         // 获取值   
  12.         Object object = actionContext.get("person");   
  13.         // 其他代码   
  14.         // ......   
  15.         return SUCCESS;   
  16.     }   
  17. }  
[java]  view plain copy
  1. // 本类将演示在Action中对ActionContext进行操作  
  2. public class MyAction extends ActionSupport {  
  3.   
  4.     @Override  
  5.     public String execute() throws Exception {  
  6.         // 获得值栈  
  7.         ActionContext actionContext = ActionContext.getContext();  
  8.         // 存入值  
  9.         Person person = new Person();// 这是之前例子中定义的类  
  10.         actionContext.put("person", person);  
  11.         // 获取值  
  12.         Object object = actionContext.get("person");  
  13.         // 其他代码  
  14.         // ......  
  15.         return SUCCESS;  
  16.     }  
  17. }  
 
Html代码  复制代码  收藏代码
  1. <!DOCTYPE html>  
  2. <html>  
  3.     <head>  
  4.         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  5.         <title>JSP Page</title>  
  6.     </head>  
  7.     <body>  
  8.         <!-- 本JSP将演示在JSP中对ActionContext的使用 -->  
  9.         <!-- 本JSP为MyAction对应的JSP -->  
  10.   
  11.         <!-- 由于Action中已经向ActionContext存入了key为"person"的值,所以可以使用“#person”来获取它,如下  -->  
  12.         <s:property value="#person"/>  
  13.         <!-- 获得person的name属性,如下  -->  
  14.         <s:property value="#person.name"/>  
  15.         <!-- 获得Struts2在ActionContext中存入的值,比如request的Map,如下  -->  
  16.         <s:property value="#request"/>  
  17.         <!-- 获得Struts2在ActionContext中存入的值,比如session的Map,如下  -->  
  18.         <s:property value="#session"/>  
  19.         <!-- 获得Struts2在ActionContext中存入的值,request请求传递的GET参数或POST参数的Map,如下  -->  
  20.         <s:property value="#parameters"/>  
  21.            
  22.         <!-- 以下演示在JSP中把值存入ActionContext中  -->  
  23.         <!-- 存入一个字符串"myName",key为"myKey",如下 -->  
  24.         <s:set value="%{'myName'}" var="myKey"/>  
  25.         <!-- 使用s:bean标签来创建一个对象,并把它存入ActionContext中,key为myObject,如下  -->  
  26.         <s:bean name="com.example.Person" var="myObject"/>  
  27.         <!-- 之后就可以用“#”来读取它们,如下  -->  
  28.         <s:property value="#myKey"/>  
  29.         <s:property value="#myObject"/>  
  30.     </body>  
  31. </html>  
[html]  view plain copy
  1. <!DOCTYPE html>  
  2. <html>  
  3.     <head>  
  4.         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  5.         <title>JSP Page</title>  
  6.     </head>  
  7.     <body>  
  8.         <!-- 本JSP将演示在JSP中对ActionContext的使用 -->  
  9.         <!-- 本JSP为MyAction对应的JSP -->  
  10.   
  11.         <!-- 由于Action中已经向ActionContext存入了key为"person"的值,所以可以使用“#person”来获取它,如下  -->  
  12.         <s:property value="#person"/>  
  13.         <!-- 获得person的name属性,如下  -->  
  14.         <s:property value="#person.name"/>  
  15.         <!-- 获得Struts2在ActionContext中存入的值,比如request的Map,如下  -->  
  16.         <s:property value="#request"/>  
  17.         <!-- 获得Struts2在ActionContext中存入的值,比如session的Map,如下  -->  
  18.         <s:property value="#session"/>  
  19.         <!-- 获得Struts2在ActionContext中存入的值,request请求传递的GET参数或POST参数的Map,如下  -->  
  20.         <s:property value="#parameters"/>  
  21.           
  22.         <!-- 以下演示在JSP中把值存入ActionContext中  -->  
  23.         <!-- 存入一个字符串"myName",key为"myKey",如下 -->  
  24.         <s:set value="%{'myName'}" var="myKey"/>  
  25.         <!-- 使用s:bean标签来创建一个对象,并把它存入ActionContext中,key为myObject,如下  -->  
  26.         <s:bean name="com.example.Person" var="myObject"/>  
  27.         <!-- 之后就可以用“#”来读取它们,如下  -->  
  28.         <s:property value="#myKey"/>  
  29.         <s:property value="#myObject"/>  
  30.     </body>  
  31. </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项目没有区别,本文不再详述。

 

    使用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传值。

 

    一些例子:

 

Java代码  复制代码  收藏代码
  1. // 本类将演示拦截器中对HttpServletRequest和request的Map的操作   
  2. public class MyInterceptor extends AbstractInterceptor {   
  3.   
  4.     public String intercept(ActionInvocation invocation) throws Exception {   
  5.         // 获得ActionContext   
  6.         ActionContext actionContext = invocation.getInvocationContext();   
  7.         // 获得HttpServletRequest   
  8.         HttpServletRequest httpServletRequest=(HttpServletRequest)actionContext.get(StrutsStatics.HTTP_REQUEST);   
  9.         // 获得request的Map   
  10.         Map requestMap = (Map) actionContext.get("request");   
  11.         // 创建一个类作为实例   
  12.         Person person = new Person();   
  13.         // 以下两行的语句作用相同   
  14.         httpServletRequest.setAttribute("person", person);   
  15.         requestMap.put("person", person);   
  16.         // 其他代码   
  17.         // ......   
  18.         return invocation.invoke();   
  19.     }   
  20. }  
[java]  view plain copy
  1. // 本类将演示拦截器中对HttpServletRequest和request的Map的操作  
  2. public class MyInterceptor extends AbstractInterceptor {  
  3.   
  4.     public String intercept(ActionInvocation invocation) throws Exception {  
  5.         // 获得ActionContext  
  6.         ActionContext actionContext = invocation.getInvocationContext();  
  7.         // 获得HttpServletRequest  
  8.         HttpServletRequest httpServletRequest=(HttpServletRequest)actionContext.get(StrutsStatics.HTTP_REQUEST);  
  9.         // 获得request的Map  
  10.         Map requestMap = (Map) actionContext.get("request");  
  11.         // 创建一个类作为实例  
  12.         Person person = new Person();  
  13.         // 以下两行的语句作用相同  
  14.         httpServletRequest.setAttribute("person", person);  
  15.         requestMap.put("person", person);  
  16.         // 其他代码  
  17.         // ......  
  18.         return invocation.invoke();  
  19.     }  
  20. }  

 

 

 

Java代码  复制代码  收藏代码
  1. // 本类将演示在Action中对HttpServletRequest和request的Map进行操作(静态方法获得ActionContext)  
  2. public class MyAction extends ActionSupport {   
  3.   
  4.     @Override  
  5.     public String execute() throws Exception {   
  6.         // 获得ActionContext   
  7.         ActionContext actionContext = ActionContext.getContext();   
  8.         // 获得HttpServletRequest   
  9.         HttpServletRequest httpServletRequest=(HttpServletRequest)actionContext.get(StrutsStatics.HTTP_REQUEST);   
  10.         // 获得request的Map   
  11.         Map requestMap = (Map) actionContext.get("request");   
  12.         // 创建一个类作为实例   
  13.         Person person = new Person();   
  14.         // 以下两行的语句作用相同   
  15.         httpServletRequest.setAttribute("person", person);   
  16.         requestMap.put("person", person);   
  17.         // 其他代码   
  18.         // ......   
  19.         return SUCCESS;   
  20.     }   
  21. }  
[java]  view plain copy
  1. // 本类将演示在Action中对HttpServletRequest和request的Map进行操作(静态方法获得ActionContext)  
  2. public class MyAction extends ActionSupport {  
  3.   
  4.     @Override  
  5.     public String execute() throws Exception {  
  6.         // 获得ActionContext  
  7.         ActionContext actionContext = ActionContext.getContext();  
  8.         // 获得HttpServletRequest  
  9.         HttpServletRequest httpServletRequest=(HttpServletRequest)actionContext.get(StrutsStatics.HTTP_REQUEST);  
  10.         // 获得request的Map  
  11.         Map requestMap = (Map) actionContext.get("request");  
  12.         // 创建一个类作为实例  
  13.         Person person = new Person();  
  14.         // 以下两行的语句作用相同  
  15.         httpServletRequest.setAttribute("person", person);  
  16.         requestMap.put("person", person);  
  17.         // 其他代码  
  18.         // ......  
  19.         return SUCCESS;  
  20.     }  
  21. }  

 

 

 

Java代码  复制代码  收藏代码
  1. // 本类将演示在Action中使用ServletRequestAware获得HttpServletRequest(注意:要使用ServletConfigInterceptor拦截器)  
  2. public class MyAction extends ActionSupport implements ServletRequestAware {   
  3.   
  4.     private HttpServletRequest request;   
  5.        
  6.     //此方法是接口ServletRequestAware的方法   
  7.     public void setServletRequest(HttpServletRequest request) {   
  8.         this.request = request;   
  9.     }   
  10.   
  11.     @Override  
  12.     public String execute() throws Exception {   
  13.         // HttpServletRequest已在该类的字段中准备好,可直接使用  
  14.         // ......   
  15.         return SUCCESS;   
  16.     }   
  17. }  
[java]  view plain copy
  1. // 本类将演示在Action中使用ServletRequestAware获得HttpServletRequest(注意:要使用ServletConfigInterceptor拦截器)  
  2. public class MyAction extends ActionSupport implements ServletRequestAware {  
  3.   
  4.     private HttpServletRequest request;  
  5.       
  6.     //此方法是接口ServletRequestAware的方法  
  7.     public void setServletRequest(HttpServletRequest request) {  
  8.         this.request = request;  
  9.     }  
  10.   
  11.     @Override  
  12.     public String execute() throws Exception {  
  13.         // HttpServletRequest已在该类的字段中准备好,可直接使用  
  14.         // ......  
  15.         return SUCCESS;  
  16.     }  
  17. }  

 

 

Java代码  复制代码  收藏代码
  1. // 本类将演示在Action中使用ServletRequestAware获得request的Map(注意:要使用ServletConfigInterceptor拦截器)  
  2. public class MyAction extends ActionSupport implements RequestAware {   
  3.   
  4.     Map<String, Object> request;   
  5.   
  6.     // 该方法是接口RequestAware的方法   
  7.     public void setRequest(Map<String, Object> request) {   
  8.         this.request = request;   
  9.     }   
  10.   
  11.     @Override  
  12.     public String execute() throws Exception {   
  13.         // request的Map已在该类的字段中准备好,可直接使用   
  14.         // ......   
  15.         return SUCCESS;   
  16.     }   
  17. }  
[java]  view plain copy
  1. // 本类将演示在Action中使用ServletRequestAware获得request的Map(注意:要使用ServletConfigInterceptor拦截器)  
  2. public class MyAction extends ActionSupport implements RequestAware {  
  3.   
  4.     Map<String, Object> request;  
  5.   
  6.     // 该方法是接口RequestAware的方法  
  7.     public void setRequest(Map<String, Object> request) {  
  8.         this.request = request;  
  9.     }  
  10.   
  11.     @Override  
  12.     public String execute() throws Exception {  
  13.         // request的Map已在该类的字段中准备好,可直接使用  
  14.         // ......  
  15.         return SUCCESS;  
  16.     }  
  17. }  
 

 

Java代码  复制代码  收藏代码
  1. <!DOCTYPE html>   
  2. <html>   
  3.     <head>   
  4.         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">   
  5.         <title>JSP Page</title>   
  6.     </head>   
  7.     <body>   
  8.         <!-- 本JSP将演示在JSP中对request的Map的使用 -->   
  9.         <!-- 本JSP为MyAction对应的JSP -->   
  10.   
  11.         <!-- request的Map是Struts2自动在ActionContext中存入的值(key为request),所以使用“#”来访问ActionContext,从中读取request  -->   
  12.         <s:property value="#request"/>   
  13.         <!-- 以下两行均是访问request的Map中key为“name”的值  -->   
  14.         <s:property value="#request.name"/>   
  15.         <s:property value="#request['name']"/>   
  16.     </body>   
  17. </html>  
[java]  view plain copy
  1. <!DOCTYPE html>  
  2. <html>  
  3.     <head>  
  4.         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  5.         <title>JSP Page</title>  
  6.     </head>  
  7.     <body>  
  8.         <!-- 本JSP将演示在JSP中对request的Map的使用 -->  
  9.         <!-- 本JSP为MyAction对应的JSP -->  
  10.   
  11.         <!-- request的Map是Struts2自动在ActionContext中存入的值(key为request),所以使用“#”来访问ActionContext,从中读取request  -->  
  12.         <s:property value="#request"/>  
  13.         <!-- 以下两行均是访问request的Map中key为“name”的值  -->  
  14.         <s:property value="#request.name"/>  
  15.         <s:property value="#request['name']"/>  
  16.     </body>  
  17. </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的MapActionContext. get("request")一次Http请求使用“#request”再加上key,如“#request.name”或者“#request['name']”实现RequestAware接口
parameters的MapActionContext. get( "parameters")一次Http请求使用“# parameters”再加上key,如“#parameters .name”或者“#parameters ['name']”实现ParameterAware接口
HttpServletSession类无(需通过HttpServletRequest来获得)一次Http Session会话无方便的方法无法注入
session的MapActionContext. get("session")每次请求创建,但在一次Http Session会话中数据都是一样的使用“#session”再加上key,如“# session.name”或者“#session ['name']”实现SessionAware接口
ServletContext类ActionContext. get( StrutsStatics. SERVLET_CONTEXT)网站项目启动后一直存在且唯一无方便的方法使用ServletContextAware接口
application的MapActionContext.get( "application")每次请求时创建,但其中的数据是网站项目启动后一直存在且共享使用“# application”再加上key,如“#application .name”或者“#application ['name']”使用ApplicationAware接口

 

附录1 ActionContext中到底有哪些数据

 

keykey的声明处value的类型value.toString()

com. opensymphony. xwork2. dispatcher.

HttpServletRequest

 StrutsStatics. HTTP_REQUESTorg. apache. struts2. dispatcher. StrutsRequestWrapperorg. apache. struts2. dispatcher. StrutsRequestWrapper @10984e0
application 无org. apache. struts2. dispatcher. ApplicationMap
com. opensymphony. xwork2. ActionContext. locale ActionContext. LOCALEjava. util. Localezh_CN
com. opensymphony. xwork2. dispatcher. HttpServletResponse StrutsStatics. HTTP_RESPONSEorg. apache. catalina. connector. ResponseFacadeorg. apache. catalina. connector. ResponseFacade @14ecfe8

xwork. NullHandler.

createNullObjects

 Booleanfalse
com. opensymphony. xwork2. ActionContext. name ActionContext. ACTION_NAMEStringindex

com.opensymphony. xwork2.ActionContext.

conversionErrors

 ActionContext. 

CONVERSION_ERRORS

java. util. HashMap{}
com. opensymphony. xwork2. ActionContext. application ActionContext. APPLICATIONorg. apache. struts2. dispatcher. ApplicationMap
attr 无org. apache. struts2. util. AttributeMaporg. apache. struts2. util. AttributeMap @133a2a8
com. opensymphony. xwork2. ActionContext. container ActionContext. CONTAINERcom. opensymphony. xwork2. inject. ContainerImplcom. opensymphony. xwork2. inject. ContainerImpl @fc02c8
com. opensymphony. xwork2. dispatcher. ServletContext StrutsStatics. SERVLET_CONTEXTorg. apache. catalina. core. ApplicationContextFacadeorg. apache. catalina. core. ApplicationContextFacade @11ad78c
com. opensymphony. xwork2. ActionContext. session ActionContext. SESSIONorg.apache.struts2. dispatcher.SessionMap{}

com.opensymphony. xwork2.ActionContext.

actionInvocation

 ActionContext. ACTION_INVOCATIONcom. opensymphony. xwork2. DefaultActionInvocationcom. opensymphony. xwork2. DefaultActionInvocation @13d4497
xwork. MethodAccessor. denyMethodExecution 笔者很懒,没有找Booleanfalse
report. conversion. errors 笔者很懒,没有找Booleanfalse
session 无org. apache. struts2. dispatcher. SessionMap{}
com. opensymphony. xwork2. util. ValueStack. ValueStack ValueStack.VALUE_STACKcom. opensymphony. xwork2. ognl. OgnlValueStackcom. opensymphony. xwork2. ognl. OgnlValueStack @16237fd
request 无org. apache. struts2. dispatcher. RequestMap
action 笔者很懒,没有找com. example. MyAction
struts. actionMapping 笔者很懒,没有找org. apache. struts2. dispatcher. mapper. ActionMappingorg. apache. struts2. dispatcher. mapper. ActionMapping @892cc5
parameters 无java. util. HashMap{}
com. opensymphony. xwork2. ActionContext. parameters ActionContext.PARAMETERSjava. 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,并且没有在其他地方看到类型检查操作:

 

 

Java代码  复制代码  收藏代码
  1. // 本代码截取Struts2.3.1.2版本com.opensymphony.xwork2.ognl.OgnlValueStack类的第340行-352行  
  2.     private Object tryFindValue(String expr, Class asType) throws OgnlException {   
  3.         Object value = null;   
  4.         try {   
  5.             expr = lookupForOverrides(expr);   
  6.             value = getValue(expr, asType);   
  7.             if (value == null) {   
  8.                 value = findInContext(expr);   
  9.             }   
  10.         } finally {   
  11.             context.remove(THROW_EXCEPTION_ON_FAILURE);   
  12.         }   
  13.         return value;   
  14.     }  
[java]  view plain copy
  1. // 本代码截取Struts2.3.1.2版本com.opensymphony.xwork2.ognl.OgnlValueStack类的第340行-352行  
  2.     private Object tryFindValue(String expr, Class asType) throws OgnlException {  
  3.         Object value = null;  
  4.         try {  
  5.             expr = lookupForOverrides(expr);  
  6.             value = getValue(expr, asType);  
  7.             if (value == null) {  
  8.                 value = findInContext(expr);  
  9.             }  
  10.         } finally {  
  11.             context.remove(THROW_EXCEPTION_ON_FAILURE);  
  12.         }  
  13.         return value;  
  14.     }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值