1.OGNL是Object-Graph Navigation Language的缩写,是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。其中OGNL用得最多的地方就是和Struts2的标签绑定,也可以在配置文件中通过${}使用OGNL表达式。
2.OGNL表达式中有几个常用的符号,下面介绍这三种符号的使用:
(1).OGNL中$号的使用:第一种,可以在国际化资源文件中引用OGNL表达式。第二种,可以在struts.xml配置文件中引用OGNL表达式。
(2).OGNL中%号的使用:%符号的用途是在标志属性为字符串类型时,计算OGNL表达式的值。
~使用%{}可以取出保存在值堆栈中的Action对象,直接调用它的方法。
~如果Action类继承了ActionSupport类,那么在页面标签中可以使用%{getText('key')}获取国际化信息。
(3).OGNL中#号的使用:OGNL中的#号可以取出堆栈上下文中存放的对象,访问OGNL上下文和Action上下文。#相当于ActionContext.getContext()。
~其中在栈的上下文中有5个对象(attr,request,session,application,parameters):
attr:用于按request>>session>>application顺序访问其属性,#attr.userName,相当于按顺序从三个范围读取userName属性,直到找到为止。
request:包含当前HttpServletRequest的属性的Map,#request.userName,相当于request.getAttribute("userName")。
session:包含当前HttpSession的属性的Map,#session.userName,相当于session.getAttribute("userName")。
application:包含当前应用的ServletContext的属性的Map,#application.userName,相当于application.getAttribute("userName")。
parameters:包含当前HTTP请求参数的Map,#parameters.id[0],相当于request.getParameter("id")。
3.获取Action中的属性值或者Action中的对象的某某属性值:
利用<s:property/>标签可以直接获取Action中的引用类型user里面的userName属性,同样可以通过user.address.addr获取user中引用类型address中的addr属性的值,像这种一层层往下传递的访问方式,即所谓的导航,也就是一步步往下调用。
4.调用Action的对象里面的普通方法:
默认的会把Action放到值栈里面去,而值栈在访问的时候,并不需要值栈的名字,当我们使用<s:property value="user.getVOMethod()"/>的时候,它会自动到值栈里面查找Action对象里面有没有user对象,如果发现有user对象,然后它就再找user里面有没有getVOMethod()方法,如果发现有,于是调用getVOMethod()这个方法。
实际上调用getVOMethod()方法的过程与获取表单中的姓名密码的方式都是相同的,都是到值栈里面去查找,找是否存在user对象,如果存在,接着查找user中是否存在某某属性或方法。
5.调用Action中的静态方法:
我们可以在JSP页面中使用OGNL表达式调用Action中的静态方法,调用Action中的静态方法时,与上面调用user对象的getVOMethod()方法的过程,是截然不同的。此时value的写法是固定的,以@开头,后面跟上具体的包名,然后@加上静态方法,比如<s:property value="@com.gk.action.LoginAction@getStaic()"/>。另外user对象只是LoginAction中的一个属性,这个属性会自动放到值栈里面,而值栈调用的时候,不用加上@或者包名等等,所以直接user.getVOMethod()就可以了。
6.调用JDK类中的静态方法:
可以使用<s:property value="@@floor(46.68)"/>输出floor()的执行结果,这就意味着如果不在@@中指定类的话,默认就表示java.lang.Math类,当前大多数情况下,都不会省略这个类,都会写全了的,然后在后面加上静态方法。
7.集合的伪属性:OGNL能够引用集合的一些特殊的属性,这些属性并不是JavaBean模式,例如size(),length(),当表达式引用这些属性时,OGNL会调用相应的方法,这就是伪属性,比如获取一个List的大小,可以使用<s:property value="testList.size()"/>。
List的伪属性:size,isEmpty,iterator。
Set的伪属性:size,isEmpty,iterator。
Map的伪属性:size,isEmpty,keys,values。
Iterator(迭代)的伪属性:next,hasNext。
Enumeration(枚举)的伪属性:next,hasNext,nextElement,hasMoreElements。
8.获取集合中元素的实质就是调用它的toString()方法:
OGNL表达式还可以直接获取集合中的元素,事实上是在调用集合的toString()方法,所以我们可以根据实际情况通过重写集合的toString()方法来实现个性化输出,甚至它还可以像访问数组那样,直接testList[2]获取集合的元素,但这种方法只适用于List,不适用于Map。因为Map的索引是key,不是数值,另外,由于HashSet的元素是没有顺序的,所以也不能用下标获取单个元素。
9.利用投影获取属性:利用投影获取List中对象的userName属性时,其中{}表示的是一个集合,stus.{userName}就表示将stus中所有的userName属性取出组成一个新的列表。
10.利用选择获取属性:
OGNL表达式是很灵活的,可以同时使用选择技术与投影技术获得属性,#this代表当前元素, 问号?是把所有满足条件的元素都取出来,上箭头^是开始的意思,美元符号$是结束的意思,并且这三个符号返回的都是List列表。
11.补充:
(1).当OGNL取不到值的时候,它不会报错,而是什么都不显示
(2).<s:property value="[0]"/>返回的是ValueStack中从上至下的所有的Object,<s:property value="[1]"/>返回的是ValueStack中从上至下的第二个Objec。
(3).<s:property value="[0].username"/>返回的是成员变量username的值,假设ValueStack中存在两个Action的话,如果第一个Action如果没有username变量,那么它会继续找第二个Action。那么在什么情况下ValueStack中会存在两个Action呢?
答案是在struts.xml中配置的是从一个Action通过<result type="chain">跳转到另一个Action。
(4).<constant name="struts.ognl.allowStaticMethodAccess" value="true"/>, 在Struts2.1.6中必须设置struts.ognl.allowStaticMethodAccess为true之后,才允许使用OGNL访问静态方法。而在Struts2.0.11则无需设置,即可直接访问。
package com.gk.action; import com.gk.bean.Cat; import com.gk.bean.User; import com.opensymphony.xwork2.ActionSupport; public class OgnlAction extends ActionSupport { private String username; private String password; private User user=new User(); private Cat cat=new Cat(); public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } public String execute(){ return SUCCESS; } }
package com.gk.bean; public class User { private int age = 8; public User() { } public User(int age) { this.age = age; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "user"+age; } }
package com.gk.bean; public class Cat { private Dog friend; public Dog getFriend() { return friend; } public void setFriend(Dog friend) { this.friend = friend; } public String miaomiao(){ return "miaomiao"; } }
package com.gk.bean; public class Dog { private String name; public Dog(){ } public Dog(String name){ this.name=name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString(){ return "dog"+name; } }
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <a href="ognl?username=u&password=p">ognl</a> </body> </html>
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ taglib uri="/struts-tags" prefix="s"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'ognl.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <ol> <li>访问值栈中的:username = <s:property value="username " /></li> <li>访问值栈中的:password=<s:property value="password" /></li> <li>访问值栈中对象的普通属性(get set方法):<s:property value="user.age" /></li> <li>访问值栈中对象的普通属性(get set方法):<s:property value="cat.friend.name" /></li> <li>访问值栈中对象的普通方法<s:property value="cat.miaomiao()"/></li> </ol> <s:debug></s:debug> </body> </html>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <constant name="struts.enable.DynamicMethodInvocation" value="true"></constant> <constant name="struts.devMode" value="true"></constant> <package name="ognl" namespace="/" extends="struts-default"> <action name="ognl" class="com.gk.action.OgnlAction"> <result>/ognl.jsp</result> </action> </package> </struts>
package com.gk.action; import com.gk.bean.Cat; import com.gk.bean.User; import com.opensymphony.xwork2.ActionSupport; public class OgnlAction extends ActionSupport { private String username; private String password; private User user; private Cat cat=new Cat(); public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } public String execute(){ return SUCCESS; } }
package com.gk.bean; public class User { private int age = 8; public User(int age) { this.age = age; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "user"+age; } }