OGNL表达式语言以及在Structs中的运用


这里写图片描述


OGNL

OGNL是Object-Graph Navigation Language对象图导航语言的缩写,它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。
##基本介绍

OGNL可以让我们用非常简单的表达式访问对象层,例如,当前环境的根对象为user1,则表达式person.address[0].province可以访问到user1的person属性的第一个address的province属性。

这种功能是模板语言的一个重要补充,象jsp2.0,velocity,jelly等等,都有类似的功能,但是ognl比它们完善得多,而且以一个独立的lib出现,方便我们构建自己的框架。

webwork2和现在的Struts2.x中使用OGNL取代原来的EL来做界面数据绑定,所谓界面数据绑定,也就是把界面元素(例如一个textfield,hidden)和对象层某个类的某个属性绑定在一起,修改和显示自动同步。

和struts1.x的formbean相比,这样做的好处非常明显:在webwork中不需要为每个页面专门写formbean,可以直接利用对象层的对象。例如在对象设计中,我们的User和Person是分开的,而一个注册用户界面需要填写两者的内容,在webwork中,就可以保持后台的对象结构,把属于用户属性的界面元素用user.person.xxx绑定,把属于账号属性的界面元素用user.xxx绑定。
#Structs2
OGNL,可以方便地操作对象属性的开源表达式语言,使页面更简洁;
支持运算符(如±*/),比普通的标志具有更高的自由度和更强的功能;
Struts 2默认的表达式语言是OGNL,原因是它相对其它表达式语言具有下面几大优势:

  • 支持对象方法调用,如xxx.doSomeSpecial();
  • 支持类静态的方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名 | 值名],例如:
@java.lang.String@format('foo %s', 'bar')或@tutorial.MyConstant@APP_NAME;
  • 支持赋值操作和表达式串联,例如
price=100, discount=0.8, calculatePrice(price*discount),这个表达式会返回80;
  • 访问OGNL上下文(OGNL context)和ActionContext;
  • 操作集合对象。
  • 可以直接new一个对象

Ognl有一个上下文(Context) 概念,就是一个Map结构,它实现了 java.utils.Map 接口,在Structs2中上下文(Context)的实现为ActionContext

OGNL表达式示例

这里写图片描述

参考视频:http://www.chuanke.com/v7232853-198071-1144871.html

示例一

Person.java

//package ognltest;

public class Person {

	private String name;
	private int  age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

OGNL1.java

//package ognltest;

import ognl.Ognl;
import ognl.OgnlException;

public class OGNL1 {
	public static void main(String[] args) {
		Person person = new Person();
		person.setName("李未央");	
		
		try {
			//从person对象中获取name属性值,类似反射,根据属性名获取属性值
			Object value = Ognl.getValue("name", person);
			System.out.println(value);
		} catch (OgnlException e) {
			e.printStackTrace();
		}
	}
}

结果:

李未央

示例2

OGNL2.java

//package ognltest;

import java.util.HashMap;
import java.util.Map;

import ognl.Ognl;
import ognl.OgnlException;

/**
 * 对于使用上下文的OGNL
 * 若不指定从哪一个对象中查找“name”属性,
 * 则OGNL直接从根对象(root)查找,
 * 若指定查找对象(使用#号指定,如#person1),
 * 则从指定的对象中查找,
 * 若指定对象不再上下文中则会抛出异常
 * 指定查找对象则必须要保证指定对象在上下文环境中。
 * 把集合中某个对象的操作进行了简化
 */
public class OGNL2 {
	public static void main(String[] args) {
		// 创建一个上下文Context对象,来用保存多个对象
		Map<String, Object> context = new HashMap<String, Object>();

		Person person1 = new Person();
		person1.setName("老舍");

		Person person2 = new Person();
		person2.setName("朱自清");

		Person person3 = new Person();
		person3.setName("海子");

		context.put("person1", person1);
		context.put("person2", person2);
		context.put("person3", person3);

		Person person4 = new Person();
		person4.setName("金庸");

		try {
			// 根据属性名获取属性值
			Object value1 = Ognl.getValue("name", context, person1);
			System.out.println("ognl expression\"name\":" + value1);

			Object value2 = Ognl.getValue("#person2.name", context, person2);
			System.out.println("ognl expression\"#person2.name\":" + value2);
			
			//取得不是根对象person2的属性值,而是person1的name属性值
			Object value3 = Ognl.getValue("#person1.name", context, person2);
			System.out.println("ognl expression\"#person1.name\":" + value3);]
			
			//以person4为根对象
			Object value4 = Ognl.getValue("name", context, person4);
			System.out.println("ognl expression\"name\":" + value4);

			// #person4.name必须要在容器中
			// Object value5 = Ognl.getValue("#person4.name",context, person4);
			// System.out.println("ognl expression\"#person4.name\":"+value5);
		} catch (OgnlException e) {
			e.printStackTrace();
		}

	}
}

执行结果:

ognl expression"name":老舍
ognl expression"#person2.name":朱自清
ognl expression"#person1.name":老舍
ognl expression"name":金庸

示例3

OGNL3.java

//package ognltest;

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
/**
 * 使用OGNL调用方法也非常简单,
 * 对应成员方法调用,只需要给出方法的名称+(),
 * 若有参数,直接写在括号内,与一般调用Java方法一致
 * 对于静态方法的调用,需要使用如下的格式:
 * @ClassName@method,
 * 对应静态变量需要使用如下格式:
 * @ClassName@field
 */
public class OGNL3 {
	public static void main(String[] args) {
		// OGNL提供了一个上下文类,他实现了Map接口
		OgnlContext context = new OgnlContext();

		Person person1 = new Person();
		person1.setName("项羽诸葛");

		Person person2 = new Person();
		person2.setName("李青盲僧");

		Person person3 = new Person();
		person3.setName("张飞");

		context.put("person1", person1);
		context.put("person2", person2);
		context.put("person3", person3);

		context.setRoot(person1);
		//context.setRoot(person2);
		//context.setRoot(person3);

		try {
			// 调用成员方法
			Object value = Ognl.getValue("name.length()", context, context.getRoot());
			System.out.println("person1 name length is:" + value);

			Object upperCase = Ognl.getValue("#person2.name.toUpperCase()", context, context.getRoot());
			System.out.println("person2 name upperCase is;" + upperCase);

			Object invokeWithArgs = Ognl.getValue("name.charAt(2)", context, context.getRoot());
			System.out.println("people1 name.charAt(2) is:" + invokeWithArgs);

			// 调用静态方法
			Object min = Ognl.getValue("@java.lang.Math@min(4,10)", context, context.getRoot());
			System.out.println("min(4,10)is :" + min);

			// 调用静态变量
			Object e = Ognl.getValue("@java.lang.Math@E", context, context.getRoot());
			System.out.println("E is :" + e);

		} catch (OgnlException e) {
			e.printStackTrace();
		}
	}
}

执行结果:

person1 name length is:4
person2 name upperCase is;李青盲僧
people1 name.charAt(2) is:诸
min(4,10)is :4
E is :2.718281828459045

context.setRoot(person2);执行结果为:

person1 name length is:4
person2 name upperCase is;李青盲僧
people1 name.charAt(2) is:盲
min(4,10)is :4
E is :2.718281828459045

示例4

Classroom.java

包含Classroom类和Student类

//package ognltest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Classroom {
	private List<String> students = new ArrayList<String>();

	public List<String> getStudents() {
		return students;
	}

	public void setStudents(List<String> students) {
		this.students = students;
	}
	
}
class Student{
	private Map<String, Object> contactWays = new HashMap<>();

	public Map<String, Object> getContactWays() {
		return contactWays;
	}

	public void setContactWays(Map<String, Object> contactWays) {
		this.contactWays = contactWays;
	}
}

OGNL4.java

//package ognltest;

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
/**
 * OGNL不仅可以操作集合对象,还可以创建集合对象,
 * 对集合操作与属性的操作没什么不同,
 * 需要注意的是OGNL人为List和Array是一样的
 * 使用OGNL创建List集合使用{},创建Map对象是使用#{}
 */
