Struts2中的ActionContext、OGNL及EL的使用
文章分类:Java编程
本文基于struts2.1.8.1,xwork2.1.6 
1.EL 
        EL(Expression Language)源于jsp页面标签jstl,后来被jsp2.0直接支持,因此可以在jsp页面中直接使用EL表达式。其使用语法为${expr},如${username},表达式expr中变量的获取,默认使用PageContext.findAttribute(String)方法,也就是从pageContext隐藏对象中查找,pageContext隐藏对象包含以下隐藏对象:request,response,session,servletContext.查找范围顺序是page, request,session, and application,找不到则返回null。指定对象查找则使用${implictObject.foo}语法,其中implictObject代表任意隐藏对象,除pageContext之外,还包含:param,paramValues,header,headerValues,cookie,initParam以及pageScope,requestScope,sessionScope,applicationScope等。 
        注意:自定义变量如果和隐藏对象同名,${implicitObject}将返回隐藏对象,而不是自定义对象的值。
2.OGNL in Struts2 
        struts2使用ActionContext作为OGNL的上下文,也就是ActionContext.context,其默认的root上下文是一个OGNL的值栈(OgnlValueStack),用于存放action的实例,其访问不需要标记,同时存放了其它的对象,如request,parameters,session,application,attr等,访问需要#标记并指明对象名称,如#session.username.由于ActionContext存放到ThreadLocal中,所以是线程安全的。在同一个请求经过不同的action转发(forward)处理的过程中,这些action实例都会压进root这个值栈中,最后的在最上面,查找变量值也是从上面开始顺序往下。 
        ActionContext是由org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter进行初始化的,在doFilter中调用prepare.createActionContext(request,
response);追踪下去,核心代码在org.apache.struts2.dispatcher.ng.PrepareOperations中:
Java代码
- public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
 - ActionContext ctx;
 - Integer counter = 1;
 - Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
 - if (oldCounter != null) {
 - counter = oldCounter + 1;
 - }
 - ActionContext oldContext = ActionContext.getContext();
 - if (oldContext != null) {
 - // detected existing context, so we are probably in a forward
 - ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
 - } else {
 - ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
 - stack.getContext().putAll(dispatcher.createContextMap(request, response, null, servletContext));
 - ctx = new ActionContext(stack.getContext());
 - }
 - request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
 - ActionContext.setContext(ctx);
 - return ctx;
 - }
 
public ActionContext
createActionContext(HttpServletRequest request, HttpServletResponse response) {
ActionContext ctx;
Integer counter = 1;
Integer oldCounter = (Integer)
request.getAttribute(CLEANUP_RECURSION_COUNTER);
if (oldCounter != null) {
counter = oldCounter + 1;
}
ActionContext oldContext =
ActionContext.getContext();
if (oldContext != null) {
// detected existing context, so we
are probably in a forward
ctx = new ActionContext(new
HashMap<String, Object>(oldContext.getContextMap()));
} else {
ValueStack stack =
dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
stack.getContext().putAll(dispatcher.createContextMap(request, response,
null, servletContext));
ctx = new
ActionContext(stack.getContext());
}
request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
ActionContext.setContext(ctx);
return ctx;
}
3.JSP中的使用 
        JSP2.0可以直接使用EL表达式,方便变量的获取。使用struts2的标签,可以取到ActionContext中的对象,如action中的成员变量,非root中的变量使用标记方式。 
        另外,struts2标签中,非字符类型(如boolean,int型)的属性取值,需要使用%{expr}的方式。在JSP中也可以使用EL表达式获取Action中的成员属性,原因是struts2对request进行了封装(org.apache.struts2.dispatcher.StrutsRequestWrapper),重写了request.getAttribute()方法,查找范围扩大到了ActionContext的root中,核心代码如下:
Java代码
- public Object getAttribute(String s) {
 - if (s != null && s.startsWith("javax.servlet")) {
 - // don't bother with the standard javax.servlet attributes, we can short-circuit this
 - // see WW-953 and the forums post linked in that issue for more info
 - return super.getAttribute(s);
 - }
 - ActionContext ctx = ActionContext.getContext();
 - Object attribute = super.getAttribute(s);
 - if (ctx != null) {
 - if (attribute == null) {
 - boolean alreadyIn = false;
 - Boolean b = (Boolean) ctx.get("__requestWrapper.getAttribute");
 - if (b != null) {
 - alreadyIn = b.booleanValue();
 - }
 - // note: we don't let # come through or else a request for
 - // #attr.foo or #request.foo could cause an endless loop
 - if (!alreadyIn && s.indexOf("#") == -1) {
 - try {
 - // If not found, then try the ValueStack
 - ctx.put("__requestWrapper.getAttribute", Boolean.TRUE);
 - ValueStack stack = ctx.getValueStack();
 - if (stack != null) {
 - attribute = stack.findValue(s);
 - }
 - } finally {
 - ctx.put("__requestWrapper.getAttribute", Boolean.FALSE);
 - }
 - }
 - }
 - }
 - return attribute;
 - }
 
一.Xwork的OGNL
在Struts2里边的OGNL是基于XWork的。XWork的OGNL和普通意义上的OGNL有一些差别,首先最大的差别就是OGNL只提供了一个根对象(root),而Xwork提供了一个ValueStack,这是Struts2的OGNL的默认root。另外,XWork提供了自己独特的OGNL PropertyAccessor自动从顶向下的查找Stack中符合条件的对象属性。
比如说,有两个对象Animal和Person,两个对象都提供了name属性,同时Animal有species属性,Person有salary属性。假定Animal在stack的顶端。
- species // call to animal.getSpecies()
 - salary // call to person.getSalary()
 - name // call to animal.getName() because animal is on the top
 
species // call to
animal.getSpecies()
salary // call to
person.getSalary()
name // call to
animal.getName() because animal is on the top
从这里可以看到从顶向下查找的作用。在XWork中,我们可以用[n].name这种方式来访问不同层次的同名属性。n必须是正整数。
- [0].name // call to animal.getName()
 - [1].name // call to person.getName()
 
[0].name // call to
animal.getName()
[1].name // call to
person.getName()
访问对象的静态属性的时候,OGNL默认采用如下的方式
- @some.package.ClassName@FOO_PROPERTY
 - @some.package.ClassName@someMethod()
 
@some.package.ClassName@FOO_PROPERTY
@some.package.ClassName@someMethod()
而XWork访问静态属性的方式有所差异:通过@vs来访问。vs表示的意思是valueStack。并且,可以在vs后面跟随数字来表示其访问stack的层次。
- @vs@FOO_PROPERTY
 - @vs@someMethod()
 - @vs1@FOO_PROPERTY
 - @vs1@someMethod()
 - @vs2@BAR_PROPERTY
 - @vs2@someOtherMethod()
 
@vs@FOO_PROPERTY
@vs@someMethod()
@vs1@FOO_PROPERTY
@vs1@someMethod()
@vs2@BAR_PROPERTY
@vs2@someOtherMethod()
二.Struts2中的OGNL
在Struts2中,采用标准命名的上下文(Context)来处理OGNL表达式。处理OGNL的顶级对象是一个Map(也叫context map),而OGNL在这个context中就是一个顶级对象(root)。在用法上,顶级对象的属性访问,是不需要任何标记前缀的。而其它非顶级的对象访问,需要使用#标记。
Struts2框架把OGNL Context设置为我们的ActionContext。并且ValueStack作为OGNL的根对象。除value stack之外,Struts2框架还把代表application、session、request这些对象的Map对象也放到ActionContext中去。(这也就是Struts2建议在Action类中不要直接访问Servlet API的原因,他可以通过ActionContext对象来部分代替这些功能,以方便对Action类进行测试!)
Action的实例,总是放到value stack中。因为Action放在stack中,而stack是root(根对象),所以对Action中的属性的访问就可以省略#标记。但是,要访问ActionContext中其它对象的属性,就必须要带上#标记,以便让OGNL知道,不是从根对象,而是从其它对象中去寻找。
那么访问Action中的属性的代码就可以这样写
<s:property value="postalCode"/>
其它ActionContext中的非根对象属性的访问要像下面这样写:
<s:property value="#session.mySessionPropKey"/>
or
<s:property value="#session['mySessionPropKey']"/> or
<s:property value="#request['myRequestPropKey']"/>
对Collection的处理,内容就很简单。
<s:select label="label"
name="name" list="{'name1','name2','name3'}"
value="%{'name2'}" />
这是处理List。这个代码在页面上建立一个下拉选项,内容是list中的内容,默认值是name2.
处理map
<s:select label="label"
name="name" list="#{'foo':'foovalue', 'bar':'barvalue'}"
/>
需要注意的是,判断一个值是否在collection中。我们要使用in或者not in来处理。
<s:if test="'foo' in
{'foo','bar'}">
   muhahaha
</s:if>
<s:else>
   boo
</s:else>
 另外,可以使用通配符来选择collection对象的子集。
 ?——所有匹配选择逻辑的元素
 ^——只提取符合选择逻辑的第一个元素
 $——只提取符合选择逻辑的最后一个元素
person.relatives.{? #this.gender == 'male'}
Struts2中的ActionContext、OGNL及EL的使用的更多相关文章
- struts2中#,$,%的用法以及el,ognl表达式的用法
		
OGNL, JSTL, STRUTS2标签中符号#,$,%的用法示例 取Session中的值 <c:out value="${sessionScope.user.userId}&quo ...
 - Struts2中的ActionContext
		
ActionContext(Action上下文) ActionContext介绍 通过上面用户注册例子的学习,我们知道Xwork与Web无关性,我们的Action不用去依赖于任何Web容器,不用和那些 ...
 - [转]STRUTS2中的OGNL
		
OGNL表达式是(Object-Graph Navigation Language)是对象图形化导航语言.OGNL是一个开源的项目,struts2中默认使用OGNL表达式语言来显示数据.与serlve ...
 - struts2中根对象以及ognl .
		
Struts2中的OGNL表达式语言是对Xwork的OGNL的封装.我们要理解一下几点: 1. Struts2中将ActionContext作为OGNL的上下文环境(ActionContext内部含有 ...
 - struts2中struts.xml配置文件详解【未整理】
		
1. 深入Struts2的配置文件 本部分主要介绍struts.xml的常用配置. 1.1. 包配置: Struts2框架中核心组件就是Action.拦截器等,Struts2框架使用包来管 ...
 - Struts中的OGNL和EL表达式笔记
		
Struts中的OGNL和EL表达式笔记 OGNL(Object-Graph Navigation Language),可以方便的操作对象属性的表达式语言. 1.#符号的用途 一般有三种方式: 1.1 ...
 - 关于Struts2中的值栈与OGNL表达式
		
1.1.1 OGNL概述: Object Graphic Navigation Language(对象图导航语言)的缩写 * EL :OGNL比EL功能强大很多倍. 它是一个开源项目. ...
 - struts2中使用ognl表达式时各种符号的使用规则$,#,%
		
OGNL表达式struts2标签“%,#,$” 一.什么是OGNL,有什么特点? OGNL(Object-Graph Navigation Language),大概可以理解为:对象图形化导航语言.是一 ...
 - struts2中s:iterator 标签的使用详解 及 OGNL用法
		
简单的demo: s:iterator 标签有3个属性:value:被迭代的集合id :指定集合里面的元素的idstatus 迭代元素的索引 1:jsp页面定义元素写法 数组或list <s ...
 
随机推荐
- HDU 1054 Strategic Game(最小点覆盖+树形dp)
			
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=106048#problem/B 题意:给出一些点相连,找出最小的点数覆盖所有的 ...
 - crossdomain.xml的配置详解
			
目录 1 简介 2 crossdomain.xml的配置详解 3 总结 1 简介 flash在跨域时唯一的限制策略就是crossdomain.xml文件,该文件限制了flash是否可以跨域读写数据以及 ...
 - Spring学习7-Spring整合Hibernate
			
一.Springl为什么要整合Hibernate 二者的整合主要是把hibernate中核心的一些类型交给spring管理,这些类型主要包括sessionFactory. transactionM ...
 - javascript中this的学习总结
			
在开发中,this多使用在function函数中,也正是由于调用function的对象的不同,才导致了this的指向不同.需要明白(1).function也是对象:(2).function执行时是在某 ...
 - 在Eclipse中编写servlet时出现"The import javax.servlet cannot be resolved" 问题解决办法
			
在Eclipse中,project->properties,选择Java Build Path->Libraries->Add External JARs,找到你计算机中tomcat ...
 - Servlet之Filter详细讲解
			
Filter,过滤器,顾名思义,即是对数据等的过滤,预处理过程.为什么要引入过滤器呢?在平常访问网站的时候,有时候发一些敏感的信息,发出后显示时 就会将敏感信息用*等字符替代,这就是用过滤器对信息进行 ...
 - Python socket编程之二:【struct.pack】&【struct.unpack】
			
import struct """通过 socket 的 send 和 recv 只能传输 str 格式的数据""" "" ...
 - java调用本地方法的时候报错 could not find the main class:xx.program will exit
			
如图所示,当在java调用本地方法的时候报错 我的解决办法是把dll文件放到System.out.println(System.getProperty("java.library.path& ...
 - c语言的头文件-不是c++类的头文件?
			
下面的概述是参考的这篇文章:http://blog.csdn.net/bingxx11/article/details/7771437 c语言编程中也有,也需要头文件, 头文件不只是C++的类才需要! ...
 - mysql 权限设置
			
1.“grant all on *.* to root@'%' identified by 'yourpassword';”——这个还可以顺带设置密码.2.“flush privileges; ”—— ...