1.1.1 OGNL概述:
Object Graphic Navigation Language(对象图导航语言)的缩写
* EL :OGNL比EL功能强大很多倍.
它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。
OGNL相对其它表达式语言具有下面几大优势:
1、支持对象方法调用,如xxx.doSomeSpecial();
2、支持类静态的方法调用和值访问,表达式的格式:
@[类全名(包括包路径)]@[方法名 | 值名],例如:
@java.lang.String@format('foo %s', 'bar')
或@tutorial.MyConstant@APP_NAME;
设置 struts.ognl.allowStaticMethodAccess=true
3、访问OGNL上下文(OGNL context)和ActionContext;
4、支持赋值操作和表达式串联,如price=100, discount=0.8,
calculatePrice(),这个表达式会返回80;
5、操作集合对象。
1.1.2 访问类的方法:
<s:property value="'helloworld'.length()"/><br/>
1.1.3 访问类的静态方法:
开启一个常量:
<constant name="struts.ognl.allowStaticMethodAccess" value="true"/>
语法:
@类的全路径@方法名
<s:property value="@java.lang.Math@random()"/><br/>
<s:property value="@java.lang.Math@max(12,15)"/><br/>
<s:property value="@java.lang.String@format('%s,你好','小明')"/><br/>
1.1.4 访问OGNL的上下文:(值栈ValueStack )
什么是值栈?
ValueStack(值栈): 贯穿整个 Action 的生命周期(每个 Action 类的对象实例都拥有一个 ValueStack 对象). 相当于一个数据的中转站. 在其中保存当前 Action 对象和其他相关对象.
Struts 框架把 ValueStack 对象保存在名为 “struts.valueStack” 的请求属性中,request中
结论:
Action何时创建:每次访问的时候创建.Action多实例的.没次访问都会创建一个Action.每个Action中有一个ValueStack对象的引用.
值栈对象ValueStack在request域中有一份.名字struts.valueStack
值栈:Action--->JSP传递值的.
OGNL:获得值栈的数据.
值栈的内部结构?
在 ValueStack 对象的内部有两个逻辑部分:
ObjectStack: Struts 把动作和相关对象压入 ObjectStack 中--List
ContextMap: Struts 把各种各样的映射关系(一些 Map 类型的对象) 压入 ContextMap 中
Struts 会把下面这些映射压入 ContextMap 中
parameters: 该 Map 中包含当前请求的请求参数
request: 该 Map 中包含当前 request 对象中的所有属性
session: 该 Map 中包含当前 session 对象中的所有属性
application:该 Map 中包含当前 application 对象中的所有属性
attr: 该 Map 按如下顺序来检索某个属性: request, session, application
值栈ValueStack 和 ActionContext关系? --- 值栈的创建
StrutsPrepareAndExecuteFilter:核心过滤器:(预处理和执行)
核心过滤器 init 和 doFilter 两个方法.服务器启动的时候init就执行了 .每次访问doFilter执行.
Action每次访问的时候会创建.每次请求doFilter都会执行.(Action的创建的代码在doFilter)中.
在doFilter的代码中:
* prepare.createActionContext(request, response);--- 创建了ActionContext对象.
* ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack(); --- 创建了一个ValueStack对象
* ctx = new ActionContext(stack.getContext()); --- 将值栈对象的引用保存到ActionContext中.
***** 所以可以从ActionContext对象中获得到值栈对象.
* 将ValueStack存request域中:
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
如何获得值栈对象?
两种方式:
// 1.ActionContext对象中有值栈的引用.
ValueStack valueStack1 = ActionContext.getContext().getValueStack();
// 2.从request域中获得值栈对象.
ValueStack valueStack2 = (ValueStack) ServletActionContext.getRequest()
.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
向值栈保存数据?
push(Object obj); --- 将对象压入到栈顶.
set(String key,Object); --- 创建一个Map集合,将Map集合压入到(root)栈中
***** Action对象默认是在栈中的!!!那么在Action中定义的属性呢?
* 对属性提供了相应get方法.获得到属性? -- Action的属性也在栈中.
在页面通过struts2标签 获取值栈内容?
获得root区域值:不需要加#
<s:property value=”name”/>
获得context区域的值:需要加#
<s:property value=”#request.username”/>
通过EL表达式可以访问值栈数据?
底层的代码:StrutsRequestWrapper
public class StrutsRequestWrapper extends HttpServletRequestWrapper {
public StrutsRequestWrapper(HttpServletRequest req) {
super(req);
}
public Object getAttribute(String s) {
......
ActionContext ctx = ActionContext.getContext();
Object attribute = super.getAttribute(s);//先从request范围获取属性值
if (ctx != null) {
if (attribute == null) {
//如果从request范围没有找到属性值,即从ValueStack中查找对象的属性值
......
ValueStack stack = ctx.getValueStack();
attribute = stack.findValue(s);
......
}
}
return attribute;
}
}
1.1.5 OGNL:获得值栈的数据.
#号的用法:
1.获的值栈context中的值
<s:property value="#request.name"/>
<s:property value="#session.name"/>
<s:property value="#application.name"/>
<s:property value="#attr.name"/>
<s:property value="#parameters.name"/>
2.投影集合:(对集合中的数据进行过滤)
<h3>遍历整个list集合</h3>
<s:iterator var="p" value="list">
<s:property value="name"/>---<s:property value="price"/><br/>
<s:property value="#p.name"/>---<s:property value="#p.price"/><br/>
</s:iterator>
<h3>过滤要集合的所有的name属性</h3>
<s:iterator value="list.{name}" var="pname">
<s:property value="pname"/>
</s:iterator>
<h3>遍历集合中价格大于1500的商品</h3>
<s:iterator value="list.{?#this.price > 1500}">
<s:property value="name"/>---<s:property value="price"/>
</s:iterator>
<h3>遍历集合中价格大于1500的商品名称</h3>
<s:iterator value="list.{?#this.price>2000}.{name}" var="pname">
<s:property value="pname"/>
</s:iterator>
3.构建一个map集合.
<h3>构建一个List集合</h3>
<!-- 构建一个list集合 -->
<s:iterator value="{'aa','bb','cc','dd'}" var="i" >
<s:property value="i"/>
</s:iterator>
<h3>构建Map集合</h3>
<s:iterator value="#{ 'aa':'name1','bb':'name2','cc':'name3' }">
<s:property value="key"/>---<s:property value="value"/>
</s:iterator>
%号用法:
1.告诉运行环境是一个OGNL表达式:
<% request.setAttribute("name", "张三"); %>
<s:textfield name="name" value="%{#request.name}" label="用户名"/>
2.告诉运行环境不是一个OGNL表达式:
<% request.setAttribute("foo", "foo"); %>
<s:property value="%{'#request.foo'}"/>
$号用法:
1.在国际化文件中使用OGNL表达式
itcast.test=${\#request.name}
页面中:
<s:i18n name="message">
<s:text name="itcast.test"></s:text>
</s:i18n>
2.在配置文件XML中使用OGNL表达式
<param name="contentType">${contentType}</param>