首页 > 代码库 > OGNL表达式
OGNL表达式
一.知识点学习
1.struts2中包含以下6种对象,requestMap,sessionMap,applicationMap,paramtersMap,attr,valueStack;
1)requestMap用来存放包含当前HttpServletRequest的属性(attribute)的Map,简单来说就是request域中的值;
2)sessionMap用来存放包含当前HttpSession的属性(attribute)的Map
3)applicationMap用来存放包含当前应用的ServletContext的属性(attribute)的Map
4)paramtersMap包含当前HTTP请求参数的Map
5)attr,只是用来取值,用于按request > session > application顺序访问其属性(attribute)
6)valueStack值栈是Action的数据中心,关于Action中的所有Value都是存放在valueStack中.
2.OGNL几种常见的符号用法
<s:property value="http://www.mamicode.com/#attr.username"/>会在以下几个域对象中依次查询
[pageContext对象]===>requestMap对象===>valueStack对象===>sessionMap对象===>applicationMap对象===>空白字符串
注意:pageContext对象不是Struts2的数据中心之一.
3.#用法:
1) <s:property value="http://www.mamicode.com/#request.username"/> 作用于struts2的域对象,而不是普通域对象
2)<s:property value="http://www.mamicode.com/#user.username"/>作用于JavaBean对象
3)<s:property value="http://www.mamicode.com/#username"/><===><s:property value="http://www.mamicode.com/username"/>作用于普通字符串
OGNL (Object Graph Navigation Language)对象图导航语言。Struts2框架使用OGNL作为默认的表达式语言。
OGNL相对其它表达式语言具有下面几大优势:
- 支持对象方法调用,如xxx.doSomeSpecial();
- 支持类静态方法的调用和值的访问,表达式的格式:
@[类全名(包括包路径)]@[方法名 | 值名],例如:
@java.lang.String@format(‘foo %s’, ‘bar’)
或@tutorial.MyConstant@APP_NAME; - 支持赋值操作和表达式串联;
- 访问OGNL上下文ActionContext;
操作集合对象List,Map。
Ognl 有一个上下文(Context)概念,在 Struts2 中上下文(Context)的实现为ActionContext,ActionContext对象对应Action,可以理解为action执行相关的对象的容器,包括application,session,parameters,locale,value stack等。ActionContext中:ValueStack是OGNL上下文的root元素,贯穿整个 Action 的生命周期(每个Action类的对象实例都拥有一个ValueStack 对象)。 相当于一个数据的中转站. 在其中保存当前Action 对象和其他相关对象。
private Map<String, Object> context;
这个才是真正意义上的上下文。其中可以put进数据,jsp中可通过OGNL表达式通过key获取。
OGNL Context 实现者为 ActionContext ,它结构示意图如下 :
注:这里的context map指的是ActionContext的map效果;action为相关的action包名,而不是action对象(代码中更清晰)。
16.2 理解Struts2中的 ValueStack和OGNL Context
ValueStack实际是一个接口,在Struts2中利用OGNL时,实际上使用的是实现了该接口的OgnlValueStack类,这个类是Struts2利用OGNL的基础。
ValueStack(值栈): 贯穿整个 Action 的生命周期(每个 Action 类的对象实例都拥有一个ValueStack 对象). 相当于一个数据的中转站. 在其中保存当前Action 对象和其他相关对象。
OgnlValueStack 类包含两个重要的属性:
CompoundRoot root; // CompoundRoot extends ArrayList transient Map<String, Object> context;
- 1
- 2
- 其中root为一个ArrayList模拟的值栈,action等相关对象就是保存这里:
/** * 实现ValueStack接口的pop操作 * @see com.opensymphony.xwork2.util.ValueStack#pop() */ public Object pop() { return root.pop(); } /** * 实现ValueStack接口的push操作 * @see com.opensymphony.xwork2.util.ValueStack#push(java.lang.Object) */ public void push(Object o) { root.push(o); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
再查看ActionContext类的源代码可知:
public class ActionContext implements Serializable { static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>(); // 所要执行的action类名 public static final String ACTION_NAME = "com.opensymphony.xwork2.ActionContext.name"; // 值栈ValueStack的类名,即上面所说的_root对象 public static final String VALUE_STACK = ValueStack.VALUE_STACK; public static final String SESSION = "com.opensymphony.xwork2.ActionContext.session"; public static final String APPLICATION = "com.opensymphony.xwork2.ActionContext.application"; public static final String PARAMETERS = "com.opensymphony.xwork2.ActionContext.parameters"; public static final String LOCALE = "com.opensymphony.xwork2.ActionContext.locale"; // context map private Map<String, Object> context; ...}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
会发现ActionContext中包含一个context,OgnlValueStack中也包含一个context,这两个context是否为同一个对象呢??我们在action的execute方法中进行测试:
public String execute() { ActionContext context = ActionContext.getContext(); OgnlValueStack ognlValueStack = (OgnlValueStack) context.getValueStack(); // 获取OgnlValueStack中的context属性 Map<String, Object> ognlValueStack_Context = ognlValueStack.getContext(); // 获取ActionContext中的context属性 Map<String, Object> actionContext_Context = context.getContextMap(); // 比较ActionContext中的context属性和OgnlValueStack中的context属性是否为同一个对象 System.out.println(ognlValueStack_Context == actionContext_Context); // true return SUCCESS; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
测试结果为true!所以说ActionContext中的context属性和OgnlValueStack中的context属性实则为同一个对象!这也就解释了:通过ActionCOntext.getContext().put();
方法放入到context(Map集合)的数据,也即OgnlValueStack中context(Map集合),所以可以通过OGNL表达式可以获取。
注:在Ognl上下文对象(ActionContext)中,维持值栈root的包名(com.opensymphony.xwork2.util.ValueStack.ValueStack),OGNL访问root中的元素时,是不需要#号的,直接通过元素的名称来进行访问;而访问其他对象时,如application、request、session、parameters、attr等,则需要#号引用。
当Struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action等。然后把action存放进值栈OgnlValueStack的root对象中,所以在页面上通过Struts2标签访问Action的属性时,就不需要通过#号来引用。
由于 ValueStack( 值栈 ) 是 Struts 2 中 OGNL上下文的根对象,如果用户需要访问值栈中的对象,在 JSP 页面可以通过EL表达式访问 ValueStack(值栈)中对象的属性:
${foo} // 获得值栈中某个对象的 foo 属性
- 1
如果访问其他 Context 中的对象,由于他们不是根对象,所以在访问时,需要添加 # 前缀。
- application对象:用于访问ServletContext,例如#application.userName或者#application[‘userName’],相当于调用ServletContext的getAttribute(“username”)。
- session对象:用来访问HttpSession ,例如#session.userName或者#session[‘userName’] ,相当于调用session.getAttribute(“userName”)。
- request对象:用来访问HttpServletRequest属性(attribute)的Map,例如#request.userName或者#request[‘userName’] ,相当于调用request.getAttribute(“userName”)。
- parameters对象:用于访问HTTP的请求参数,例如#parameters.userName或者#parameters[‘userName’] ,相当于调用 request.getParameter(“username”)。
- attr对象:用于按page->request->session->application顺序访问其属性。
16.3 为何使用EL 表达式能够访问valueStack中对象的属性
在JSP页面中通过${foo}
这样的EL表达式就可以获取值栈中某个对象的 foo 属性。原因是Struts2对HttpServletRequest作了进一步的封装。简略代码如下:
public class StrutsRequestWrapper extends HttpServletRequestWrapper { public StrutsRequestWrapper(HttpServletRequest req) { super(req); } public Object getAttribute(String key) { ...... ActionContext ctx = ActionContext.getContext(); Object attribute = super.getAttribute(key);// 先从 request 范围获取属性值 // 如果从 request 范围没有找到属性值 , 即从 ValueStack 中查找对象的属性值 if (ctx != null && attribute == null) { ...... ValueStack stack = ctx.getValueStack(); if (stack != null) { attribute = stack.findValue(key); } ...... } return attribute; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
16.4 基本案例测试
案例需求:输入界面通过表单输入数据,并注入到action中,输出界面通过Ognl表达式获取输入的内容中未保存到action部分和保存的部分,已经action中只提供get方法的属性。(即获取以上讨论的三种类型的数据)
(1)输入界面input.jsp
<form action="/Ognl/day07/ognlTest.action" method="post"> username: <input type="text" name="username"/><br> phone: <input type="text" name="phone"/><br> <!-- 此属性并没有注入到action的属性中 --> other: <input type="text" name="other"/><br> <input type="submit" value=http://www.mamicode.com/"提交"></form>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
(2)Action类:
package com.markliu.day07;import org.apache.struts2.ServletActionContext;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionSupport;public class OgnlTestAction extends ActionSupport { private static final long serialVersionUID = 4491003976083155453L; private String username; private String phone; private String message; public String getMessage() { return message; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String execute() { this.message = "从action获取message!"; 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
- 32
- 33
- 34
- 35
- 36
- 37
(3)struts.xml配置:
<package name="day07" namespace="/day07" extends="struts-default"> <action name="ognlTest" class="com.markliu.day07.OgnlTestAction" method="execute"> <result name="success">/pages/day07/ognlGetInfo.jsp</result> </action> </package>
- 1
- 2
- 3
- 4
- 5
(4)ognl获取数据显示:
<%@ taglib uri="/struts-tags" prefix="s" %> ...<body>输入的值并保存到action中的属性:<s:property value=http://www.mamicode.com/"username"/><br>${phone }<br>输入的值没有保存到action中的属性:${other }<s:property value=http://www.mamicode.com/"other"/><br>action中只提供get方法的属性: ${message }</body>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
(5)运行显示:
输入的值并保存到action中的属性: wq18212345678输入的值没有保存到action中的属性:action中只提供get方法的属性: action获取message!
- 1
- 2
- 3
- 4
由运行结果可知:由于action被保存到valuestack值栈中,所以用户输入的信息注入到action中的属性,以及action本身的属性(提供get方法)都可以通过OGNL表达式的两种形式获取:EL表达式或Struts2标签。
16.5 采用 OGNL 表达式创建 List/Map 集合对象
如果需要一个集合元素的时候(例如 List 对象或者 Map 对象),可以使用 OGNL 中同集合相关的表达式。
使用如下代码直接生成一个 List 对象:
<s:set name="list" value=http://www.mamicode.com/"{‘zhangming‘,‘xiaoi‘,‘liming‘}" /><!-- s:iterator会将当前迭代的对象放到值栈的栈顶中!因此才会有s:property默认输出ValueStack栈顶的值 --><s:iterator value=http://www.mamicode.com/"#list" id="n"> <s:property value=http://www.mamicode.com/"n"/><br></s:iterator><!-- s:property标签的value属性可选,如果没有给定,则默认输出ValueStack栈顶的值 因此还可以简写成如下形式 --><s:iterator value=http://www.mamicode.com/"#list"> <s:property/><br></s:iterator>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
生成一个 Map 对象:
<s:set name="foobar" value=http://www.mamicode.com/"#{‘foo1‘:‘bar1‘, ‘foo2‘:‘bar2‘}" /><s:iterator value=http://www.mamicode.com/"#foobar" > <!-- Map集合迭代采用了内部的Entry类,且此时迭代的Entry对象放在值栈的栈顶, Entry中包含key和value的属性,因此可以通过OGNL表达式获取栈顶对象的属性 --> <s:property value=http://www.mamicode.com/"key"/>=<s:property value=http://www.mamicode.com/"value"/><br></s:iterator>
- 1
- 2
- 3
- 4
- 5
- 6
<s:set>
标签用于将某个值放入指定范围。
- scope:指定变量被放置的范围,该属性可以接受application、session、request、page或action。如果没有设置该属性,则默认放置在ActionContext(OGNL上下文)中。
- value :赋给变量的值 . 如果没有设置该属性 , 则将 ValueStack 栈顶的值赋给变量。
对于集合类型, OGNL 表达式可以使用 in 和 not in 两个元素符号。其中, in 表达式用来判断某个元素是否在指定的集合对象中; not in 判断某个元素是否不在指定的集合对象中。s:if标签的test中填入OGNL表达式,如下所示。
<s:if test="‘foo‘ in {‘foo‘,‘bar‘}"></s:if><s:else></s:else><s:if test="‘foo‘ not in {‘foo‘,‘bar‘}"></s:if><s:else></s:else>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
16.6 OGNL 表达式的投影功能
除了 in 和 not in 之外, OGNL 还允许使用某个规则获得集合对象的子集,常用的有以下 3 个相关操作符:
? :获得所有符合逻辑的元素。
^ :获得符合逻辑的第一个元素。
$ :获得符合逻辑的最后一个元素。
例如代码,获取价格大于35的所有图书:
<s:iterator value=http://www.mamicode.com/"books.{?#this.price > 35}"> <s:property value=http://www.mamicode.com/"title" /> - $<s:property value=http://www.mamicode.com/"price" /><br></s:iterator>
- 1
- 2
- 3
在上面代码中,直接在集合后紧跟 .{} 运算符表明用于取出该集合的子集, {} 内的表达式用于获取符合条件的元素, this 指的是为了从大集合 books 筛选数据到小集合,需要对大集合 books 进行迭代,this 代表当前迭代的元素。
几种与OGNL有关的符号
在Struts2中使用OGNL经常会接触到几个有关的符号:”#”,”%”,”$”。刚开始学习的时候经常分布清楚这几个符号的作用,这里我们对他们的作用大致做一个列举。
“#”的作用:
(1) 访问非root对象的属性。例如:#session[“userName”]
(2) 对集合进行投影与选择
(3) 构造对象,
“%”的作用:
在标签的属性值被理解为字符串类型时,告诉执行环境%{}里的是OGNL表达式 <s:property value="http://www.mamicode.com/%{#foobar[‘foo1‘]}" />
“$”的作用:
(1) 在配置文件中引用OGNL表达式(访问Action的属性)。
(2) 在国际化资源文件中引用OGNL表达式(学习国际化时会学到)
参考:
http://blog.csdn.net/songylwq/article/details/5645040
http://www.cnblogs.com/huzi007/p/4279807.html
https://commons.apache.org/proper/commons-ognl/language-guide.html
转载请注明出处:http://blog.csdn.net/mark_lq/article/details/49839895
OGNL表达式