什么是OGNL?
OGNL(Object-Graph Navigation Language),是一种功能强大的开源表达式语言,可以获取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。
- EL:从域对象中获取数据,从EL的11个对象中获取。
- OGNL:调用对象的方法,获取struts2值栈的数据。OGNL其实是第三方的表达式语言。
OGNL的作用?
- 支持对象方法调用。例如:objName.methodName();
- 支持类静态方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名|值名]。例如:@java.lang.String@format('foo %s', 'bar');
- 支持赋值操作和表达式串联。例如price=100, discount=0.8, calculatePrice(price*discount),这个表达式会返回80;
- 访问OGNL上下文(OGNL context)和ActionContext;
- 操作集合对象。
OGNL的要素
- 表达式:表明此次OGNL操作要“做什么”
- 根对象:OGNL的操作对象,即root规定“对谁操作”
- Context对象:root对象所在的环境就是OGNL的上下文环境,规定OGNL的操作“在哪里进行”,上下文环境Context是一个Map类型的对象,在表达式中访问Context中的对象,需要使用“#”号加上对象的名称,即“#对象名称”的形式。
OGNL的Struts环境入门
访问对象的方法
<h3>调用对象的方法</h3>
<s:property value="'helloWord'.length()"/>
访问对象的静态方法
<h3>调用对象的静态方法</h3>
<s:property value="@java.lang.Math@random()"/>
什么是值栈?
ValueStack是struts的一个接口,ognlValueStack是ValueStack的实现类,客户端发起一个请求,struts2架构会创建一个Action实例同时创建一个ognlValueStack值栈实例,ognlValueStack贯穿整个Action的生命周期,struts2中使用OGNL将请求Action的参数封装为对象存储到值栈中,并通过OGNL表达式读取值栈中的对象属性值。
ValueStack其实类似于一个数据中转站,struts2框架当中的数据就保存到了ValueStack中。
值栈的内部结构?
结果显示:
- ValueStack中有两个主要的区域:
- root区域:为CompoundRoot,存储了action实例,它作为ognlContext的Root对象。其实就是一个ArrayList。里面一般放置对象。获取root的数据不需要加#
- context区域:其实就是一个Map。里面放置的是web开发常用的对象数据的引用。获取context数据需要加#
- request:
- session:
- application:
- parameters:
- attr:
值栈与ActionContext的关系
- ServletContext:Servlet的上下文
- ActionContext:Action的上下文。
- 当请求过来的时候,执行过滤器中的doFilter方法,在这个方法中创建ActionContext,在创建ActionContext过程中,创建ValueStack对象,将ValueStack对象传递给ActionContext对象。所以可以通过ActionContext获取值栈对象。
- ActionContext对象之所以能够访问Servlet的API(访问的是域对象),因为其内部有值栈的引用。
获得值栈
- 通过ActionContext对象获取值栈
//方法一:通过ActionContext获得
ValueStack valueStack1 = ActionContext.getContext().getValueStack();
- 在Struts2的内部,将值栈存入request中一份
//方法二:通过request获得
ValueStack valueStack2 = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
操作值栈----向值栈中存入数据
- 一种:在Action中提供属性的get方法的方式
- 默认情况下,将·Action对象压入到值栈中,Action的属性?(也会在值栈中)
public class ValueStackDemo3 extends ActionSupport{
private User user;
public User getUser() {
return user;
}
@Override
public String execute() throws Exception {
user = new User("李斌","123");
return SUCCESS;
}
}
- 二种:使用ValueStack中本省的方法的方式。
public class ValueStackDemo4 extends ActionSupport{
@Override
public String execute() throws Exception {
//获得值栈
ValueStack valueStack = ActionContext.getContext().getValueStack();
//使用push(Object obj); set(String key,Object obj);
User user = new User("李白","123");
valueStack.push(user);
valueStack.set("name", "小龙");//创建一个Map集合,将Map压入到栈中
return SUCCESS ;
}
}
获取值栈数据
- 获取值栈中的数据就是在页面中使用OGNL表达式即可。
- 获取root的数据:不需要加#
<!-- 获取一个对象的数据 -->
<s:property value="username"/>
<s:property value="password"/><br/>
<!-- 获取集合中的数据 -->
<s:property value="list[0].username"/>
<s:property value="list[0].password"/><br/>
<s:property value="list[1].username"/>
<s:property value="list[1].password"/><br/>
<s:property value="list[2].username"/>
<s:property value="list[2].password"/><br/>
- 获取context数据
<!-- 获取context中的数据 -->
<s:property value="#request.name"/><br/>
<s:property value="#session.name"/><br/>
<s:property value="#application.name"/><br/>
<s:property value="#attr.name"/><br/>
<s:property value="#parameters.id"/><br/>
EL为何访问值栈数据?
因为Struts2框架底层对request.getAttribute(String key)方法做了增强:即先从request中获取数据,如果没有获取到,再从值栈中获取。
OGNL中特殊字符
1、#号
获取context中的数据
<h3>获取context中的数据</h3>
<%
request.setAttribute("name", "李冰");
%>
<s:property value="#request.name"/>
使用#构建map集合
<s:iterator var="entry" value="#{'a':'1','b':'2','c':'3'}">
<s:property value="key"/>--<s:property value="value"/></br>
<s:property value="#entry.key"/>--<s:property value="#entry.value"/></br>
</s:iterator>
<s:radio list="#{'1':'男','2':'女'}" name="sex3" label="性别"></s:radio>
2、%号
强制解析OGNL
<h1>OGNL中%的用法</h1>
<%
request.setAttribute("name","王东");
%>
姓名:<s:textfield name="name" value="%{#request.na
3、$号
在配置文件中使用OGNL
- 属性文件
- 国际化地方:
- message_zh_CN.properties
- user.login=登陆
- user.welcome=欢迎,${#session.user.username}
- message_en_US.properties
- user.login=Login
- user.welcome=Welcome,${#session.user.username}
- message_zh_CN.properties
- 国际化地方:
- xml文件
- 文件下载:
- 配置
- <action name="download" class=xxx.DownloadAction>
- <result type="stream">
- <param name="Content-Type">文件类型</param>
- <param name="Content-Disposition">attachment;filename=${文件名}</param>
- </result>
- <result type="stream">
- </action>
- 文件下载: