Struts2之OGNL表达式语言

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.allowStaticMethodAccesstrue之后才允许使用OGNL访问静态方法。而在Struts2.0.11则无需设置,即可直接访问





12.接下来附上一个例子,通过这个例子可以了解如何通过OGNL表达式获取Action中的属性值或者Action对象中的某个属性值,也可以知道如何调用Action中对象里面的普通方法和Action类的普通方法:

(1).新建一个struts2项目,项目名为Struts2_OGNL,首先新建一个Action类,此类继承于ActionSupport类,代码如下:
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;
	}

}


(2).其中又有几个JavaBean类,分别为User,Cat,Dog类,代码分别如下:
User.java文件代码:
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;
	}
	
	
	
}

Cat.java文件代码:
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";
	}
	
}

Dog.java文件代码:
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;
	}
}

(3).其中又有两个JSP页面,一个是index.jsp页面,一个为ognl.jsp页面,代码分别如下:
index.jsp文件代码:
<%@ 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>

ognl.jsp代码如下,通过struts2的标签和OGNL表达式来获取Action的属性:
<%@ 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>

(4).struts.xml配置如下:
<?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>




13.此时我们访问index.jsp页面,结果如下图所示:

Struts2之OGNL表达式语言_第1张图片

点击此链接:

Struts2之OGNL表达式语言_第2张图片

查看一下值栈的内容和上下文环境:

Struts2之OGNL表达式语言_第3张图片

(1).我们可以看到通过超链接传入参数username和password,然后取出值栈里的username和password的属性,然后我们又看到值栈内容中有user属性,我们通过<s:property value="user.age" />获取到了8,原因是我们在User类里面把age初始化为8,在Action类中使用User user=new User这行代码实例化了user对象,然后通过toString方法输出来,所以值栈中user属性的值为user8。


(2).我们通过<s:property value="cat.friend.name" />想要获取cat对象中的friend属性的名字,但是取不出来,是因为我们没有把cat.friend.name这个参数传进去,如果我们输入地址: http://localhost:8083/Struts2_OGNL/ognl?username=u&password=p&cat.friend.name=Lc 的话,就可以取出来了,这也是OGNL如何访问值栈中的内容。
Struts2之OGNL表达式语言_第4张图片



(3)如果我们输入 http://localhost:8083/Struts2_OGNL/ognl?username=u&password=p&user.age=90 这个地址的话,年龄就会变为90岁了:
Struts2之OGNL表达式语言_第5张图片



(4).如果我们把User.java文件中public User(){}这个无参构造方法删除掉,然后在OgnlAction中的代码中不实例化这个User类,即OgnlAction.java文件代码如下:
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;
	}

}

Use.java文件代码修改成:
 
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;
	}
	
	
	
}

然后在输入 http://localhost:8083/Struts2_OGNL/ognl?username=u&password=p 发现age内容为空了。

如果我们输入地址为: http://localhost:8083/Struts2_OGNL/ognl?username=u&password=p&user.age=23 看能否把age的值23传进去,发现报了个错误,这个错误是实例化User出错,所以一般我们的域模型,即JavaBean对象永远都要提供一个无参的构造方法,要不然就不知道实例化哪个类了。


(5).我们通过<s:property value="cat.miaomiao()"/>这个标签可以直接获取cat对象的miaomiao()方法。如果想取得OgnlAction类的普通方法的话,即Action类普通方法,假如Action类中有个返回类型为String的普通方法mm()的话,可以直接使用<s:property value="mm()"/>,这样就可以获得该Action类普通方法的返回值。


(6).其中为什么OGNL叫对象图导航语言呢?从上面这个例子来说,访问OgnlAction类的user对象的age属性,就可以使用user.age来取到,如果访问OgnlAction类中的cat对象的miaomiao方法,可以使用cat.miaomiao(),如果想访问cat对象的friend对象中的name属性,就用cat.friend.name,这样就可以取得Dog的friend对象的name属性,但是必须要传入参数值进去。




14.本来还想再附上多两个例子的,其中一个例子是使用OGNL来访问静态方法和静态属性的,但是昨天晚上写代码时发现了一些警告和错误,想专门写一篇博客来记录,所以就先写到这,基本的做法和说明都在上面已经讲述。后面我写好访问静态方法和静态属性的那篇文章后,再附上地址。那篇文章我已经写好,对于使用OGNL访问静态方法时出现的问题进行了介绍并解决,文章地址如下: http://blog.csdn.net/u012561176/article/details/44958915



15.以上内容仅供大家学习和参考,谢谢!


你可能感兴趣的:(struts2,Ognl,OGNL表达式语言)