public class OGNL4 {
	public static void main(String[] args) {
		// OGNL提供了一个上下文类,他实现了Map接口
		OgnlContext context = new OgnlContext();

		Classroom classroom = new Classroom();
		classroom.getStudents().add("摇滚");
		classroom.getStudents().add("轻音乐");
		classroom.getStudents().add("民谣");
		classroom.getStudents().add("流行");
		classroom.getStudents().add("电子");

		Student student = new Student();
		student.getContactWays().put("loveNumber", "520");
		student.getContactWays().put("foreverNumber", "1314");
		student.getContactWays().put("happyNumber", "1111");

		context.put("classroom", classroom);
		context.put("student", student);

		context.setRoot(classroom);

		try {
			// 获得classroom的students集合
			Object collection = Ognl.getValue("students", context, context.getRoot());
			System.out.println("students collection is:" + collection);

			// 获得classroom的students集合
			Object firststudent = Ognl.getValue("students[0]", context, context.getRoot());
			System.out.println("first student is:" + firststudent);

			// 调用集合的方法
			Object size = Ognl.getValue("students.size()", context, context.getRoot());
			System.out.println("students collection size is:" + size);

			System.out.println("------split line---------");

			Object mapCollection = Ognl.getValue("#student.contactWays", context, context.getRoot());
			System.out.println("mapColection is :" + mapCollection);

			Object firstElement = Ognl.getValue("#student.contactWays['loveNumber']", context, context.getRoot());
			System.out.println("the first element of contactWays is :" + firstElement);
			//相当于System.out.println(student.getContactWays().get("loveNumber"));

			System.out.println("------split line---------");

			// 创建集合
			Object createCollection = Ognl.getValue("{'aa','bb','cc','dd'}", context, context.getRoot());
			System.out.println(createCollection);
			// 创建Map集合
			Object createMapCollection = Ognl.getValue("#{'天气':'晴','黄昏':'日落'}", context, context.getRoot());
			System.out.println(createMapCollection);

		} catch (OgnlException e) {
			e.printStackTrace();
		}
	}
}

执行结果:

students collection is:[摇滚, 轻音乐, 民谣, 流行, 电子]
first student is:摇滚
students collection size is:5
------split line---------
mapColection is :{foreverNumber=1314, happyNumber=1111, loveNumber=520}
the first element of contactWays is :520
------split line---------
[aa, bb, cc, dd]
{天气=晴, 黄昏=日落}

示例5

Human.java

//package ognltest;

import java.util.ArrayList;
import java.util.List;

public class Human {
	private String name;
	private String sex;
	private int age;
	private List<Human> friends = new ArrayList<Human>();

	public Human() {
	}

	public Human(String name, String sex, int age) {
		super();
		this.name = name;
		this.sex = sex;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public List<Human> getFriends() {
		return friends;
	}

	public void setFriends(List<Human> friends) {
		this.friends = friends;
	}

	@Override
	public String toString() {
		return "Human [name=" + name + ", sex=" + sex + ", age=" + age + "]";
	}
}

OGNL5.java

//package ognltest;

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;

public class OGNL5 {
	public static void main(String[] args) {
		OgnlContext context = new OgnlContext();

		Human human = new Human();
		human.setName("冬音");
		human.setSex("male");
		human.setAge(22);
		human.getFriends().add(new Human("钢琴", "female", 21));
		human.getFriends().add(new Human("长笛", "female", 12));
		human.getFriends().add(new Human("小提琴", "male", 23));
		human.getFriends().add(new Human("风琴随风如琴似梦", "male", 23));
		human.getFriends().add(new Human("萨克斯", "female", 43));
		human.getFriends().add(new Human("单簧管", "female", 45));

		context.put("human", human);
		context.setRoot(human);

		try {

			/**
			 * OGNL过滤集合的语法:collection.{?expression} 
			 * ?是获得所有符合逻辑的元素 
			 * ^获得符合逻辑的第一个元素
			 * $获得符合逻辑的最后一个元素
			 */
			Object filterCollection = Ognl.getValue("friends.{?#this.name.length()>7}", context, context.getRoot());
			System.out.println("filterCollection is:" + filterCollection);

			System.out.println("-----------呆萌的分隔线------------");
			// OGNL投影集合的语法为:collection.{expression}
			Object projectionCollection = Ognl.getValue("friends.{name}", context, context.getRoot());
			System.out.println("projectionCollection is:" + projectionCollection);
		} catch (OgnlException e) {
			e.printStackTrace();
		}
	}
}

执行结果:

filterCollection is:[Human [name=风琴随风如琴似梦, sex=male, age=23]]
-----------呆萌的分隔线------------
projectionCollection is:[钢琴, 长笛, 小提琴, 风琴随风如琴似梦, 萨克斯, 单簧管]

若OGNL格式输入错误,会提示下面的格式错误

Was expecting one of:
    "," ...
    "=" ...
    "?" ...
    "||" ...
    "or" ...
    "&&" ...
    "and" ...
    "|" ...
    "bor" ...
    "^" ...
    "xor" ...
    "&" ...
    "band" ...
    "==" ...
    "eq" ...
    "!=" ...
    "neq" ...
    "<" ...
    "lt" ...
    ">" ...
    "gt" ...
    "<=" ...
    "lte" ...
    ">=" ...
    "gte" ...
    "in" ...
    "not" ...
    "<<" ...
    "shl" ...
    ">>" ...
    "shr" ...
    ">>>" ...
    "ushr" ...
    "+" ...
    "-" ...
    "*" ...
    "/" ...
    "%" ...
    "instanceof" ...
    "." ...
    "(" ...
    "[" ...
    "}" ...
    <DYNAMIC_SUBSCRIPT> ...
    ]

