OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。
OGNL优势
1、支持对象方法调用,如xxx.doSomeSpecial();
2、支持类静态的方法调用和值访问,表达式的格式:
@[类全名(包括包路径)]@[方法名 | 值名],例如:
@java.lang.String@format('foo %s', 'bar')
或@tutorial.MyConstant@APP_NAME;
3、支持赋值操作和表达式串联,如price=100, discount=0.8,
calculatePrice(),这个表达式会返回80;
4、访问OGNL上下文(OGNL context)和ActionContext;
5、操作集合对象。
总结
OGNL 有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现了 java.utils.Map 的接口。 OgnlContext对象
OgnlContext对象是ognl表达式语言的核心。
源码类:
public class OgnlContext extends Object implements Map{..}
硬编码方式,了解OgnlContext对象:
// OgnlContext用法
public class OgnlDemo1 {
/** * 1. Ognl表达式语言语言取值,取非根元素的值,必须用#号 * @throws Exception */
@Test
public void testOgnl() throws Exception {
// 创建一个Ognl上下文对象
OgnlContext context = new OgnlContext();
// 放入数据
User user = new User();
user.setId(100);
user.setName("Jack");
// 【往非根元素放入数据, 取值的时候表达式要用"#"】
context.put("user", user);
// 获取数据(map)
// 先构建一个Ognl表达式, 再解析表达式
Object ognl = Ognl.parseExpression("#user.name");
Object value = Ognl.getValue(ognl, context, context.getRoot());
System.out.println(value);
}
/** * 2. Ognl表达式语言语言取值,取根元素的值,不用带#号 * @throws Exception */
@Test
public void testOgn2() throws Exception {
// 创建一个Ognl上下文对象
OgnlContext context = new OgnlContext();
// 放入数据
User user = new User();
user.setId(100);
user.setName("Jack");
// 【往根元素放入数据】
context.setRoot(user);
// 获取数据(map)
// 先构建一个Ognl表达式, 再解析表达式
Object ognl = Ognl.parseExpression("address.province");
Object value = Ognl.getValue(ognl, context, context.getRoot());
System.out.println(value);
}
/** * 3.Ognl对 静态方法调用的支持 * @throws Exception */
@Test
public void testOgn3() throws Exception {
// 创建一个Ognl上下文对象
OgnlContext context = new OgnlContext();
// Ognl表单式语言,调用类的静态方法
//Object ognl = Ognl.parseExpression("@Math@floor(10.9)");
// 由于Math类在开发中比较常用,所以也可以这样写
Object ognl = Ognl.parseExpression("@@floor(10.9)");
Object value = Ognl.getValue(ognl, context, context.getRoot());
System.out.println(value);
}
}
ValueStack, 即值栈对象。
值栈对象:
是整个struts数据存储的核心,或者叫中转站。
用户每次访问struts的action,都会创建一个Action对象、值栈对象、ActionContext对象; 然后把Action对象放入值栈中; 最后再把值栈对象放入request中,传入jsp页面。(key: struts.valueStack); 开发者只需要通过ActionContext对象就可以访问struts的其他的关键对象。 (ActionContext是给开发者用的,便于学习与使用。)
ValueStack图解
/** * struts的数据流转 */
public class OgnlDemo2 extends ActionSupport{
// 根元素值
private User user = new User(100,"Jacks");
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String execute() throws Exception {
ActionContext ac = ActionContext.getContext();
// 映射数据
ac.getContextMap().put("request_data", "request_data");
// 数据存储request
// Map<String,Object> map = (Map<String, Object>) ac.get("request");
// map.put("request_data", "request_data");
// map.put("cn", "China");
ac.getSession().put("Session_data", "Session_data");
ac.getApplication().put("Application_data", "Application_data");
// 二、值栈对象的存储数据的原理
ValueStack vs = ac.getValueStack();
/***************操作根元素的几种方法*****************/
// 设置数据: 入栈
//vs.push(new User(1002,"Tom")); // 栈顶
//vs.pop(); // 移除栈顶元素
// 如何存储? map结构存储
//vs.set("user1", new User(1,"Jacky1"));
//vs.set("user2", new User(2,"Jacky2"));
return super.execute();
}
// 一、获取值栈对象的2种方式
private void getVs() {
// 获取值栈对象,方式1:
HttpServletRequest request = ServletActionContext.getRequest();
ValueStack vs1 = (ValueStack) request.getAttribute("struts.valueStack");
// 获取值栈对象,方式2:
ActionContext ac = ActionContext.getContext();
ValueStack vs2 = ac.getValueStack();
System.out.println(vs1 == vs2);//true
}
}
在jsp中取值:
<body>
<!-- 页面: 必须要拿到ValueStack -->
<br/>1. 取根元素的值<br/>
<s:property value="user.id"/>
<s:property value="user.name"/>
<s:property value="user.address"/>
<s:property value="user.address.city"/>
<s:property value="user.address.province"/>
<br/>2. 取非根元素的值<br/>
<s:property value="#request.cn"/>
<s:property value="#session.Session_data"/>
<s:property value="#application.Application_data"/> <br/>
<!-- 自动找request/session/application,找到后立刻返回 -->
<s:property value="#request_data"/>
<s:property value="#attr.Session_data"/>
<s:property value="#attr.Application_data"/> <br/>
<!-- 获取请求的参数数据 -->
<s:property value="#parameters.userName"/>
<!-- struts的调试标签:可以观测值栈数据 -->
<s:debug></s:debug>
</body>
1. 主要用于访问访问Map栈信息,不使用#号主要用于访问List(对象栈)信息
2. #号还有一个作用就是在JSP页面中构建Map集合。
格式:#{key:value,key:value...}
<s:property value="#request.username"/>
<s:property value="#request.userpsw"/>
<s:property value="address"/> // 获取对象栈信息(默认从栈顶检索)
用于通知执行环境%{}里的是OGNL表达式。
为了方便使用%{}我们可以在任何地方都直接添加%{}来确保运行OGNL表达式:
<s:property value="%{#request.username}"/>
property标签用于输出指定值:
<s:property value=“#name" default="a default value" />
* default:可选属性, 如果需要输出的属性值为null,则显示该属性指定的值
* escape:可选属性,指定是否格式化HTML代码。
* value: 可选属性,指定需要输出的属性值,如果没有指定该属性,则默认输出ValueStack栈顶的值。
<s:property value="#user.id"/>
Iterator: 标签用于对集合进行迭代,这里的集合包含List、Set和数组。
value: 可选属性,指定被迭代的集合,如果没有设置该属性,则使用ValueStack栈顶的集合。
var: 可选属性,引用变量的名称.
status: 可选属性,该属性指定迭代时的IteratorStatus实例。该实例包含如下几个方法:
int getCount(),返回当前迭代了几个元素。
int getIndex(),返回当前迭代元素的索引。
boolean isEven(),返回当前被迭代元素的索引是否是偶数
boolean isOdd(),返回当前被迭代元素的索引是否是奇数
boolean isFirst(),返回当前被迭代元素是否是第一个元素。
boolean isLast(),返回当前被迭代元素是否是最后一个元素。
<s:iterator var="user" value="#request.list" status="st">
<tr class=<s:property value="#st.even?'even':'odd'"/> >
<td><s:property value="#user.id"/></td>
<td><s:property value="#user.name"/></td>
</tr>
</s:iterator>