struts2 ognl 原理
Struts2内置了OGNL这是大家都知道的了,其实这种说话不严格,应该OGNL本身是一种很强大的表达式语言,XWork整合了OGNL的一部分并且将这部分内容做了相应的扩展,而Struts2又建立在XWork这个项目的基础之上,所以Struts2也就内置了OGNL这部分强大的功能。
为了详细些一步一步做记录吧。
先说OGNL,OGNL内部自己会维护一个OGNL上下文(OgnlContext)是一个实现了Map接口的对象,OGNL会将对象放在这个上下文中统一管理的,并且会有一个对象被指定为根对象(root)。假设有User和Customer这么两个类,分别有user和customer两个实例,这两个对象都有一个name属性,并且将user对象配置为唯一的根对象,那么就会有下面的情况:
#user.name 返回user.getName();
#customer.name 返回customer.getName();
#name 返回user.getName(); 因为user对象为根对象
OGNL访问对象的基本机制就是这样的。
在XWork中,ValueStack对象是上下文中的根对象,XWork中不仅可以根据表达式从ValueStack对象中获取对象,还可以获取对象的属性,XWork自己有一个强大的属性访问器,它可以自动搜索栈内的所有实体(从上到下),直到找到你所访问的对象和属性。假设ValueStack栈中有两个上面所说的user和customer两个对象,并且user是栈顶元素,customer在下面,就会有下面的情况:
name 返回user.getName(); 因为user在栈顶,搜索器找到一个匹配的属性就不会继续找下去
如果希望访问靠后对象的属性XWork提供了索引访问ValueStack的方法:
[0].name 返回user.getName()
[1].name 返回customer.getName();
了解上面这些之后Struts2中的OGNL就很好理解了,Struts2框架也没有对XWork中的OGNL做太大的修改,只是拿过来做了一下整合工作,Struts2将ActionContext设置为OGNL中的上下文,ValueStack依然是OGNL上下文中的根元素,大家知道application,session和request这几个对象也是在ActionContext中的,它们是和根对象ValueStack共存的,与根对象是无关的,就像刚开始说OGNL那个例子实在OGNL上下文中的两个平行对象,只不过ValueStack这个对象是这个OGNL上下文中的根对象(root)。如果要访问上下文中根对象中的对象和属性是不用加任何标记符号的,但是在访问application,session和request这几个范围内的对象和属性就要用"#"符号来告诉ognl不要在根对象中去搜索了,而是去我们指定的上下文中去找。用官方一个图来形象描述ValueStack和其他几个对象的关系:
|--request
|
|--application
|
context map---|--OgnlValueStack(root)
|
|--session
|
|--attr
|
|--parameters
基本原理就是这样了,举例验证理论。
1. ActionContext是OGNL的上下文,ValueStack对象是上下文中的根对象:
随便找一个Action给JSP页面传东西过去的例子,然后在Action的execute()方法中加入以下代码:
ActionContext.getContext().getValueStack().set("test", "love java");
在目标JSP页面空白处加上如下代码:
<s:label value="%{test}"></s:label>
再次跳转到该页面就可以看到love java出现在页面上了
2. 其他范围和ValueStack平行关系:
还找刚才那个例子,在Action中加入
request.setAttribute("test1", "love java1");
在JSP页面加入代码:
<s:label value="%{#request.test1}"></s:label>
这次跳转就可以看到love java1出现了
3. OGNL上下文的访问
Action中加入代码:
ActionContext.getContext().put("test2", "love java2");
JSP页面中加入:
<s:label value="%{#test}"></s:label>
看到love java2之后应该大彻大悟了吧,这里值得说一下就是在ActionContext.getContext().put("test2", "love java2")之后上下文结构:
|--request
|
|--application
|
context map---|--OgnlValueStack(root)
|
|--session
|
|--attr
|
|--parameters
|
|
|--test2
这样更清楚了吧!
总结:
1. 在JSP页面中"%{"就表示OGNL表达式开始,"}"表示OGNL表达式结束
2. 如果访问根对象中的对象和属性不用任何符号标志,如:%{Object.field}
3. 访问特定Scope中的对象和属性用"#"来通知OGNL查询器,如:%{#request.object},当然OGNL很强大,在一个链中,前一个对象做为解释下一个对象的上下文。你可以任意扩展这个链,在链中也可以访问对象中的方法。