一、OGNL表达式学习
1.OGNL表达式语言
访问上下文(Context)中的对象需要使用#符号标注命名空间,如#appaication、#session
OGNL会设定一个根对象(root对象),在Struts2中根对象就是ValueStack(值栈)。若要访问根对象中对象的属性,则可以省略#命名空间,直接访问该对象的属性即可。
在Struts2中,根对象ValueStack的实现类为
OgnlValueStack,该对象不是我们想象的只存放单个值,而是存放一组对象。在
OgnlValueStack类中有一个List类型的root变量,就是使用它来存放一组对象。
|--request
|--application
context------|--
OgnlValueStack
root变量[action,OgnlUtil,....]
|--session
|--attr
|--parameters
在root变量中处于第一位的对象叫栈顶对象,通常在OGNL表达式里直接写上属性的名称即可访问root变量里对象的属性,搜索顺序是从栈顶对象开始寻找,若栈顶对象不存在该属性,就会从第二个对象寻找,若没有找到就从第三个对象寻找,依次往下访问,知道找到为止。
需注意:在Struts2中,OGNL表达式需要配合Struts标签才可使用。<s:property value="name"/>
由于ValueStack是Struts2中OGNL的根对象,若用户需要访问值栈中的对象,在JSP页面可以直接通过下面的EL表达式访问值栈中对象的属性:
${foo} //获得值栈中某个对象的foo属性
若访问其他Context中的对象,由于他们不是根对象,所以在访问时,需要添加#前缀。
application对象:用来访问ServletContext,例如#application.username或者#application['username'],相当于调用ServletContext的getAttribute("
username");
session对象:用来访问HttpSession,例如#session.username或者#session['username'],相当于调用session.getAttribute("username");
request对象:用来访问HttpServletRequest属性(attribute)的Map,例如#request
.username或者#request
['username
'],相当于调用request
.
getAttribute("username");
parameters对象:用来访问HTTP的请求参数,例如#parameters
.username或者#parameters
['username
'],相当于调用request
.
getParameter("username");
attr对象:用于按page→request→session→application顺序访问其属性。
为何使用EL表达式能够访问值栈中对象的属性?
原因是Struts2对HttpServletRequest作了进一步的封装。
public class StrutsRequestWrapper extends HttpServletRequestWrapper {
public StrutsRequestWrapper(HttpServletRequest request) {
super(request);
}
public Object getAttribute(String s){
...
ActionContext ctx = ActionContext.getContext();
Object attribute = super.getAttribute(s);//先从request范围获取属性值
if(ctx!=null){
if(attribute == null){//如果从request范围没有找到属性值,就从值栈中查找对象的属性值
....
ValueStack vs = ctx.getValueStack();
attribute = vs.findValue(s);
...
}
}
return attribute;
}
}
二、OGNL表达式学习
三、OGNL表达式学习
ognl所需jar包为ognl-3.0.jar和javassist-3.7.jar
1.OgnlContext 上下文对象,实现了Map接口,是一个map对象。存在唯一的叫做根的对象(root),可以通过程序设定上下文中的那个对象作为根对象。
2.在OGNL中,如果表达式没有使用#号,那么OGNL会从根对象中寻找该属性对应的get方法,如果寻找的不是根对象中的属性,则需要以#号开头,找到对应对象的属性。
3.当使用OGNL调用静态方法或者静态属性时,需要按照如下方法编写表达式@package.calssname@methodname(parameter)或者
@package.calssname@attributename
,其中Math类的调用比较特殊,只需要
@@methodname(parameter)
4.数组和集合是一样的,都是通过下标来访问。
5.使用OGNL处理映射(Map)的语法格式为:#{'key1':'value1'
'key2':'value2'...};
6.过滤(filtering
类比数据库中的表,
针对行记录):collection.{? expression},符合表达式expression的集合
collection,获取集合中符合条件的第一个元素的方式也可以是
collection.{^ expression},
获取集合中符合条件的最后一个元素的方式也可以是
collection.{$ expression}.
7.在使用过滤操作时,我们通常会使用#this,该表达式用于代表当前正在迭代的集合中的对象。
8.OGNL针对集合提供了一些伪属性(如size,isEmpty),让我们可以通过属性的方式来调用方法,也可以通过调用方法来实现相同的目的。
9.投影(projection 类比数据库中的表,针对列记录):
collection.{expression},对集合进行表达式expression的操作后的集合
,获取集合中符合条件的第一个元素的方式也可以是
collection.{^ expression},
获取集合中符合条件的最后一个元素的方式也可以是
collection.{$ expression}.
示例:
Person类
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Dog类
public class Dog {
private String name;
private String[] friends;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String[] getFriends() {
return friends;
}
public void setFriends(String[] friends) {
this.friends = friends;
}
}
测试类
import java.util.ArrayList;
import java.util.List;
import ognl.Ognl;
import ognl.OgnlContext;
public class OgnlTest {
public static void main(String[] args) throws Exception {
Person p = new Person();
p.setName("zhangsan");
Dog d = new Dog();
d.setName("wangcai");
d.setFriends(new String[]{"aa","bb","cc","dd"});
OgnlContext context = new OgnlContext();
context.put("p", p);
context.put("d", d);
context.setRoot(p);
//ognl 解析表达式
Object obj1 = Ognl.parseExpression("name");
System.out.println(obj1);
Object obj2 = Ognl.getValue(obj1, context, context.getRoot());
System.out.println(obj2);
System.out.println("================");
Object obj3 = Ognl.parseExpression("#p.name");
System.out.println(obj3);
Object obj4 = Ognl.getValue(obj3, context, context.getRoot());
System.out.println(obj4);
System.out.println("================");
Object obj5 = Ognl.parseExpression("#d.name");
System.out.println(obj5);
Object obj6 = Ognl.getValue(obj5, context, context.getRoot());
System.out.println(obj6);
System.out.println("================");
//调用方法
Object obj7 = Ognl.parseExpression("name.toUpperCase()");
System.out.println(obj7);
Object obj8 = Ognl.getValue(obj7, context, context.getRoot());
System.out.println(obj8);
System.out.println("================");
//调用某个类的静态方法并传递参数
Object obj9 = Ognl.parseExpression("@java.lang.Integer@toBinaryString(10)");
System.out.println(obj9);
Object obj10 = Ognl.getValue(obj9, context, context.getRoot());
System.out.println(obj10);
System.out.println("================");
//特殊类调用的静态方法并传递参数
Object obj11 = Ognl.parseExpression("@@min(4,10)");
System.out.println(obj11);
Object obj12 = Ognl.getValue(obj11, context, context.getRoot());
System.out.println(obj12);
System.out.println("================");
//创建对象
Object obj13 = Ognl.parseExpression("new java.util.LinkedList()");
System.out.println(obj13);
Object obj14 = Ognl.getValue(obj13, context, context.getRoot());
System.out.println(obj14);
System.out.println("================");
Object obj15 = Ognl.parseExpression("{'aa','bb','cc'}");
System.out.println(obj15);
Object obj16 = Ognl.getValue(obj15, context, context.getRoot());
System.out.println(obj16);
System.out.println("================");
Object obj17 = Ognl.parseExpression("{'aa','bb','cc'}[2]");
System.out.println(obj17);
Object obj18 = Ognl.getValue(obj17, context, context.getRoot());
System.out.println(obj18);
System.out.println("================");
//访问数组
Object obj19 = Ognl.parseExpression("#d.friends");
System.out.println(obj19);
Object obj20 = Ognl.getValue(obj19, context, context.getRoot());
System.out.println(obj20);
System.out.println("================");
Object obj21 = Ognl.parseExpression("#d.friends[2]");
System.out.println(obj21);
Object obj22 = Ognl.getValue(obj21, context, context.getRoot());
System.out.println(obj22);
System.out.println("================");
//处理映射map
Object obj23 = Ognl.parseExpression("#{'key1':'value1','key2':'value2','key3':'value3','key4':'value4'}");
System.out.println(obj23);
Object obj24 = Ognl.getValue(obj23, context, context.getRoot());
System.out.println(obj24);
System.out.println("================");
Object obj25 = Ognl.parseExpression("#{'key1':'value1','key2':'value2','key3':'value3','key4':'value4'}['key3']");
System.out.println(obj25);
Object obj26 = Ognl.getValue(obj25, context, context.getRoot());
System.out.println(obj26);
System.out.println("================");
//上一个实例等价于这个实例
Object obj27 = Ognl.getValue("#{'key1':'value1','key2':'value2','key3':'value3','key4':'value4'}['key3']", context, context.getRoot());
System.out.println(obj27);
System.out.println("================");
List<Person> list = new ArrayList<Person>();
Person p1 = new Person();
p1.setName("zhan");
Person p2 = new Person();
p2.setName("zhangsan222");
Person p3 = new Person();
p3.setName("zhangsan333");
list.add(p1);
list.add(p2);
list.add(p3);
context.put("list", list);
//过滤
System.out.println(Ognl.getValue("#list.{? #this.name.length() > 4}", context, context.getRoot()));
System.out.println("================");
System.out.println(Ognl.getValue("#list.{? #this.name.length() > 4}.size()", context, context.getRoot()));
System.out.println("================");
System.out.println(Ognl.getValue("#list.{^ #this.name.length() > 4}[0].name", context, context.getRoot()));
System.out.println("================");
System.out.println(Ognl.getValue("#list.{$ #this.name.length() > 4}[0].name", context, context.getRoot()));
System.out.println("================");
//投影
System.out.println(Ognl.getValue("#list.{name}", context, context.getRoot()));
System.out.println("================");
System.out.println(Ognl.getValue("#list.{#this.name.length() > 4 ? #this.name : 'hello world'}", context, context.getRoot()));
}
}
输出的结果为:
name
zhangsan
================
#p.name
zhangsan
================
#d.name
wangcai
================
name.toUpperCase()
ZHANGSAN
================
@java.lang.Integer@toBinaryString(10)
1010
================
@java.lang.Math@min(4, 10)
4
================
new java.util.LinkedList()
[]
================
{ "aa", "bb", "cc" }
[aa, bb, cc]
================
{ "aa", "bb", "cc" }[2]
cc
================
#d.friends
[Ljava.lang.String;@3901c6
================
#d.friends[2]
cc
================
#{ "key1" : "value1", "key2" : "value2", "key3" : "value3", "key4" : "value4" }
{key1=value1, key2=value2, key3=value3, key4=value4}
================
#{ "key1" : "value1", "key2" : "value2", "key3" : "value3", "key4" : "value4" }["key3"]
value3
================
value3
================
[com.bj.study.ognl.Person@388993, com.bj.study.ognl.Person@1d04653]
================
2
================
zhangsan222
================
zhangsan333
================
[zhan, zhangsan222, zhangsan333]
================
[hello world, zhangsan222, zhangsan333]
四、OGNL在Struts2中的应用
1.值栈的概念 OgnlValueStack,是根对象,在Struts2的任何流程中,Val
ueStack中的最顶层对象一定是Action对象。
2.命名对象:在OGNL Context 中包含有值栈和命名对象,是并列关系;其中命名对象包含parameters、request、session、application和attr
3.访问静态方法或静态成员变量的改进:
@vs@method 表示访问值栈中的method静态方法
request:<s:property value="#request.hello"/>
session:<s:property value="#session.hello"/>
application:<s:property value="#application.hello"/>
--------------------------------<br>
request:<%=((Map)ActionContext.getContext().get("request")).get("hello") %><br>
session:<%=((Map)ActionContext.getContext().get("session")).get("hello") %><br>
application:<%=((Map)ActionContext.getContext().get("application")).get("hello") %><br>
-------------------------------<br/>
address:<s:property value="list[0].address" /><br>
age:<s:property value="list[1].age" /><br>
cat1:name:<s:property value="list[0].cat.name" /><br>
-------------------------------<br/>
address:<%=((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get("address") %><br>
age:<%=((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get("age") %><br>
cat1:name:<%=((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get("cat") %><br>
4.对于struts2标签中使用OGNL需要注意
%与#的关系:
a.如果标签的属性值是OGNL表达式,那么无需添加%{};eg:<s:property value="ognl表达式"/>
b.如果标签的属性值是字符串类型,那么在字符串当中凡是出现的%{}都会被解析成OGNL表达式,解析完毕后再与其他的字符串进行拼接造出最后的字符串。eg:<s:a hfef="....?id=%{ognl表达式}"
c.我们可以在所有的属性值上添加%{},这样如果该属性值是OGNL表达式,则标签处理类就会将%{}忽略掉。
该拦截器需要配置在所有拦截器后
wait页面需添加