ognl
ognl中有一个OgnlContext,它可以设置root与非root,root中获取数据时,不需要加#,而非root数据获取时需要加#号。
简单示例如下:
OgnlDemo1
package cn.itcast.ognl;
import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
public class OgnlDemo1 {
public static void main(String[] args) throws OgnlException {
// ognl可以通过对象调用方法
// System.out.println("aaa".length());
// 使用ognl来完成上面操作
// 1.创建一个ognl上下文
OgnlContext context = new OgnlContext();
Object obj1 = Ognl.getValue("'aaa'.length()", context.getRoot());
System.out.println(obj1);
}
}
OgnlDemo2
package cn.itcast.ognl;
import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
public class OgnlDemo2 {
public static void main(String[] args) throws OgnlException {
// ognl可以通过类调用静态方法
System.out.println(Math.max(10, 20));
System.out.println(Math.PI);
// 使用ognl来完成上面操作
// 1.创建一个ognl上下文
OgnlContext context = new OgnlContext();
Object obj1 = Ognl.getValue("@java.lang.Math@max(10,20)",
context.getRoot());
System.out.println(obj1);
Object obj2 = Ognl.getValue("@java.lang.Math@PI", context.getRoot());
System.out.println(obj2);
}
}
关于存取根与非根数据如下所示:
Person
package cn.itcast.ognl;
public class Person {
private String name;
private Dog dog;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
}
Dog
package cn.itcast.ognl;
public class Dog {
private String name;
private Person p;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getP() {
return p;
}
public void setP(Person p) {
this.p = p;
}
}
OgnlDemo3
package cn.itcast.ognl;
import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
public class OgnlDemo3 {
public static void main(String[] args) throws OgnlException {
// 创建一个ognl上下文
OgnlContext context = new OgnlContext();// 本质上是一个Map集合
Person p = new Person();
p.setName("张三");
Dog dog = new Dog();
dog.setName("lucy");
p.setDog(dog); // 张三有条狗叫lucy
context.setRoot(p);
Dog dog1 = new Dog();
dog1.setName("豆豆");
Person pp = new Person();
pp.setName("jams");
dog1.setP(pp);
context.put("dog", dog1);
context.put("name", "tom");
// 使用ognl来获取根中数据,不需要加#
Object name1 = Ognl.getValue("name", context, context.getRoot());
System.out.println(name1);
// 使用ognl来获取非根中的数据,获取非根中的数据 需要使用#
Object name2 = Ognl.getValue("#name", context, context.getRoot());
System.out.println(name2);
// 获取张三的狗的名称
Object name3 = Ognl.getValue("dog.name", context, context.getRoot());
System.out.println(name3);
// 获取豆豆的主人名称
Object name4 = Ognl.getValue("#dog.p.name", context, context.getRoot());
System.out.println(name4);
}
}
ognl介绍
ognl是Object Graphic Navigation Language(对象导航图语言)的缩写,它是一个开源项目。Struts2框架使用ognl作为默认的表达式语言。
ognl是一种比EL强大很多倍的语言。
ognl相对其它表达式语言具有下面五大优势:
1、支持对象方法调用,如xxx.doSomeSpecial();
2、支持类静态方法的调用和值访问,表达式的格式:@[类全名(包括包路径)]@[方法名| 值名],例如:@java.lang.String@format("foo %s","bar");或@tutorial.MyConstant@APP_NAME;
设置:struts.ognl.allowStaticMethodAccess=true;
3、访问ognl上下文(OGNL context)和ActionContext;(重点:操作valueStack值栈)
4、支持赋值操作和表达式串联,如price=100,discount=0.8,caculatePrice(),这个表达式会返回80;
5、操作集合对象。
示例:
<h1>实例方法调用</h1>
<s:property value="'abcdef'.length()"/>
<h2>静态方法调用</h2>
<s:property value="@java.lang.String@format('你好, %s','小明')"/>
<s:property value="'abcdef'.length()"/>
<h2>静态方法调用</h2>
<s:property value="@java.lang.String@format('你好, %s','小明')"/>
演示:在struts2中使用ognl表达式
需要结合struts2的标签使用<s:property value="ognl表达式">
<s:property value="'abc'.length()"/> 演示对象调用方法
<s:property value="@java.lang.Math@max(10,20)"/> 演示静态成员访问.
注意:在struts2中使用静态成员访问,必须设置一个常量:
struts.ognl.allowStaticMethodAccess=false
<s:property value="'abc'.length()"/> 演示对象调用方法
<s:property value="@java.lang.Math@max(10,20)"/> 演示静态成员访问.
注意:在struts2中使用静态成员访问,必须设置一个常量:
struts.ognl.allowStaticMethodAccess=false
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>演示:使用ognl来通过对象调用方法</title>
</head>
<body>
<s:property value="'abc'.length()" />
<hr>
<s:property value="@java.lang.Math@max(10,20)" />
</body>
</html>
Struts2中的valueStack
valueStack概述:
ValueStack实际上是一个接口com.opensymphony.xwork2.util.ValueStack,在Struts2中利用ognl时,实际上使用的是实现了该接口的OgnlValueStack类,这个类是Struts2利用OGNL的基础
- ValueStack(值栈):贯穿Action的生命周期(每个Action类的对象实例都拥有一个ValueStack对象)相当于一个数据中的中转站.在其中保存当前Action对象和其他相关对象。
- Struts框架把ValueStack对象保存在名为"struts.valueStack"的请求属性中,request中。
在ValueStack对象内部有两个逻辑部分:
- ObjectStack:Struts把动作和相关对象压入ObjectStack中—(List)
- ContextMap:Struts把各种各样的映射关系(一些Map类型的对象)压入ContextMap中
Struts会把下面这些映射压入ContextMap中
- parameters:该Map中包含当前请求的请求参数
- request:该Map中包含当前request对象中的所有属性
- session:该Map中包含当前session对象中的所有属性
- application:该Map中包含当前application对象中的所有属性
- attr:该Map按如下顺序来检索某个属性:request、session、application
理解Struts2中的ValueStack
断点执行如下代码:
Object ctx=ServletActionContext.getRequest().getAttribute("struts.valueStack");
______________________________________________________________________________
理解OGNL Context
OGNL Context是Struts2的数据中心,结构示意图如下:
当Struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action,然后将action存放进ValueStack,所以action的实例变量可以被OGNL访问
注意:Struts2中,OGNL表达式需要配合Struts标签才可以使用,如:<s:property value="name" />
问题1:什么是ValueStack?
valueStack主要是将action数据携带到页面上,通过ognl获取数据
1、ValueStack有一个实现类叫OgnlValueStack。
2、每一个action都有一个ValueStack(一个请求,一个request,一个action,一个ValueStack)valueStack生命周期就是request生命周期。
3、valueStack中存储了当前action对象以及其它常用web对象(request,session,application,parameters)
4、Struts2框架将valueStack以"struts.valueStack"为名存储到request域中
ValueStack内部结构图如下:
问题2:valueStack结构?
ValueStack中存在root属性(CompoundRoot)、context属性(OgnlContext)
* CompoundRoot 就是ArrayList
* OgnlContext 就是Map
list 集合中存储的是action相关信息
map集合中存储的是相关映射信息,包含 parameters、request、session,application,attr等
想要从list中获取数据,可以不使用#号(它就是ognl的root)
如果从map中获取数据,需要使用#(其实在Struts2中的map—context其实就是OgnlContext)
结论:
ValueStack有两部分List Map
在Struts2中List就是root,Map就是OgnlContext
默认情况下,在Struts2中从ValueStack中获取数据从root中获取
问题3:值栈对象的创建,ValueStack和ActionContext是什么关系?
ActionContext ctx = ActionContext.getContext();
if (ctx != null) {
stack = ctx.getValueStack();
}
if (ctx != null) {
stack = ctx.getValueStack();
}
ValueStack是每一次请求时,都会创建
在ActionContext中持有了ValueStack的引用
ValueStack对象的创建过程
StrutsPrepareAndExecuteFilter
doFilter方法
prepare.createActionContext(request, response);
创建ActionContext和ValueStack
ctx = new ActionContext(stack.getContext());
ActionContext引用ValueStack对象
Dispatcher——serviceAction方法
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
将ValueStack对象 保存到request 范围
doFilter方法
prepare.createActionContext(request, response);
创建ActionContext和ValueStack
ctx = new ActionContext(stack.getContext());
ActionContext引用ValueStack对象
Dispatcher——serviceAction方法
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
将ValueStack对象 保存到request 范围
问题4:如何获得值栈对象?
对于ValueStack获取有两种方式:
1、通过request获取
ValueStack vs=(ValueStack)ServletActionContext.getRequest().getAttribute(ServletActionContext.STATUS_VALUESTACK_KEY);
2、通过ActionContext获取
ValueStack vs=ActionContext.getContext().getValueStack();
问题5:向值栈中保存数据(主要针对root)
主要有两个方法
push(Object obj)----->底层就是root.add(0,obj) 将数据存储到栈顶。
set(String name,Object obj)------->底层是将数据封装到HashMap中,在将这个HashMap通过push存储。
在JSP通过<s:debug />查看值栈内容
ActionContext提供了对ognl上下文对象中数据操作的方法
ServletActionContext.getRequest().setAttribute("username", "username_request");
ServletActionContext.getServletContext().setAttribute("username", "username_application");
ServletActionContext.getContext().getSession().put("username", "username_session");
// 获取值栈对象
ValueStack valueStack=ServletActionContext.getContext().getValueStack();
System.out.println("valueStack "+valueStack);
// 向值栈保存数据
valueStack.set("username", "username_valueStack");
valueStach.push("www.baidu.com");
ServletActionContext.getServletContext().setAttribute("username", "username_application");
ServletActionContext.getContext().getSession().put("username", "username_session");
// 获取值栈对象
ValueStack valueStack=ServletActionContext.getContext().getValueStack();
System.out.println("valueStack "+valueStack);
// 向值栈保存数据
valueStack.set("username", "username_valueStack");
valueStach.push("www.baidu.com");
问题6:如何在JSP中获取值栈的数据?
获取root中数据不需要#,而context中数据需要#
1、如果栈顶是一个Map集合,获取时,可以直接通过Map集合的key来获取value
<s:property value="username" />
2、如果栈顶数据不是一个Map,没有key值,可以通过序号来获取
<s:property value="[0]"> 从0的位置向下查找所有
<s:property value="[0].top"> 只查找0位置上数据(栈顶数据)
3、获取OgnlContext中的数据
request:<s:property value="#request.username"/>
session:<s:property value="#session.username"/>
application:<s:property value="#application.username"/>
attr:<s:property value="#attr.username"/>
parameters:<s:property value="#pa
session:<s:property value="#session.username"/>
application:<s:property value="#application.username"/>
attr:<s:property value="#attr.username"/>
parameters:<s:property value="#pa