OGNL表达式

1.OGNL简介

OGNL(ObjectGraphic Navigation Language)对象图导航语言,它是一个开源项目。
Struts2框架使用OGNL作为默认的表达式语言,大大加强了数据访问功能。

OGNL表达式与EL表达式有很多相似的地方,也有不同的地方。

相同点:
获取域对象(page,request,session,application)的数据。

不同点:
EL表达式不能存放数据(可以),不能调用方法(可以)。
OGNL表达式可以存放数据,可以调用方法。

OGNL有一个上下文(Context)概念,说白了上下文就是一个Map结构,它实现了java.utils.Map接口,在Struts2中上下文实现为ActionContext。
在这里插入图片描述

OGNL优势:
(1)支持对象方法调用,如xxx.sayHello();
(2)支持类静态方法调用和值访问,表达式的格式为:
@[类全名(包路径)]@[方法名|值名]
例如:@java.lang.String@format(‘foo%s’, ‘bar’) 或 @cn.itcast.Constant@APP_NAME;
(3)支持赋值操作和表达式串联
如:price=100, discount=0.8,calculatePrice()这个表达式会返回80。
(4)操作集合对象。
(5)访问OGNL上下文(OGNL context)和ActionContext。

2.值栈 ValueStack

在Servlet中使用域对象(page、request、session、application)进行存值和取值,将其作为载体来承载页面和后台之间的数据传递。
在Struts2中,又有了一种新的机制来进行数据的传递,那就是ValueStack,即值栈。

在理解ValueStack之前我们先要了解一下Servlet和Action的区别。

Servlet和Action的区别
Servlet:单对象(单例模式)
默认在第一次访问时创建对象,但它只会创建一次对象,无论后面访问多少次这个Servlet,都只有一开始创建的那一个Servlet对象。
/DemoServlet.do

Action:多对象(多例)
默认在第一次访问时创建对象,但每一次访问它的时候,都会创建一个新对象。
/DemoAction.action

什么是值栈
值栈(ValueStack)是一种类似于域对象的,用来存值和取值,在页面和后台之间传递数据的功能。
在Action中将数据存入值栈,然后在页面中通过EL表达式或者OGNL表达式将值取出。

值栈存储的位置
值栈和Action的关系是:
值栈存在于Action对象中。
每创建一个Action对象,就会创建一个值栈对象。且每个Action对象中只有一个值栈对象。

在这里插入图片描述

在Action中获取值栈对象
获取值栈对象的方法很多,最常用的是使用ActionContext类来获取:

ActionContext context = ActionContext.getContext();
// 获得值栈对象
ValueStack stack = context.getValueStack();

值栈本质上是一种栈类型的数据结构,如图所示:

在这里插入图片描述
栈中数据遵循后进先出的原则,在线最上面的元素叫做栈顶元素,新的数据存储进来的时候会压在原有数据的上面,这个操作被称为压栈。

值栈的内部结构
值栈分为两个部分:root和context
root部分是List结构;context部分是Map结构。
存值和取值一般都是操作root部分的数据,而context部分存储的是一些对象的引用。

测试:

在ValueStack vs = ServletActionContext.getContext().getValueStack();处设置断点测试,运行看结果:stack1,里面有root和context。

获取值栈中push方法存入的值
push()压栈方式向值栈存值,使用的不是Map结构,没有Key我们如何取值?
Struts2中将push()方法存入值栈的值,都放在一个名为top的集合中,我们利用这个集合便可获取到其中的值。

基本操作步骤

导入OGNL的jar包:ognl-3.0.6.jar,Struts核心包自带
Struts2的标签库:
<%@ taglib prefix=“s” uri = “/struts-tags” %>
使用Struts2的标签:OGNL与Struts2中的<s:property>标签配合使用。

//可以调方法,测试字符串'haha'的长度
<s:property value=" 'haha'.length() " />	

//1.首先从request域获取值,如果获取到,直接返回
//2.如果从request域获取不到值,到值栈中把值获取出来,把值放到域对象里面

OnglExpression 核心类:


package com.xzy.test;

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

/**
 * 用于OGNL表达计算的一个工具类
 * 
 */
public class OnglExpression {
	private OnglExpression() {
	}