OGNL在Structs2中的运用

参考:http://blog.csdn.net/tjcyjd/article/details/6850203
Structs2 中的OGNL Context实现者为ActionContext。

OGNL Context 包含的对象

ValueStack(值栈,根对象)
parameters
request
session
application
attr

当Structs2 接收一个请求时,会迅速创建ActionContext,ValueStack,action。然后把 action 存放进ValueStack,所以action的实例变量可以被OGNL访问。

值栈(ValueStack)

值栈(ValueStack)是Structs 2 中的根对象。

可以在值栈中放入、删除、查询对象。访问值栈中的对象不用“#”。
Struts2总是把当前Action实例放置在栈顶。所以在OGNL中引用Action中的属性也可以省略“#”。

ValueStack的实现类为 OgnlValueStack,该对象存放的一组对象。在 OgnlValueStack 类里有一个 List 类型的 root 变量,就是使用它存放一组对象

在root变量中处于第一位的对象叫栈顶对象。通常我们在OGNL表达式里直接写上属性的名称即可访问root变量里的对象的属性,搜索顺序从栈顶对象开始寻找,一直向下寻找

Struts2的标签库都是使用OGNL表达式来访问ActionContext中的对象数据的。如:<s:propertyvalue="xxx"/>。

${foo} //在jsp页面中,获得值栈中某个对象的foo属性

#符号

访问非根对象属性,需要加#前缀。

  • application 对象 用于访问ServletContext
#application.userName 或者 #application['userName'] 
相当于
//调用ServletContext的getAttribute("userName")
  • session 对象 用来访问HttpSession
#session.userName 或者 session['userName']
相当于
session.getAttribute("userName")
  • request 对象 用来访问 HttpServletRequest属性的Map
#request.userName 或者 #request['userName']
相当于
request.getAttribute("userName")
  • parameter对象 用来访问HTTP的请求参数
#parameters.userid 或者 #parameters['userid']
相当于
request.getparameter("userid")
  • attr 对象 用于按 page–>request–>session–>application 顺序访问其属性
    ##OGNL取值示例

index.jsp通过action跳转到ognl.jsp,携带请求参数,action对session,application,request赋值,传递设置好的参数,ognl.jsp显示

structs.xml

<action name="ognl" class="action.OgnlAction">
 			<result>/ognl.jsp</result>
</action>

OgnlAction.java

//package action;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

@SuppressWarnings("serial")
public class OgnlAction extends ActionSupport {

	private String message;
	
	public String getMessage() {
		return message;
	}
	public void setMessage(String message) {
		this.message = message;
	}
	@Override
	public String execute() throws Exception {
		message="hello";
		ActionContext context = ActionContext.getContext();
		context.put("request1", "request");
		context.getSession().put("session1", "session");
		context.getApplication().put("application1", "appication");
		return SUCCESS;
	}
}

index.jsp

...
<body>
	<a href="ognl.action?user=">访问ognl.jsp</a>
</body>
..

login.jsp

