Struts2中的OGNL表达式

值栈

<li>ValueStack对象相当于一个栈,它贯穿整个Action的生命周期,每个Action类的对象实例都会拥有一个ValueStack对象。当Struts2接收到一个*.action请求后,并不是直接调用Action方法,而是先将Action类的相应属性放到ValueStack对象的顶层节点
值栈也位于内存中,它也是和parameters、request、session、application、attr对象放在一起的。值栈属于ONGL Context里面的根对象。也就是说它位于整个内存中最最重要的地方,所以叫根对象。根对象和另外五个对象是有区别的,根对象可以省写#号,比如<s:property value="user.username"/>。值栈的生命周期与request请求相关,每次请求产生一个值栈。默认所有的Action会被自动放到值栈里。

服务器跳转时共用值栈

假设从一个Action11通过服务器跳转到Action22的话,就意味着这两个Action是共享一个值栈的,因为一次请求只使用一个值栈。这时内存中情况是这样的:首先接收到Action11请求后,会产生一个值栈,在栈顶存放Action11对象以及它所有的属性。然后经过服务器跳转到Action22,这时就会把Action22对象压入值栈的栈顶位置,此时Action11对象以及它的所有属性就位于栈底了。

取值过程

栈的特征是后进先出。于是首先到栈顶的对象里查找是否存在这个属性,如果栈顶的Action22对象中不存在这个属性的话
它就会继续向下寻找直至栈底对象,一直查找是否存在这个属性
如果最后找到该属性的话,那么就会在JSP页面中通过<s:property value="username"/>输出属性值
如果在Action22和Action11都有一个同名的同类型的username属性的话,那么将输出Action22中的属性值
因为它是先从栈顶开始寻找属性的,值栈的特征就是后进先出,但有个前提:请求过程是通过服务器跳转的

三个语法

假设此时想要获取Action11中的username属性的话,就可以使用值栈的Top语法或者N语法
<li>使用Top语法获取值栈中的第二个对象的属性:<s:property value="[1].top.username"/>
<li>使用 N 语法获取值栈中的第二个对象的属性:<s:property value="[1].username"/>
<li>使用@语法调用Action中的静态方法:<s:property value="@vs@getVOMethod()"/>
@vs@get()等价于@vs1@getVOMethod(),指的是栈顶对象的静态getVOMethod()方法
同理@vs2@getVOMethod()就是取值栈中第二个对象的静态getVOMethod()方法

客户端跳转时使用各自的值栈

假如中间某一个步骤中出现了客户端跳转的话,那么两个Action所使用的就是两个不同的值栈了。所以在Action22中就不能再使用Action11中的属性了,在最后跳转到的JSP页面中也就无法获取Action11的属性了。也即从Action22跳转到JSP页面时使用的是redirect的话,那么最后值栈中是没有任何的Action对象的。这个时候我们可以通过链接传参,比如<result type="redirect">test.jsp?netname=${username}</result>,意思就是取出Action22中的username属性作为参数,通过浏览器地址栏传递到JSP页面中然后使用OGNL中的#号获取Paraments对象的属性,即<s:property value="#parameters.netname"/>就可以取到值了。

手工向值栈中压入对象

正常情况下值栈保存的是Action对象,而我们也可以直接往值栈中添加其它对象,这时可以在Action中添加如下代码
向值栈中添加对象:

ActionContext.getContext.getValueStack().push(new Student("沈浪",22));

而且我们手工往值栈中添加的Student对象会位于栈顶。这是因为Struts2会首先初始化Action,然后才能调用它的方法。初始化Action的时候,便把Action放到值栈中了,然后在执行它的execute()方法时,就又往值栈中添加了Student对象。


OGNL

OGNL是Object-Graph Navigation Language的缩写,是一种功能强大的表达式语言。通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。OGNL用得最多的地方就是和Struts2的标签绑定,也可以在配置文件中通过${}使用OGNL表达式

OGNL中$号的使用

1.在国际化资源文件中,引用OGNL表达式
2.在struts.xml文件中,引用OGNL表达式

OGNL中%号的使用

1.使用%{}可以取出保存在值堆栈中的Action对象,直接调用它的方法
2.如果Action继承了ActionSupport,那么在页面标签中可以使用%{getText('key')}获取国际化信息

OGNL中#号的使用

OGNL中的#号可以取出堆栈上下文中存放的对象

|名称|作用|例子|
|---|---|---|
|attr|用于按request>>session>>application顺序访问其属性|#attr.userName相当于按顺序从三个范围读取userName属性直到找到为止|
|request|包含当前HttpServletRequest的属性的Map|#request.userName相当于request.getAttribute("userName")|
|session|包含当前HttpSession的属性的Map|#session.userName相当于session.getAttribute("userName")|
|application|包含当前应用的ServletContext的属性的Map|#application.userName相当于application.getAttribute("userName")|
|parameters|包含当前HTTP请求参数的Map|#parameters.id[0]相当于request.getParameter("id")|

