struts2 ognl原理

Struts2内置了OGNL这是大家都知道的了,其实这种说话不严格,应该OGNL本身是一种很强大的表达式语言,XWork整合了OGNL的一部分并且将这部分内容做了相应的扩展,而Struts2又建立在XWork这个项目的基础之上,所以Struts2也就内置了OGNL这部分强大的功能。

为了详细些一步一步做记录吧。

先说OGNL,OGNL内部自己会维护一个OGNL上下文(OgnlContext)是一个实现了Map接口的对象,OGNL会将对象放在这个上下文中统一管理的,并且会有一个对象被指定为根对象(root)。假设有User和Customer这么两个类,分别有user和customer两个实例,这两个对象都有一个name属性,并且将user对象配置为唯一的根对象,那么就会有下面的情况:

#user.name 返回user.getName();

#customer.name 返回customer.getName();

#name 返回user.getName(); 因为user对象为根对象

OGNL访问对象的基本机制就是这样的。

在XWork中,ValueStack对象是上下文中的根对象,XWork中不仅可以根据表达式从ValueStack对象中获取对象,还可以获取对象的属性,XWork自己有一个强大的属性访问器,它可以自动搜索栈内的所有实体(从上到下),直到找到你所访问的对象和属性。假设ValueStack栈中有两个上面所说的user和customer两个对象,并且user是栈顶元素,customer在下面,就会有下面的情况:

name 返回user.getName(); 因为user在栈顶,搜索器找到一个匹配的属性就不会继续找下去

如果希望访问靠后对象的属性XWork提供了索引访问ValueStack的方法:

[0].name 返回user.getName()

[1].name 返回customer.getName();

了解上面这些之后Struts2中的OGNL就很好理解了,Struts2框架也没有对XWork中的OGNL做太大的修改,只是拿过来做了一下整合工作,Struts2将ActionContext设置为OGNL中的上下文,ValueStack依然是OGNL上下文中的根元素,大家知道application,session和request这几个对象也是在ActionContext中的,它们是和根对象ValueStack共存的,与根对象是无关的,就像刚开始说OGNL那个例子实在OGNL上下文中的两个平行对象,只不过ValueStack这个对象是这个OGNL上下文中的根对象(root)。如果要访问上下文中根对象中的对象和属性是不用加任何标记符号的,但是在访问application,session和request这几个范围内的对象和属性就要用"#"符号来告诉ognl不要在根对象中去搜索了,而是去我们指定的上下文中去找。用官方一个图来形象描述ValueStack和其他几个对象的关系:

|--request

|

|--application

|

context map |--OgnlValueStack(root)

|

|--session

|

|--attr

|

|--parameters

基本原理就是这样了,举例验证理论。

1. ActionContext是OGNL的上下文,ValueStack对象是上下文中的根对象:

随便找一个Action给JSP页面传东西过去的例子,然后在Action的execute()方法中加入以下代码:

ActionContext.getContext().getValueStack().set("test", "love java");

在目标JSP页面空白处加上如下代码:

<s:label value="%{test}"></s:label>

再次跳转到该页面就可以看到love java出现在页面上了

2. 其他范围和ValueStack平行关系:

还找刚才那个例子,在Action中加入

request.setAttribute("test1", "love java1");

在JSP页面加入代码:

<s:label value="%{#request.test1}"></s:label>

这次跳转就可以看到love java1出现了

3. OGNL上下文的访问

Action中加入代码:

ActionContext.getContext().put("test2", "love java2");

JSP页面中加入:

<s:label value="%{#test}"></s:label>

看到love java2之后应该大彻大悟了吧,这里值得说一下就是在ActionContext.getContext().put("test2", "love java2")之后上下文结构:

|--request

|

|--application

|

context map |--OgnlValueStack(root)

|

|--session

|

|--attr

|

|--parameters

|

|

|--test2


这样更清楚了吧!

总结:

1. 在JSP页面中"%{"就表示OGNL表达式开始,"}"表示OGNL表达式结束

2. 如果访问根对象中的对象和属性不用任何符号标志,如:%{Object.field}