..
<body>
	0.EL表达式获取:${message}<br/>
	1.获取message变量:<s:property value="message"/><br/>
	2.获取request变量:<s:property value="#request['request1']"/><br/>
	3.获取session变量:<s:property value="#session['session1']"/><br/>
	4.获取application变量:<s:property value="#application.application1"/><br/>
	5.获取请求参数:<s:property value="#parameters.user"/><br/>
</body>
..

执行结果:

 0.EL表达式获取:hello
 1.获取message变量:hello
 2.获取request变量:request
 3.获取session变量:session
 4.获取application变量:appication
 5.获取请求参数:狄川是

在jsp页面中通过EL表达式${request1},${session1},${application1},${param.user},同样可以获取上面的值

采用OGNL表达式创建List/Map集合对象

list.jsp

 <%@ taglib uri="/struts-tags" prefix="s" %>
 ..
<body>
	<!-- 创建list集合: -->
	<s:set name="list1" value="{'A梦','B梦','C梦'}"></s:set>
	<s:iterator value="#list1" id="n">
		<s:property value="n"/>,	
	</s:iterator>
	<br/>
	<!-- 创建map集合 -->
	<s:set name="map" value="#{'天':'地','玄':'黄' }"></s:set>
		<s:iterator value="#map" >
		<s:property value="key"/>=<s:property value="value"/><br/>		
	</s:iterator>
</body>

结果:

A梦, B梦, C梦, 
天=地
玄=黄

set标签将某个值放入到指定范围
scope:指定变量放置的范围
action 默认放置在OGNL Context中
value 赋给变量的值,未设置,则将值栈栈顶的值赋给变量
###OGNL表达式判断对象是否存在集合中
判断创建的map集合是否存在

<hr color="red">
	
	<s:if test="'map' in {'map',map1}">
		map存在
	</s:if>
	<s:else>
		map不存在
	</s:else>
	<br/>
	<s:if test="'map' not in{'map','map2'">
		map集合不在{'map','map2'}	
	</s:if>
	<s:else>
		map集合在{'map','map2'}
	</s:else>

执行结果:

map存在 
map集合在{'map','map2'} 

OGNL表达式的投影功能

BookAction.java

//package action;

import java.util.ArrayList;
import java.util.List;

import com.opensymphony.xwork2.ActionSupport;

@SuppressWarnings("serial")
public class BookAction extends ActionSupport {
	private List<Book> books;
	
	@Override
	public String execute() throws Exception {
		books = new ArrayList<>();
		books.add(new Book("大唐英雄传",23.6));
		books.add(new Book("碧血剑",32.5));
		books.add(new Book("法医秦明",43.4));
		return SUCCESS;
	}

	public List<Book> getBooks() {
		return books;
	}

	public void setBooks(List<Book> books) {
		this.books = books;
	}
}

<action name="book" class="action.BookAction">
 			<result>/book.jsp</result>
 		</action>

Book.java

//package action;

public class Book {
	private String title;
	private double price; 
	
	public Book() {
		super();
	}
	public Book(String title, double price) {
		super();
		this.title = title;
		this.price = price;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getTitle() {
		return title;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public double getPrice() {
		return price;
	}
}

book.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
		<h2>这里是book.jsp</h2>
		<!--  ?是获得所有符合逻辑的元素 
		 ^获得符合逻辑的第一个元素
 		 $获得符合逻辑的最后一个元素 -->
		<s:iterator value="books.{?#this.price>30}">
			<s:property value="title"/>$<s:property value="price"/><br/>
		</s:iterator>
</body>
</html>

执行结果:

price 大于30的输入

这里是book.jsp
碧血剑$32.5
法医秦明$43.4

<s:iterator>标签

<s:iterator value="" id="" status="">
		<s:property value=""/>
</s:iterator>

1.value属性:可选的属性,value属性是指一个被迭代的集合,使用ognl表达式指定,如果为空的话默认就是ValueStack栈顶的集合

2.id属性:可选属性, 是指集合元素的id

3.status属性:可选属性,该属性在迭代时会产生一个IteratorStatus对象,该对象可以判断当前元素的位置,包含了以下属性方法

int getCount(); 迭代元素个数
int getIndex(); 迭代元素当前索引
boolean isFirst(); 是否为第一个
boolean isEven(); 是否为偶
boolean isLast(); 是否最后一个
bolean isOdd(); 是否为奇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值