Struts2 中 OGNL 如何更简单的访问静态变量和静态方法

发布时间:2016-12-6 18:12:19 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"Struts2 中 OGNL 如何更简单的访问静态变量和静态方法",主要涉及到Struts2 中 OGNL 如何更简单的访问静态变量和静态方法方面的内容,对于Struts2 中 OGNL 如何更简单的访问静态变量和静态方法感兴趣的同学可以参考一下。

在 struts2 标签中是使用 OGNL 来访问对象属性或方法的,也就是访问的 ValueStack 中的值,即 OgnlValueStack。OGNL 也能让你直接访问类的静态变量和静态方法,标准写法是: @[email protected],比如访问某个常量: <s:property value="@[email protected]_NAME"/> <s:property value="@cc.unmi.common.Utils.now()"/> 麻烦就是一定要写上类的全限定名称,实际应用时肯定比这个还要长,所以必须寻求一种更精练的写法。幸好像这篇文章:Struts2 OGNL 的增强 提到了可以用: 除了使用标准的OGNL表达式访问静态字段和静态方法外,Struts2还允许你不指定完整的类名,而是通过“vs”前缀来调用保存在栈中的静态字段和静态方法。 [email protected]@FOO_PROPERTY [email protected]@someMethod() [email protected]@someMethod() vs表示ValueStack,如果只有vs,那么将使用栈顶对象的类;如果在vs后面跟上一个数字,那么将使用栈中指定位置处的对象类。 看似确实很精简,实际上也是。但问题是我们该怎么把自己的常量或静态方法(应该是它们所在的类) 放到 ValueStack 上呢,并且是在栈里的哪个位置呢? OGNL 本身的规定是在它的上下文中只能有一个 root,然后 XWork/Struts2 对它衍生了,它认为在 ValueStack 中可以有多个根对象,对根对象的属性的访问可以不用 # 号。在 Struts2 的标签中对于是否该附上 # 号,也许很多人会有些迷糊。 比如对于一个简单的 Action 转向的 jsp 页面 index.jsp,在其中用 <s:debug/> 来查看一下 ValueStack: 上图中这两个对象 IndexAction 和 DefaultTextProvider 就是 ValueStack 的根对象,所以如果要访问 IndexAction 的 locale 属性就可以直接用 <s:property value="locale"/> 来访问,而不需要用井号(#) 的方式,像 <s:property value="#some.locale"/> 来访问的。但如果 ValueStack 中多个根对象含相同的属性名,Struts2 如何知道是取哪个根对象的相应属性呢?这也难不倒 Struts2 的,它用一个特殊的 OGNL PropertyAccessor,从栈顶的对象找下去,找到为止。 想像一下,对于 ModelDriven 的 Action,我们可以直接用 <s:property value="id"/> 访问到 Action 中 model 对象的 id 属性,就是因为 Struts2 把 Action 的 model 对象放到了 ValueStack 的根位置上了,并且处理 Action 实例的顶上。 明白了上面的原理之后,我们可以有两种方式在 Struts2 标签中用 @[email protected]_PROPERTY 的形式来访问静态变量或静态方法。 1)把常量和静态方法(非它们所在的类)声明在某个根对象中 比如,这里的 IndexAction, 我们在其中声明: 1 public static final String MY_NAME="Unmi come from IndexAction"; 本文原始链接:http://unmi.cc/struts2-ognl-access-static, 来自:隔叶黄莺 Unmi Blog 在 jsp 中用 <s:property value="@[email protected]_NAME"/> 就能够显示出它的值为: Unmi com from IndexAction。对于静态方法也是类似的。由上图得知,IndexAction 处在 ValueStack 的栈顶,由上往下,即位置为 1 (从零起),所以也可以用 <s:property value="@[email protected]_NAME"/> 我们也可以来看一下 ValueStack 中是什么样子的,用 <s:debug/> 显示出来是没有变化的,因为静态变量不会显示出来的。 该方法的实际应用,可以把静态变量或静态方法声明在 Action 类中,比如放在 BaseAction 中。或是能否寻找一种更巧妙的方式,在应用程序初始化时把某个 Constants 类中的常量或 Utils 中静态方法用 AOP 或字节码修改的方法插入到 BaseAction 中。这个方法此处不深究了。 2)把常量或静态方法所在类压入到 ValueStack 中直接作为根对象 比如,可以在这里的 IndexAction 的 execute() 方法,或初始方法中加上代码: 1 2 ValueStack vs = ActionContext.getContext().getValueStack(); vs.push(new cc.unmi.struts2.Constants()); 然后在 jsp 中同样是用 <s:property value="@[email protected]_NAME"/> 可以显示出 Constants 的 MY_NAME 静态变量来。现在来看一下新的 ValueStack 是啥样子: 在栈顶多了一个 Constants 对象,这样就可以用 @[email protected]_NAME 或 @[email protected]() [email protected]此代码向 ValueStack 中压入多个实例,比如 vs.push(new cc.unmi.struts2.Utils()),那么你在用 @vs@ 的方式访问时就得知道每个根据对象的位置为,是 @vs@ 还是 @vs1@ 就得自己心里有底了。 实际操作也应该是在你的 BaseAction 的初始化时用把常量类或工具类的实例压到 ValueStack 中。看到这里你可能会有个疑问,我们调用静态方法或常量里推荐用类实例去引用,所以往栈里压入一个 Class 实例更表意,也就是要这么写: vs.push(cc.unmi.struts.Constans.class); 想法是不错的,然而这样做反而是不行的,你可以看到 ValueStack 中栈顶是一个 java.lang.Class,并且右边是 Class 实例所有的属性,像: interface false declaredClasses [Ljava.lang.Class;@1485542 constructors [Ljava.lang.reflect.Constructor;@1d59d3c componentType null superclass class java.lang.Object canonicalName cc.unmi.struts2.Constants enumConstants null declaredMethods [Ljava.lang.reflect.Method;@145e5a6 但是却不能用 <s:property value="@[email protected]_NAME"/> 显示出你想要常量来。这其实产生了一个矛盾,通常我们的常量和工具类是不可实例化的,要放在 ValueStack 中的却是它的一个实例,所以要破下常规了。 至于有没有办法直接往 ValueStack 中压入一个相应的 Class 实例,比如借助于泛型的支持,还须进一步细磨一番,不知是否可行。

上一篇:VC多个MRU菜单的问题
下一篇:smtp电子邮件格式及源码解析

相关文章

相关评论