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表达式
分享结束~~~~~~~~~~~~~~~~~~···