	/**
	 * 根据OGNL表达式进行取值操作
	 * 
	 * @param expression
	 *            ognl表达式
	 * @param ctx
	 *            ognl上下文
	 * @param rootObject
	 *            ognl根对象
	 * @return
	 */
	public static Object getValue(String expression, OgnlContext ctx,
			Object rootObject) {
		try {
			return Ognl.getValue(expression, ctx, rootObject);
		} catch (OgnlException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 根据OGNL表达式进行赋值操作
	 * 
	 * @param expression
	 *            ognl表达式
	 * @param ctx
	 *            ognl上下文
	 * @param rootObject
	 *            ognl根对象
	 * @param value
	 *            值对象
	 */
	public static void setValue(String expression, OgnlContext ctx,
			Object rootObject, Object value) {
		try {
			Ognl.setValue(expression, ctx, rootObject, value);
		} catch (OgnlException e) {
			throw new RuntimeException(e);
		}
	}
}

Demo1:

package com.xzy.test;

import ognl.OgnlContext;
import ognl.OgnlException;

public class Demo1 {

	/**
	 * @param args
	 * @throws OgnlException
	 */
	public static void main(String[] args)  {
		Employee e = new Employee();
		e.setName("小李");

		Manager m = new Manager();
		m.setName("张经理");

		// 创建OGNL下文,而OGNL上下文实际上就是一个Map对象
		OgnlContext ctx = new OgnlContext();

		// 将员工和经理放到OGNL上下文当中去
		ctx.put("employee", e);
		ctx.put("manager", m);
		ctx.setRoot(e);// 设置OGNL上下文的根对象

		/** ********************** 取值操作 *************************** */
		// 表达式name将执行e.getName(),因为e对象是根对象(请注意根对象和非根对象表达式的区别)
		String employeeName = (String) OnglExpression.getValue("name", ctx, e);
		System.out.println(employeeName);

		// 表达式#manager.name将执行m.getName(),注意:如果访问的不是根对象那么必须在前面加上一个名称空间,例如:#manager.name
		String managerName = (String) OnglExpression.getValue("#manager.name",
				ctx, e);
		System.out.println(managerName);

		// 当然根对象也可以使用#employee.name表达式进行访问
		employeeName = (String) OnglExpression.getValue("#employee.name", ctx,
				e);
		System.out.println(employeeName);

		/** ********************** 赋值操作 *************************** */
		OnglExpression.setValue("name", ctx, e, "小明");
		employeeName = (String) OnglExpression.getValue("name", ctx, e);
		System.out.println(employeeName);

		OnglExpression.setValue("#manager.name", ctx, e, "孙经理");
		managerName = (String) OnglExpression.getValue("#manager.name", ctx, e);
		System.out.println(managerName);

		OnglExpression.setValue("#employee.name", ctx, e, "小芳");
		employeeName = (String) OnglExpression.getValue("name", ctx, e);
		System.out.println(employeeName);
	}

}

Action:

package com.xzy.test;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.util.ValueStack;

public class DemoAction {
	public String test1() {
		ValueStack vs = ServletActionContext.getContext().getValueStack();
		vs.push(new Employee("张雇员", 2000));// 1
		vs.push(new Student("小明同学", "s001"));// 0
		System.out.println(vs.findValue("name")); //小明同学
		System.out.println(vs.findValue("salary")); //2000

		return "rs";
	}
	
	
	
}

在这里插入图片描述
使用 # 来获取Action值栈中Context部分中的数据,相当于ActionContext.getContext();

#、%、$三个符号的主要用途

# 的用法
使用 # 来获取Action值栈中Context部分中的数据,相当于ActionContext.getContext();
那么Context也分了几个区域,如:Context的根值、parameters、request、session、application、attr,
如何获得这几个区域的值?

1、

// 获得ActionContext根下user对象的username属性值
<s:property value="#user.username" />
// 获得parameters区域中的id,相当于request.getParameter(“id”)
<s:property value="#parameters.id[0]" />
// 获得request区域中的password,相当于request.getAttribute(“password”)
<s:property value="#request.password" />
// 获得session区域中的password,相当于session.getAttribute(“password”)
<s:property value="#session.password" />
// 获得application区域中的password,相当于application.getAttribute(“password”)
<s:property value="#application.password" />
// 获得request、session、application区域中的password
<s:property value="#attr.password" />

2、用于过滤和投影(projecting)集合,如books.{?#this.price<100};
3、构造Map,如#{‘foo1’:’bar1’, ‘foo2’:’bar2’}。

“%”符号
%符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值,类似js中的eval

	<h3>%的用途</h3> 
    <p><s:url value="#foobar['foo1']" /></p> 
    <p><s:url value="%{#foobar['foo1']}" /></p> 

”$”的用法
  1、用于在国际化资源文件中,引用OGNL表达式
  2、在Struts 2配置文件中,引用OGNL表达式

分享结束~~~~~~~~~~~~~~~~~~···

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值