3. 访问特定Scope中的对象和属性用"#"来通知OGNL查询器,如:%{#request.object},当然OGNL很强大,在一个链中,前一个对象做为解释下一个对象的上下文。你可以任意扩展这个链,在链中也可以访问对象中的方法。


_______________________

Struts2与OGNL


Struts 2支持以下几种表达式语言:
1. OGNL(Object-Graph Navigation Language),可以方便地操作对象属性的开源表达式语言;
2. JSTL(JSP Standard Tag Library),JSP 2.0集成的标准的表达式语言;
3. Groovy,基于Java平台的动态语言,它具有时下比较流行的动态语言(如Python、Ruby和Smarttalk等)的一些起特性;
4. Velocity,严格来说不是表达式语言,它是一种基于Java的模板匹配引擎,具说其性能要比JSP好。

Struts 2默认的表达式语言是OGNL,原因是它相对其它表达式语言具有下面几大优势:
1. 支持对象方法调用,如xxx.doSomeSpecial();
2. 支持类静态的方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名 | 值名],例如:@java.lang.String@format('foo %s', 'bar')或@tutorial.MyConstant@APP_NAME;
3. 支持赋值操作和表达式串联,如price=100, discount=0.8, calculatePrice(),这个表达式会返回80;
4. 访问OGNL上下文(OGNL context)和ActionContext;
5. 操作集合对象。

平时使用Struts2标签时会出现一些很奇特的问题,对于OGNL不了解的人可能对问题的出现无能为力或者就算解决了问题也不知道是如何解决的。下面总结一些使用Struts2标签容易出现的困惑:

问题一:#,%{},$符号

在Struts2标签属性中经常会出现"#"或者"%{}"的符号出现,通过上面OGNL表达式基础的介绍,知道了OGNL上下文中有且仅有一个根对象。Struts2为我们定义了许多明明对象,他们分别是"ValueStack","Parameters","Session","Request", "Appliction","Attr",其中"ValueStack"被设置为上下文的根对象。访问非根对象必须加上"#"号,这就是出现"#"的原因。Struts2中的标的处理类,并不是所有都将标签的属性作为OGNL表达式来看待,有时候我们需要设置动态地值,则必须告诉标签的处理类该字符串按照OGNL表达式来处理,%{}符号的作用就是告诉标签的处理类将它包含的字符串按照OGNL表达式处理。 "$"符号用于XML文件中用于获取动态值,与%{}作用类似。

问题二:%{}符号的影响

Struts2的标签几十几百个,要记住哪一个标签的处理类将标签的属性作为OGNL表达式是一件很困难的事情,在不清楚处理类的处理方式时怎么办,%{}对于标签处理类来说,若处理类将属性值作为普通字符串则%{}符号包含的字符串当做OGNL表达式,若处理类将属性值作为OGNL表达式来处理,则直接忽略%{}符号。换句话说,不清楚处理方式的话,可以都使用%{}符号。

问题三:标签是如何获得数据

下面是ValueStack的官方描述:

ValueStack allows multiple beans to be pushed in and dynamic EL expressions to be evaluated against it. When evaluating an expression, the stack will be searched down the stack, from the latest objects pushed in to the earliest, looking for a bean with a getter or setter for the given property or a method of the given name (depending on the expression being evaluated).

大致意思:ValueStack允许保存多个bean(也就是Action),并且可以使用表达式语言获得他们。当评估一个表达式,ValueStack将会从栈顶到栈底的方向被搜索一遍,对于给定的属性名称寻找bean的getter或setter方法或寻找给定的方法。

struts2 ognl原理

每当一个请求到达Action时,Struts2会将Action对象推入ValueStack中。

<body>   
    username:<s:property value="username"/><br />  
    -------------------诡异的分割线-------------------<br />  
    username:<%= ((HelloWorldAction)ActionContext.getContext().getValueStack().peek()).getUsername() %><br />  
  </body> 
页面显示结果:

username:zhangsan  
-------------------诡异的分割线-------------------  
username:zhangsan 

可以看到标签取值与用Java代码取值的结果相同,明显标签的取值方式更简练简洁。OGNL表达式"username"表示了从根对象ValueStack中取出属性username的值。它会从栈顶到栈底遍历ValueStack,直到找某一个Action中的"username"属性。


参考:

http://blog.csdn.net/csh624366188/article/details/7550606

你可能感兴趣的:(struts2)