Struts2 & OGNL

Struts2中的OGNL

在Struts2中有一个称之为值栈的概念(ValueStack),如图:

我们可以将多个bean压到ValueStack(具有后进先出的栈的特性),并且可以使用EL表达式对栈中的每一个bean进行计算。当你计算的时候,程序会从上到下一直进行搜索。它会查看你所需要查找的属性,在栈中的各个对象中有没有对应的setter;或者你调用某一个方法的时候,它就会查看那里一个bean(栈中的)具有该方法,通过方法名进行匹配。到底是寻找属性还是方法,是根据你使用的表达式来进行区别的。
而程序真正使用的是下面这个实例:

它实现了上面的接口。
如何比较呢?在栈中。


值栈中存放的对象类型可能一样或者不一样,都行。假如我们需要获取到name属性的值。程序将返回第一个匹配的值。通过getter & setter进行读取。

但是如果我们想要访问dog的name呢(在上图的第二位)?
Struts2对其进行了增强,提供了一个[N]语法(N表示一个数字),我们可以通过[N]获取到整个值栈的部分栈。
比如说,我们写[0],则表示返回整个栈。如果我们写[1],它就返回值栈中从index为1开始的包含一下所有元素的一个子集/子栈。之后我们根据返回的这个子栈再去去dog.name就可以找到我们需要的内容了。
这就像是Java中的LinkedList中某一个元素存储了一个集合一样。
此外Struts2还提供了一个“Top”语法,当我们使用top属性的时候,就返回当前栈的第一个元素。
我们配合这个top就可以获取部分栈/子栈中的第一个元素:[1].top。
张龙:在Struts2中,根对象就是ValueStack。在Struts2的任何流程当中,ValueStack中的最顶层对象一定是Action对象。所以我们在使用struts标签库在页面中获取某一个属性的值的时候,它一定是先从Action中获取对应的属性的值。
(还有一种说法就是在我们使用OGNL表达式的#this变量一个集合的时候,这个#this代表的临时对象,它就位于Action上面。)
而这个值栈本身有可以容纳多个对象,这就是和原始的OGNL的不同。

Struts Ognl中的非根对象:
parameters,#parameters.username
request, #request.username
session, #session.username
application, #application.username
attr, #attr.username

访问OGNL上下文和Action上下文,#相当于ActionContext.getContext();下表有几个ActionContext中有用的属性:
名称 作用 例子
parameters 包含当前HTTP请求参数Map #parameters.id作用相当于request.getParameter("id")
request 包含当前HttpServletRequest的属性(attribute)Map #request.userName相当于request.getAttribute("userName")
session 包含当前HttpSession的属性(attribute)的Map #session.userName相当于session.getAttribute("userName")
application 包含当前应用的ServletContext的属性(attribute)的Map #application.userName相当于application.getAttribute("userName")
attr 用于按:当前页面>request > session > application顺序访问其属性(attribute) #attr.userName相当于按顺序在以上三个范围(scope)内读取userName属性,直到找到为止,找不到返回''空字符串。
以上几个对象叫做“命名对象”。也就是Struts中的ognl的非根对象。
ValueStack与命名对象的关系图示:

这就像一个LinkedList中存放了多个对象,但是值栈本身由是一个数字或者集合。
访问静态方法或是静态成员变量的改进。
@vs@method 表示从值栈中获取静态静态方法或是静态成员变量。

如何访问ServletApi在一个Struts项目中:
1)org.apache.struts2
Class ServletActionContext
Web-specific context information for actions. This class subclasses ActionContext which provides access to things like the action name, value stack, etc. This class adds access to web objects like servlet parameters, request attributes and things like the HTTP session.
2)org.apache.struts2.interceptor
Interface RequestAware

public interface RequestAware
Actions that want access to the current serlvet request attributes should implement this interface.如果想要访问Servlet request属性中的Action就需要实现该接口。
This interface is only relevant if the Action is used in a servlet environment
这个接口中的方法是由一个默认连接器栈中的调用的,返回一个连接器处理类给我们的requst对象,所以在实现类中要有这个对象的setter。
这个requst对象就是最底层的Map形式的request对象。
注意这里的设置,设置的是底层对象的引用,所以我们对该值的修改,都会反映到整个程序对应的对象上。而且这种设置实在程序启动的时候就被框架注入到各个属性上面了。


因为在开启程序的时候,这个连接器中就持有了一个request对象,所以在调用该方法的时候,他就会将其设置到我们的属性中。
我们有了它(Map)就可以获取相应的客户传递过来的信息了。



其余几个命名对象也可以像这样拿到。

我们既可以从栈中中获取struts为我们提供的从用户端传递过来的信息,也可以使用#parameter访问相应的信息。


demo:我们向Action中的execute方法中往request/ session/ application中放置一些信息。在jsp页面中通过Ognl tags拿到相应的值。


那么它的底层是怎么做的呢?
底层用到了ActionContext对象,他就是Action所执行的一个上下文/环境,每一个Context就是一个对象的容器。线程本地。各个请求的ActionContext是互不干扰的。
实际上在JSP页面上面的表达式,是使用该类中定义的方法来去获取的。

而我们在页面中也可以使用get方法获取相应的命名对象中的属性值。param key 就是代表各个命名对象。但会一个Object对象。我们需要进行下行转换。
需要在页面中导入相应的包。
从上下文对象中获取相应的命名对象,接着获取其中的属性。

其中个Application是获取全局范围内的数据。以上就是标签库获取值的方式。attr用的极少。
demo:我们使用ognl访问Action中的集合对象List


底层的实现方式,还是在ActionContext中的方法入手,getValueStack,获取值栈。通过值栈中的方法来获取相应的值。我们就可以使用peek/ pop/ push等方法处理该栈中的元素。如果是查询的话使用的是peek方法,获取到的就是当前jsp在转到它之前那个Action。因为我们的Action始终处于栈顶。

导入相应的包,和Action的包。




还可以使用伪属性:"list.size"....

使用<s:iterator >完成循环过滤,使之遍历的是一个符合条件的子集,而每一次迭代是集合中的一个元素,我们就可以直接获取它里面的属性。
<s:property value="...">...

<s:iterator >中的属性标签获取的是每一个迭代的集合中的元素。
而且可以直接迭代Action中元素的属性值。

如果你迭代得来的就是简单书属性,直接就获取该属性的值就行了,而如果获取到的是一个集合,那么必须加“.”才能获取相应的属性值。
对于JSP页面中的ognl的 # 和 %
加 %是因为对应Struts2的标签来说,有些标签获取的值类型是Ognl表达式,比如说<s:property value="password">中的value=""值,框架会使用该标签对应的处理类,根据Ognl表达式的形式进行解析,password就会被当作ognl表达式来进行解析,但是<s:a href="">href=""中的值,框架会把其当作字符串来解析,这样的话我们在连接中包含动态的数据的话...
张龙:
关于Struts2标签库属性值的%与#号的关系:
1. 如果标签的属性值是OGNL表达式,那么无需加上%{}。
2. 如果标签的属性值是字符串类型,那么在字符串当中凡是出现的%{}都会被解析成OGNL表达式,解析完毕后再与其他的字符串进行拼接构造出最后的字符串值。
3. 我们可以在所有的属性值上加%{},这样如果该属性值是OGNL表达式,那么标签处理类就会将%{}忽略掉。

你可能感兴趣的:(struts2,Ognl)