OGNL表达式
OGNL表达式语言介绍 OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写, 它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。 OGNL相对其它表达式语言具有下面几大优势: 1、支持对象方法调用,如xxx.doSomeSpecial(); 2、支持类静态的方法调用和值访问,表达式的格式: @[类全名(包括包路径)]@[方法名 | 值名],例如: @java.lang.String@format('foo %s', 'bar') 或@tutorial.MyConstant@APP_NAME; 3、支持赋值操作和表达式串联,如price=100, discount=0.8, calculatePrice(),这个表达式会返回80; 4、访问OGNL上下文(OGNL context)和ActionContext; 5、操作集合对象。 Ognl 有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现 了java.utils.Map的接口. ******************************************************************************************* 理解Struts2中的 ValueStack ValueStack实际是一个接口,在Struts2中利用OGNL时,实际上使用的是实现了该接口的OgnlValueStack类,这个类是Struts2利用OGNL的基础 ValueStack(值栈): 贯穿整个 Action 的生命周期(每个 Action 类的对象实例都拥有一个 ValueStack 对象). 相当于一个数据的中转站. 在其中保存当前 Action 对象和其他相关对象. Struts 框架把 ValueStack 对象保存在名为 “struts.valueStack” 的请求属性中,request中 在 ValueStack 对象的内部有两个逻辑部分: ObjectStack: Struts 把动作和相关对象压入 ObjectStack 中--List ContextMap: Struts 把各种各样的映射关系(一些 Map 类型的对象) 压入 ContextMap 中 Struts 会把下面这些映射压入 ContextMap 中 parameters: 该 Map 中包含当前请求的请求参数 request: 该 Map 中包含当前 request 对象中的所有属性 session: 该 Map 中包含当前 session 对象中的所有属性 application:该 Map 中包含当前 application 对象中的所有属性 attr: 该 Map 按如下顺序来检索某个属性: request, session, application 理解OGNL Context *OgnlValueStack 类包含两个重要的属性 一个root和一个context。 * 其中root本质上是一个ArrayList. * 而context 是一个Map(更确切的说是一个OgnlContext对象) *在这个OgnlContext对象(context)中,有一个默认的顶层对象 _root,OGNL访问context中这个默认顶层对象中的元素时,是不需要#号的,直接通过元素的名称来进行访问, *而访问其他对象时,如 request、session、attr等,则需要#号引用。 注:Struts2将OgnlValueStack的root对象赋值给了OgnlContext 中的_root对象,在OgnlValueStack的root对象中,保存着调用Action的实例,因此,在页面上通过Struts2标签访问Action 的属性时,就不需要通过#号来引用 总结:ognl Context包含 ObjectStack属性和ContextMap属性 当Struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action 。然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问。 注意: Struts2中,OGNL表达式需要配合Struts标签才可以使用。如:<s:property value="name"/> 理解ActionContext ActionContext提供了对ognl上下文对象中数据操作的方法. ******************************************************************************************* 演示值栈实例 1.编写JSP <%@ page language="java" pageEncoding="utf-8" contentType="text/html; charset=utf-8"%> <%@ taglib uri="/struts-tags" prefix="s"%> <html> <head> <title>My JSP 'index.jsp' starting page</title> </head> <body> 测试值栈:<br> <a href="${pageContext.request.contextPath}/ognl/valueStackAction_test.action">test</a><br> 2.编写Action package cn.itcast.ognl; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.util.ValueStack; @SuppressWarnings("serial") public class ValueStackAction extends ActionSupport { public String test(){ ServletActionContext.getRequest().setAttribute("username", "usename_request"); ServletActionContext.getRequest().setAttribute("psw", "psw_request"); ServletActionContext.getServletContext().setAttribute("username", "usename_application"); ServletActionContext.getServletContext().setAttribute("psw", "psw_application"); ServletActionContext.getContext().getSession().put("username", "usename_session"); ServletActionContext.getContext().getSession().put("psw", "psw_session"); //方法一 ValueStack valueStack=ServletActionContext.getContext().getValueStack(); return "valueStack"; } } 3.设置配置文件 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN" "http://struts.apache.org/dtds/struts-2.1.7.dtd"> <struts> <package name="ognl" namespace="/ognl" extends="struts-default"> <action name="valueStackAction_*" class="cn.itcast.ognl.ValueStackAction" method="{1}"> <result name="valueStack">/ognl/valueStack.jsp</result> </action> 4.struts.xml配置文件导入 <include file="cn/itcast/ognl/struts_ognl.xml"></include> ************************************************************************************************* OGNL表达式语言(#号的用法) 用法1:访问OGNL上下文和Action上下文,#相当ActionContext.getContext() 1、 如果访问其他Context中的对象,由于他们不是根对象,所以在访问时, 需要添加#前缀。 也可写为#request[‘userName’]或#session[‘userName’]或#appliction[‘userName’] OGNL表达式语言(#号的用法) Action中代码: ServletActionContext.getRequest().setAttribute("username", "username_request"); ServletActionContext.getServletContext().setAttribute("username", "username_application"); ServletActionContext.getContext().getSession().put("username", "username_session"); ValueStack valueStack=ServletActionContext.getContext().getValueStack(); valueStack.set("username", "username_valueStack"); Jsp页面: 使用ognl表达式取值*****************************<br> request:<s:property value="#request.username"/><br> session:<s:property value="#session.username"/><br> application:<s:property value="#application.username"/><br> attr:<s:property value="#attr.username"/><br> valueStack:<s:property value="username"/><br> parameters:<s:property value="#parameters.cid[0]"/><br> 用法1:访问OGNL上下文和Action上下文,#相当ActionContext.getContext() 2 、OGNL会设定一个根对象(root对象),在Struts2中根对象就是ValueStack (值栈) 。如果要访问根对象(即ValueStack)中对象的属性,则可以省略 #命名对象,直接访问该对象的属性即可。 Action中代码: ValueStack valueStack=ServletActionContext.getContext().getValueStack(); valueStack.set("username", "username_valueStack"); Jsp页面: valueStack:<s:property value="username"/> 深入理解值栈中的 ObjectStack 在OgnlValueStack类里有一个List类型的root变量,他存放了一组对象 处于第一位的对象叫栈顶对象。 通常我们在OGNL表达式里直接写上属性的名称即可访问root变量里对象的属性, 搜索顺序是从栈顶对象开始寻找,如果栈顶对象不存在该属性,就会从第二个对象寻找,如果没有找到就从第三个对象寻找,依次往下访问,直到找到为止。 Action中代码: ValueStack valueStack=ServletActionContext.getContext().getValueStack(); //set方法放置对象到map中,map再放入到栈(List集合)上 valueStack.set("student", new Student()); valueStack.set("employee", new Employee()); //直接放置对象到栈(List集合)上 valueStack.getRoot().add(0,new Student()); valueStack.getRoot().add(1,new Employee()); Jsp页面: name:<s:property value="name"/><br> age::<s:property value="age"/><br> number::<s:property value="number"/><br> salary:<s:property value="salary"/><br> ************************************************************************************ 用法2:集合的投影(过滤) 1、集合的投影(只输出部分属性) collectionName.{ expression } <s:iterator value="allList.{name}" var="person"> <s:property/> <br> </s:iterator> 2、集合的过滤 1) 集合的过滤有以下三种方式: a.“?#”:过滤所有符合条件的集合,如:users.{?#this.age > 19}; b.“^#”:过滤第一个符合条件的元素,如:users.{^#this.age > 19}; c.“$#”:过滤最后一个符合条件的元素,如:users.{$#this.age > 19} 。 . 2) this 表示集合中的元素; <s:iterator value="allList.{?#this.age>25}" var="person"> <s:property value="name"/> xxxxxx <s:property value="age"/> <br> </s:iterator> 3、集合的投影和过滤 投影(过滤)操作返回的是一个集合,可以使用索引取得集合中指定的 元素,如:users.{?#this.age > 19}[0] <s:iterator value="allList.{?#this.age>25}.{name}" var="person"> <s:property/><br> </s:iterator> <s:iterator value="allList.{?#this.age>25}[0]" var="person"> <s:property/><br> </s:iterator> ************************************************************************************ 用法3:构造Map,如#{‘foo1’:‘bar1’, ‘foo2’:‘bar2’}。 这种方式常用在给radio或select、checkbox等标签赋值上 jsp页面: <s:radio list=“#{‘male’:‘男’,‘female’:‘女’}” name=“sex” label=“性别” /> 运行结果是 <input type="radio" name="sex" id="sexmale" value="male"/>男 <input type="radio" name="sex" id="sexfemale" value="female"/>女 Action中的代码: Map map=new HashMap(); map.put("male", "男"); map.put("female", "女"); ServletActionContext.getRequest().setAttribute("map", map); jsp页面: <s:property value="#request.map.male"/><br> <s:property value="#request.map['female']"/><br> 运行结果是 男 女 这种方式常用在给radio或select、checkbox等标签赋值上 Action中的代码: Map map=new HashMap(); map.put("male", "男"); map.put("female", "女"); ServletActionContext.getRequest().setAttribute("map", map); jsp页面: <s:radio list="#request.map" name="sex" label="性别" /> 运行结果是 <input type="radio" name="sex" id="sexfemale" value="female"/>女 <input type=“radio” name=“sex” id=“sexmale” value=“male”>男 *********************************************************************************************** OGNL表达式语言(%用法) “%”符号的用途是在标签的属性值被理解为字符串类型时,告诉执行环境%{}里的是OGNL表达式。 形式一: { }中ognl表达式 Action中的代码: ServletActionContext.getRequest().setAttribute("username", "username_request"); jsp页面: <s:textfield name="name" label="%{#request.username} "/> 运行结果是 username_request : <input type="text" name="name" value="" id="name"/> 形式二: { }中值用 ’ ’引起来,这是不再是ogle表达式,而是普通的字符串 jsp页面: <s:textfield name="name" label="%{'foo'}"/> 运行结果是 foo : <input type="text" name="name" value="" id="name"/> *********************************************************************************************** OGNL表达式语言($用法) “$”有两个主要的用途 * 用于在国际化资源文件中,引用OGNL表达式 * 在Struts 2配置文件中,引用OGNL表达式 在struts2配置文件中引用ognl表达式 ,引用request等作用域中的值 Action中的代码: ServletActionContext.getRequest().setAttribute("msgxx", "msg_request"); struts.xml文件中 <package name="ognl" namespace="/ognl" extends="struts-default" > <action name="ognlAction_*" class="cn.itcast.ognl.OgnlAction" method="{1}"> <result name="ognl">/ognl/ongl.jsp?msg=${#request.msgxx}</result> </action> </package> jsp页面: parameters Msg:<s:property value="#parameters.msg[0]"/> 运行结果是 msg_request 在struts2配置文件中引用ognl表达式 ,引用值栈的值 Action中的代码: valueStack.set("msgxx", "msg_valueStack"); struts.xml文件中 <package name="ognl" namespace="/ognl" extends="struts-default" > <action name="ognlAction_*" class="cn.itcast.ognl.OgnlAction" method="{1}"> <result name="ognl">/ognl/ongl.jsp?msg=${msgxx}</result> </action> </package> jsp页面: parameters Msg:<s:property value="#parameters.msg[0]"/> 运行结果是 msg_valueStack ******************************************************************************************** 对于集合类型,OGNL表达式可以使用in和not in两个元素符号。其中,in表达式用来判断某个元素是否在指定的集合对象中;not in判断某个元素是否不在指定的集合对象中,如下所示。 in表达式: <s:if test="'foo' in {'foo','bar'}"> 在 </s:if> <s:else> 不在 </s:else> not in表达式: <s:if test="'foo' not in {'foo','bar'}"> 不在 </s:if> <s:else> 在 </s:else> 除了in和not in之外,OGNL还允许使用某个规则获得集合对象的子集,常用的有以下3个相关操作符。 ?:获得所有符合逻辑的元素。 ^:获得符合逻辑的第一个元素。 $:获得符合逻辑的最后一个元素。 例如代码: <s:iterator value="books.{?#this.price > 35}"> <s:property value="title" /> - $<s:property value="price" /><br> </s:iterator> 在上面代码中,直接在集合后紧跟.{}运算符表明用于取出该集合的子集,{}内的表达式用于获取符合条件的元素,本例的表达式用于获取集合中价格大于35的书集合。 public class BookAction extends ActionSupport { private List<Book> books; .... @Override public String execute() { books = new LinkedList<Book>(); books.add(new Book("A735619678", "spring", 67)); books.add(new Book("B435555322", "ejb3.0",15)); } } ************************************************************************************************ OGNL原理演示实例 实例1 获取属性参数 1.编写JSP <%@ page language="java" pageEncoding="utf-8"%> <%@ taglib uri="/struts-tags" prefix="s"%> <html> <head> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="description" content="This is my page"> </head> <body> 使用El表达式取值#######################################################################################<br> ${requestScope.username}<br> ${sessionScope.username}<br> ${applicationScope.username}<br> <br> 使用ognl表达式取值#######################################################################################<br> 访问作用域中内容:<br> <s:property value="#request.username"/><br> <s:property value="#session['username']"/><br> <s:property value="#application.username"/><br> <s:property value="#attr.username"/><br> <s:property value="#parameters.cid[0]"/><br> <s:property value="username"/><br> 深入理解值栈中的 ObjectStack#######################################################################################<br> <s:property value="name"/><br> <s:property value="salary"/><br> <s:property value="number"/><br> <s:property value="age"/><br> 用法3:构造Map,如‘foo1’:‘bar1’, ‘foo2’:‘bar2’。#######################################################################<br> <!-- <input type="radio" name="sex" id="sexmale" value="male"/><label for="sexmale">男</label> --> <s:radio name="sex" list="#{'male':'男','female':'女'}" label="性别"></s:radio> <br> <s:property value="#request.map.male"/><br> <s:property value="#request.map.female"/><br> <br> "%"符号的用途是在标签的属性值被理解为字符串类型时,告诉执行环境%{}里的是OGNL表达式#######################################################################<br> <br> <s:textfield name="username" value="%{#request.username}"></s:textfield> <s:textfield name="username" value="%{foo}"></s:textfield> <s:textfield name="username" value="%{'foo'}"></s:textfield> "$"有两个主要的用途<br> * 用于在国际化资源文件中,引用OGNL表达式<br> * 在Struts 2配置文件中,引用OGNL表达式####################################################################<br> <s:property value="#parameters.msg[0]"/> <s:debug/> </body> </html> 2.编写Action public class OgnlAction extends ActionSupport { private String name="actionName"; private Integer age=10; public String test(){ ServletActionContext.getRequest().setAttribute("username", "usename_request"); ServletActionContext.getRequest().setAttribute("psw", "psw_request"); ServletActionContext.getServletContext().setAttribute("username", "usename_application"); ServletActionContext.getServletContext().setAttribute("psw", "psw_application"); ServletActionContext.getContext().getSession().put("username", "usename_session"); ServletActionContext.getContext().getSession().put("psw", "psw_session"); //在值栈中放入数据 ValueStack valueStack=ServletActionContext.getContext().getValueStack(); //放置值栈汇中的map集合中,map集合放置list中 valueStack.set("username", "username_valueStack"); //直接放置到list(栈)中 valueStack.getRoot().add(0,new Student()); valueStack.getRoot().add(0,new Employee()); //放置map Map map=new HashMap(); map.put("male","男"); map.put("female","女"); ServletActionContext.getRequest().setAttribute("map", map); return "ognl"; } } 3.编写配置文件 <action name="ognlAction_*" class="cn.itcast.ognl.OgnlAction" method="{1}"> <result name="ognl">/ognl/ognl.jsp?msg=${username}</result> </action> 4.在struts.xml文件中导入配置文件 实例2 表达式的使用 1.编写JSP <%@ page language="java" pageEncoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="/struts-tags" prefix="s"%> <html> <head> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="description" content="This is my page"> </head> <style type="text/css"> .oddClass{ background-color: red;} .evenClass{ background-color:blue;} </style> <body> ognlTag.jsp<br> -----------------------------------------------------------------------------------------------------------<br> property标签用于输出指定值:<br> <s:property/><br> value的值为空,则输出default属性指定的值<br> <s:property value="#request.xxxxx" default="defaultValue"/><br> 注:escape=“false”时,hr作为html标签使用<br> <s:property value="%{'<hr> hr的使用'}" escape="false"/> -----------------------------------------------------------------------------------------------------------<br> <s:set value="#request.username" var="xxxx" scope="request"></s:set> <s:property value="#request.xxxx"/> <br> <s:set value="#request.username" var="xx" scope="page"></s:set> <s:property value="#attr.xx"/> <br> <s:set value="#request.username" var="x"></s:set> <s:property value="#x"/> -----------------------------------------------------------------------------------------------------------<br> push:将对象放入栈顶,不能放入其他范围,当标签结束,会从栈顶删除。了解<br> <s:push value="#request.username"> <s:property/> </s:push> -----------------------------------------------------------------------------------------------------------<br> Action:通过指定命名空间和action名称,该标签允许在jsp页面直接调用Action<br> executeResult true类似于inculde<br> <s:action name="ognlAction_test" namespace="/ognl" executeResult="false"></s:action> -----------------------------------------------------------------------------------------------------------<br> Iterator:标签用于对集合进行迭代,这里的集合包含List、Set和数组<br> 该标签没有使用var 则遍历的对象放入到了栈顶<br> <s:iterator value="#request.allList"> <s:property value="name" /> ~~~~<s:property value="age" /> <br> </s:iterator> <br> <br> <br> <br> 该标签使用了var 则遍历的对象放入到了栈顶,同时还放入到map集合中<br> <s:iterator value="#request.allList" var="person"> <s:property value="name" /> ~~~~<s:property value="age" /> <br> <s:property value="#person.name" /> ~~~~<s:property value="#person.age" /> <br> </s:iterator> <br> <br> <s:iterator value="#request.allList" var="person" begin="2" end="6" step="2"> <s:property value="#person.name" /> ~~~~<s:property value="#person.age" /> <br> </s:iterator> <br> <br> <s:iterator value="#request.allList" var="person" status="st"> <s:property value="#person.name" /> ~~~~<s:property value="#person.age" /> <br> 返回当前迭代了几个元素:<s:property value="#st.count"/><br> 返回当前迭代元素的索引:<s:property value="#st.index"/><br> 回当前被迭代元素的索引是否是偶数:<s:property value="#st.even"/><br> 回当前被迭代元素的索引是否是奇数:<s:property value="#st.odd"/><br> 返回当前被迭代元素是否是第一个元素:<s:property value="#st.first"/><br> 返返回当前被迭代元素是否是最后一个元素:<s:property value="#st.last"/><br> </s:iterator> 应用<br> <table border="1"> <s:iterator value="#request.allList" var="person" status="st"> <tr class="<s:property value='#st.even?"evenClass":"oddClass"'/>"> <td><s:property value="#person.name"/></td> <td><s:property value="#person.age" /></td> <td> <s:if test="#person.age<24">少年</s:if> <s:elseif test="#person.age<27">中年</s:elseif> <s:else>老年</s:else> </td> </tr> </s:iterator> </table> -----------------------------------------------------------------------------------------------------------<br> url:该标签用于创建url,可以通过"param"标签提供request参数<br> 注:s:param与s:property标签在使用时,不需要就加%{},其他的要加<br> <s:url action="oglnAction_test" namespace="/ognl" var="url"> <s:param name="name" value="%{'张三丰'}"></s:param> <s:param name="age" value="12"></s:param> </s:url> <a href='<s:property value="#url"/>'>test</a> <br> 使用value后缀必须加.action<br> <s:url value="oglnAction_test.action" namespace="/ognl" var="url"> <s:param name="name" value="%{'张三丰'}"></s:param> <s:param name="age" value="12"></s:param> </s:url><br> <s:debug/> <a href='<s:property value="#url"/>'>test</a> -----------------------------------------------------------------------------------------------------------<br> ognl操作集合:<br> <s:property value="#request.allList.size"/> -----------------------------------------------------------------------------------------------------------<br> 使用ognl操作list和数组 <br> <s:iterator value="{1,2,3,4}"> <s:property/> </s:iterator> <br> <s:iterator value="{'s1','s2','s3','s4'}" var="str"> <s:property value="#str"/> </s:iterator> -----------------------------------------------------------------------------------------------------------<br> 使用ognl操作map<br> <s:iterator value="#{'key01':'value01','key02':'value02'}"> <s:property/> </s:iterator> <br><br> 处理map集合时, 'key01':'value01','key02':'value02'; key value<br> <s:iterator value="#{'key01':'value01','key02':'value02'}"> <s:property value="key"/>~~~~~ <s:property value="value"/> </s:iterator> <br> <s:iterator value="#{'key01':'value01','key02':'value02'}" var="map"> <s:debug/> <s:property value="#map.key"/>~~~~~ <s:property value="#map.value"/> </s:iterator> -----------------------------------------------------------------------------------------------------------<br> 集合的投影(只输出部分属性)<br> <s:iterator value="#request.allList.{name}" var="person"> <s:property/> <br> </s:iterator> -----------------------------------------------------------------------------------------------------------<br> 集合的过滤<br> <s:iterator value="#request.allList.{?#this.age>24}" var="person"> <s:property value="name"/> ~~ <s:property value="age"/> <br> </s:iterator> -----------------------------------------------------------------------------------------------------------<br> 集合的投影和过滤 <s:iterator value="#request.allList.{?#this.age>24}.{name}" var="person"> <s:property/> <br> </s:iterator> </body> </html> 2.编写Action public class OgnlTagAction extends ActionSupport { private static final long serialVersionUID = 1L; private List allList; public String test(){ ServletActionContext.getRequest().setAttribute("username", "usename_request"); ServletActionContext.getServletContext().setAttribute("username", "usename_application"); ServletActionContext.getContext().getSession().put("username", "usename_session"); //在值栈中放入数据 ValueStack valueStack=ServletActionContext.getContext().getValueStack(); //放置值栈汇中的map集合中,map集合放置list中 //valueStack.set("username", "username_valueStack"); allList=new ArrayList(); //初始化集合 for(int i=0;i<10;i++){ Person p=new Person("tom"+i,20+i); allList.add(p); } ServletActionContext.getRequest().setAttribute("allList", allList); return "ognlTag"; } } 3.设置配置文件 <action name="ognlTagAction_*" class="cn.itcast.ognl.OgnlTagAction" method="{1}"> <result name="ognlTag">/ognl/ognlTag.jsp</result> </action> 4.导入到Struts.xml文件中
原文:http://blog.sina.com.cn/s/blog_3eb047df0100pyls.html