传智播客-struts2(4)-OGNL

来源:互联网 发布:微信服务号绑定域名 编辑:程序博客网 时间:2024/05/03 11:31

struts2里的OGNL很好很强大!最最有力的证据就是:张老师花了strtuts2总课程一半以上的时间来讲解滴~~~

 

OGNL
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。Struts2框架使用OGNL作为默认的表达式语言。

 

相对EL表达式,它提供了平时我们需要的一些功能,如支持对象方法调用,如xxx.sayHello();支持类静态方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名 | 值名],例如:@java.lang.String@format('foo %s', 'bar')或@cn.itcast.Constant@APP_NAME;操作集合对象等。

 

ActionContext与OGNLContext
OGNL有一个上下文(Context)概念,说白了就是一个map结构,它实现了java.utils.Map接口,在struts2中OGNL Context的实现为ActionContext(官方文档语:The framework sets the OGNL context to be our ActionContext)。不过OGNLContext与ActionContext并不一致,这是两个不同的类,且分属不同的jar包。例如,ActionContext.getContext().getContextMap()得到的是OGNLContext实例;ActionContext.getContext()得到的是ActionContext实例。

 

OGNL Context结构示意图如下:
                             |--request(map对象)
                             |--application(map对象)
OGNL Context -----|--OgnlValueStack root变量[action, OgnlUtil, ... ]  
                             |--session(map对象) 
                             |--attr(map对象)  
                             |--parameters(map对象)

 

从ActionContext源码可以看出,上述六个实例都被“set”到了ActionContext里,所以说“在struts2中OGNL Context的实现为ActionContext”。而且ActionContext.getContext().getContextMap().get("session")==ActionContext.getContext().getSession(),但是奇怪的是,application、session、attr以及parameters对象的获取方式ActionContext都提供了getXXX()方法,唯独没有getRequest()方法。不知道是开发者遗漏了还是出于其他的考虑。。。

 

OGNLContext与ValueStack
Struts2中设置的OGNL Context的根对象为ValueStack(OGNLValueStack为其唯一的实现类),所以Struts2中应用的OGNL Context也被称之为ValueStack Context。

 

1、访问OGNL与ValueStack里的对象
(1)可以用#key的形式访问OGNL Context对象中的各个key对应的对象,并可以采用点(.)操作符进行多级导航调用对象的属性和方法,例如,#application、#session.attr1、#key1.sayHello()。
(2)如果要访问根对象的属性或方法,则可以省略#key,直接访问该对象的属性和方法, struts2修改了OGNL表达式的默认属性访问器,它不是直接访问根对象ValueStack的属性或方法,而是在ValueStack内部的堆栈中所有对象上逐一查找该属性或方法,搜索顺序是从栈顶对象开始寻找,依次往下,直到找到为止,例如,sayHello()表示调用堆栈中某个对象的sayHello()方法。
(3)特例:如果引用名前面没有#,且valueStack中存储的各个对象没有该属性,则把该名称当作Context对象中的某个key来检索对应的对象,但这种方式不支持点(.)操作符。

 

2、ValueStack提供了如下一些方法管理其内部的堆栈和关联的Context:
(1)setValue为ognl表达式寻址到的对象设置属性值。
(2)findValue方法使用OGNL表达式获取结果。
(3)findString方法对findValue方法获取的结果调用转换器转成字符串,如果该对象的类型没有相关转换器,则调用toString方法,并返回结果字符串。一个特殊之处:如果不用#前缀访问ValueStack Context中的对象,则该对象必须是String类型。

 

需要注意的是,Struts2中OGNL表达式需要配合Struts标签才可以使用,例如<s:property value="name"/>。

 

ModelDriven
如果action实现了ModelDriven接口,getModel()方法得到的对象将会被直接压入OGNLValueStack的栈顶。但是该action必须先将model实例化,否则会报空指针异常。下面是ModelDrivenInterceptor的部分源码:
@Override
    public String intercept(ActionInvocation invocation) throws Exception {
        Object action = invocation.getAction();

        if (action instanceof ModelDriven) {
            ModelDriven modelDriven = (ModelDriven) action;
            ValueStack stack = invocation.getStack();
            Object model = modelDriven.getModel();
            if (model !=  null) { //从下文可以看到,没有对model == null的情况进行处理
             stack.push(model); //如果model不为null,则压入ValueStack栈顶
            }
            if (refreshModelBeforeResult) {
                invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
            }
        }
        return invocation.invoke();
    }

 

如果没有使用ModelDriven方式,struts2会先调用action的get方法,如果得到的对象为空,则帮助实例化该对象,然后再调用action里相应的set方法将该对象压入到ValueStack。

 

ModelDriven主要是struts2为了兼容struts1而设计的一个解决方案,如果开发全新的struts2项目,不推荐使用该方式(官方文档语)。

原创粉丝点击