OGNL表达式
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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="#attr.username"/>会在以下几个域对象中依次查询
[pageContext对象]===>requestMap对象===>valueStack对象===>sessionMap对象===>applicationMap对象===>空白字符串
注意:pageContext对象不是Struts2的数据中心之一.
3.#用法:
1) <s:property value="#request.username"/> 作用于struts2的域对象,而不是普通域对象
2)<s:property value="#user.username"/>作用于JavaBean对象
3)<s:property value="#username"/><===><s:property value="username"/>作用于普通字符串
OGNL (Object Graph Navigation Language)对象图导航语言。Struts2框架使用OGNL作为默认的表达式语言。
OGNL相对其它表达式语言具有下面几大优势:
- 支持对象方法调用,如xxx.doSomeSpecial();
- 支持类静态方法的调用和值的访问,表达式的格式:
@[类全名(包括包路径)]@[方法名 | 值名],例如:
@[email protected](‘foo %s’, ‘bar’)
或@[email protected]_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="提交">
</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="username"/><br>
${phone }<br>
输入的值没有保存到action中的属性:${other }<s:property value="other"/><br>
action中只提供get方法的属性: ${message }
</body>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
(5)运行显示:
输入的值并保存到action中的属性: wq
18212345678
输入的值没有保存到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="{‘zhangming‘,‘xiaoi‘,‘liming‘}" />
<!-- s:iterator会将当前迭代的对象放到值栈的栈顶中!因此才会有s:property默认输出ValueStack栈顶的值 -->
<s:iterator value="#list" id="n">
<s:property value="n"/><br>
</s:iterator>
<!-- s:property标签的value属性可选,如果没有给定,则默认输出ValueStack栈顶的值
因此还可以简写成如下形式 -->
<s:iterator value="#list">
<s:property/><br>
</s:iterator>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
生成一个 Map 对象:
<s:set name="foobar" value="#{‘foo1‘:‘bar1‘, ‘foo2‘:‘bar2‘}" />
<s:iterator value="#foobar" >
<!-- Map集合迭代采用了内部的Entry类,且此时迭代的Entry对象放在值栈的栈顶,
Entry中包含key和value的属性,因此可以通过OGNL表达式获取栈顶对象的属性 -->
<s:property value="key"/>=<s:property value="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="books.{?#this.price > 35}">
<s:property value="title" /> - $<s:property value="price" /><br>
</s:iterator>
- 1
- 2
- 3
在上面代码中,直接在集合后紧跟 .{} 运算符表明用于取出该集合的子集, {} 内的表达式用于获取符合条件的元素, this 指的是为了从大集合 books 筛选数据到小集合,需要对大集合 books 进行迭代,this 代表当前迭代的元素。
几种与OGNL有关的符号
在Struts2中使用OGNL经常会接触到几个有关的符号:”#”,”%”,”$”。刚开始学习的时候经常分布清楚这几个符号的作用,这里我们对他们的作用大致做一个列举。
“#”的作用:
(1) 访问非root对象的属性。例如:#session[“userName”]
(2) 对集合进行投影与选择
(3) 构造对象,
“%”的作用:
在标签的属性值被理解为字符串类型时,告诉执行环境%{}里的是OGNL表达式 <s:property value="%{#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表达式的主要内容,如果未能解决你的问题,请参考以下文章