waitingfortime

导航

struts-——OGNL和VALUE STACK

当我们输入用户名并成功跳到登陆到系统的欢迎页面后,会得到登录时输入的用户名信息。

简要的说明这一过程:
(1)login.jsp登录提交登录信息给login.action
(2)struts2监听到客户端的login.action请求,按配置文件要求,把此请求交给LoginAction处理。这表示会去new LoginAction(), 当struts2  new出此Action对象后会把这个对象放在context map中,只是这个Action非常特殊,所以放在值栈中,而放在值栈中的对象是可以直接引用的,放在其它context map中的对象引用时会要求加#。
(3)当new LoginAction时,表示它也会初始化此类中的对象,比如这里可能会去初始化User对象,但是要注意的是如果我们在用户名和密码什么都不输,再来用debug来看值栈中的user是,发现它仍会new出此对象,因为尽管我们没有输入任何值,但是后台的set方法还是要被调用,所以会new出此对象,但是如果我们直接输入.../login.action时我们会发现跳转到loginSuc.jsp页面时,用debug来看值栈中此User user,发现它的值为null。
第二点要注意的是我们必须为User类提供默认的构造方法,否则将会出现如下错误: java.lang.InstantiationException: com.asm.vo.User

1.Action会在请求时被创建,且会把创建的对象放到值栈中。
2.Action中的对象字段只有在需要时才会以new 的形式初始化,而且这些对象字段必须提供默认的构造方法。
3.ValueStack对象贯穿整个Action的生命周期(每个Action类的对象实例会拥有一个ValueStack对象)。当Struts 2接收到一个action的请求后,会先建立Action类的对象实例,但并不会调用Action方法,而是先将Action类的相应属性放到ValueStack对象的顶层节点(vs对象相当于一个栈)。
补充:值栈(根)对象也可以直接使用EL表达式访问,比如这里可以直接通过${user.username}来获取username的值。

  我们知道el表达式只能访问四种scope范围内的对象,那为什么这里能访问到值栈对象呢?原因是struts2对HttpServletRequet进行了一次封装,封装的代码主要是重写了getAttribute方法,简述重写此方法的核心代码:首先在原始的HttpServletRequest对象中查找el表达式中的属性,如果找不到再通过ActionContext获取值栈对象,进而再从值栈对象中查找el表达式中要访问的属性。

1.N-top语法

当我们通过chain链访问时,值栈中可能有两个以上的Action对象,如果这些对象中存在相同的属性,N语法便能正确区分他们。通常,这些Action对象的入栈顺序是:先访问先入栈。
我们用<s:debug>调试会发现,值栈中有一个DefaultTextProvider对象(因为此Action继承自ActionSupport),它的作用是获取资源文件中的内容(其实本质是ActionSupport重写了getText()方法),这也就是在国际化问题中我们能直接调用它的getText()方法的原因。这个对象与action对像同时存在在VS中。使用<s:debug>还能把context map中的对象列出,真是一个很好用的工具。

 value="[n]"

该语句的语法为:从第n+1个对象开始取值直到栈底元素,若想取得第n+1个元素,则[n].top,实质是截栈的操作。

实例:

N语法[0]:<s:property value="[0]"/><br>
N语法[
1]:<s:property value="[1]"/><br>
N语法[
0].top:<s:property value="[0].top"/><br>
N语法[
1].top:<s:property value="[1].top"/><br>
N语法top:
<s:property value="top"/><br>
N语法取值:
<s:property value="[0].user.username"/><br>
N语法取值:
<s:property value="top.user.username"/><br>

2.OGNL

由上一段的内容我们知道,当到达视图层时,action对象是保存在value stack中的。

利用%{}可以取出action对象,并且可以直接调用它的非静态方法。

例如:

IN ACTION

doSth(){
return "do something you like";
}

IN JSP
<s:property value="%{doSth()}">

we will see in jsp
do something you like

特殊的情况,若在action中有个方法以get开头,就像get/set方法那样,例如

IN ACTION
getSth(){
return "get something from here";

}

在VS中会有一个属性Sth,它的值为get somethig from here,虽然Sth并未定义在action的成员变量中。这时我们在jsp中可以直接

IN JSP
<s:property value="Sth">

也可以在页面上打印出这句话。

3.OGNL的集合操作

List

<s:property value="myList">

会将myList中的值依次打印出来,并放置在[]中。

[value1,value2……]

获得第一个元素  value="myList[0]"

这时打印value1不会放置在[]中。

Set

<s:property value="mySet">

打印的方式与list形式相同,都是放置在[]中,但是set类型的不能使用类似set[0]这样的表达式。

Map

<s:property value="myMap">

打印方式为{},并且key=value展示。

value="myMap.keys"  value="myMap.values"可以分别获得map的key和value,展示方式和list一样。

value="myMap.key1"  or value="myMap['key1']" 可以获得key为key1的value

4.OGNL的集合对象操作

以list为例,其他结构都是引申至list

myList中放置的对象为people,people有2个属性name(String),age(Int)。

   value="myList.{name}"  将所有people对象的name属性以list的方式展示。

获得第一个people的值

   value="myList.{name}[0]"  显示jack

   value="myList[0].{name}" 显示[jack]

实质上第二种方式处理name时还是以list的形式处理的。

筛选结果集

  value="myList.{?#this.age>60}"    选择出年龄大于60岁的对象

  value="myList.{?#this.age>60}.{name}"    

  value="myList.{?#this.age>60}[0].{name}"

  value="myList.{?#this.age>60}.{name}[0]"

  value="myList.{^#this.age>60}"   选择出年龄大于60岁的第一个对象,但这里的表现方式仍然是list的形式

  value="myList.{$#this.age>60}"   选择出年龄大于60岁的最后一个对象,但仍然是list的形式

5.访问其他scope中的元素

value="#request.req"

value="#session.sess"

jsp中若有这样的语句

<input type="hiden" name="mes" value="i am here">

可以使用

value="#parameters.mes"获得这个值

6.$%#的区别

$多用于配置文件中

%可将非OGNL文本解析为OGNL文本

#可访问在context map中的内容

7.ognl和el的区别

OGNL实现了许多EL没有的功能,支持对象方法调用,支持静态方法调用和值访问,支持操作集合对象,OGNL有一个上下文的概念,实质为一个map,在struts2中实现为actionContext,actionContext的根对像即为value stack。

posted on 2011-03-30 22:38  waitingfortime  阅读(657)  评论(1编辑  收藏  举报