获取Action中的属性值或者Action中的对象的某某属性值

利用<s:property/>标签可以直接获取Action中的引用类型user里面的username属性,同样可以通过user.address.addr获取user中引用类型address中的addr属性的值,像这种一层一层往下传递的访问方式,即所谓的导航,也就是一步步的往下调用。

调用Action的对象里面的普通方法

默认的会把Action放到值栈里面,而值栈在访问的时候,并不需要值栈的名字。当我们调用

<s:property value="user.getVOMethod()"/>

的时候,它会自动到值栈里面查找Action对象里面有没有user对象,然后它就发现有user,然后它就再找user里面有没有getVOMethod()方法,然后它发现有,于是调用getVOMethod().实际上调用User中的getVOMethod()方法的过程与获取表单中的姓名密码的方式都是相同的,都是到值栈里面查找,找是否存在user对象,如果存在,接着查找user中是否存在某某属性或方法.

调用Action中的静态方法

同样我们也可以在JSP页面中写一个OGNL表达式调用Action中的静态方法。调用Action中的静态方法时,与调用user对象的getVOMethod()方法的过程,是截然不同的。此时value的写法是固定的,以@开头,后面跟上具体的包名,然后@加上静态方法
比如

<s:property value="@com.jadyer.action.LoginAction@getStatic()"/>

另外user对象是LoginAction中的一个属性,这个属性会自动的放到值栈里面,而值栈调用的时候,不用加上@或者包名等等,所以直接user.getVOMethod()就可以了。

调用JDK类中的静态方法

可以使用<s:property value="@@floor(46.58)"/>输出floor()的执行结果这就意味着如果不在@@中指定类的话,默认的就表示Java.lang.Math类当前大多数情况下,我们都不会省略这个类,都会写全了的,然后在后面加上静态方法。

集合的伪属性

OGNL能够引用集合的一些特殊的属性,这些属性并不是JavaBean模式,例如size()、length()。当表达式引用这些属性时,OGNL会调用相应的方法,这就是伪属性。
比如获取List的大小:

<s:property value="testList.size"/>

List的伪属性:size、isEmpty、iterator
Set的伪属性:size、isEmpty、iterator
Map的伪属性:size、isEmpty、keys、values
terator的伪属性:next、hasNext
Enumeration伪属性:next、hasNext、nextElement、hasMoreElements

获取集合中元素的实质就是调用它的toString()方法

它还可以直接获取集合中的元素,事实上是在调用集合的toString()方法,所以我们可以根据实际情况通过重写集合的toString()方法来实现个性化输出,甚至它还可以像访问数组那样,直接testList[2]获取集合中的元素,但这种方法只适用于List,不适用于Map。因为Map的索引是key,不是数值.另外,由于HashSet中的元素是没有顺序的,所以也不能用下标获取单个元素.

Lambda表达式

补充一下:使用Lambda表达式可以在OGNL中书写递归式子,在帮助中对它有很详细的说明
打开帮助中的//struts-2.0.14-all//struts-2.0.14//docs//index.html页面
在左侧的Documentation下面点击Guides链接,然后在这个页面中点击OGNL,最后跳转到//struts-2.0.14-all//struts-2.0.14//docs//docs//ognl.html将这个页面右侧的下拉条拖放到最下面,就会看到它的说明了,它举的例子如下所示.

<s:property value="#fib =:[#this==0 ? 0 : #this==1 ? 1 : #fib(#this-2)+#fib(#this-1)], #fib(11)" />

Lambda表达式的语法是:[...] ,中括号前面有一个冒号,所有东西都在中括号里面写,也就是说我们只要看到一个冒号跟着一个中括号,就表示这里使用的是Lambda表达式,#this指的是表达式的参数,所以这个例子可以这样理解:先判断这个参数是否等于零,如果等于零,那么它的值最后就是零.如果参数不等于零,就再判断它是否等于壹。如果参数等于壹,那么它的值最后就是壹.如果参数不等于壹,就继续调用#fib。注意这里已经用中括号将整体的值赋给了fib.实际上很少能够用得到Lambda表达式.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,376评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,126评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,966评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,432评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,519评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,792评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,933评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,701评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,143评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,488评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,626评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,292评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,896评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,324评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,494评论 2 348

推荐阅读更多精彩内容

  • 利用投影获取属性 利用投影获取List中对象的username属性时,其中{}表示的是一个集合.stus.{use...
    FTOLsXD阅读 190评论 0 1
  • 概述 什么是Struts2的框架Struts2是Struts1的下一代产品,是在 struts1和WebWork的...
    inke阅读 2,247评论 0 50
  • OGNL是一种表达式语言,可以存取对象的属性或者调用对象的方法,能够遍历整个对象的结构图,实现对象属性类型的转换等...
    yjaal阅读 5,928评论 0 9
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • 接下来必须改变的东西。 思维——思维太过于局限了,接下来,必须让其开阔,看每一件事物的时候不能仅仅去看表面,应该挖...
    拾壹束花阅读 214评论 0 2