ONGL简介:
OGNL 的全称是对象图导航语言( Object-Graph Navigation Language),它是一种功能强大的开源表达式语言,使用这种表达式语言,可以通过某种表达式语法,存储 java 对象的任意属性,调用 java 对象的方法,同时能够自动实现必要的类型转换。如果把表达式看作是一种带有语义的字符串,那么 OGNL 无疑成为了这个语义字符串于 java 对象之间的沟通桥梁。
OGNL的要素
表达式:表达式是整个OGNL的核心,OGNL会根据表达式去对象中取值,所有的OGNL操作都是指对表达式解析后进行的。它表明了此次OGNL操作要做什么。表达式就是一个带有语法含义的字符串,这个字符串规定了操作的类型和操作的内容。OGNL支持大量的表达式语法,不仅支持这种“链式”对象访问路径,还支持在表达式中进行简单的计算。
根对象(ROOT):Root对象可以理解为OGNL的操作对象,表达式规定了“做什么”,而Root对象则规定了“对谁操作"。OGNL称为对象图导航语言,所谓对象图,就是以任意对象为根,通过OGNL可以访问这个对象关联的其他。
Context对象:实际上OGNL的取值还需一个上下文环境,设置了Root对象,OGNL可以对root对象进行取值或者写值等操作,root对象所在环境就是OGNL的上下文环境(Context)。上下文环境规定了OGNL的操作”在哪里进行“。上下文环境COntext是一个map类型的对象,在表达式中访问Context中的对象,需要使用”#”号加上对象名称,即“#对象名称”的形式。
OGNL的取值与赋值方法
1 /** 2 * 用于OGNL表达计算的一个工具类 3 * 4 */ 5 public class OnglExpression { 6 private OnglExpression() { 7 } 8 9 /** 10 * 根据OGNL表达式进行取值操作 11 * 12 * @param expression 13 * ognl表达式 14 * @param ctx 15 * ognl上下文 map 16 * @param rootObject 17 * ognl根对象 18 * @return 19 */ 20 public static Object getValue(String expression, OgnlContext ctx, 21 Object rootObject) { 22 // ${book.c.name} 意味着你要在jsp上获取书籍的类别的名称 ctx.get(#name) 根对象取值 23 // ctx.get(${book.c.name}) 非根对象取值 24 try { 25 return Ognl.getValue(expression, ctx, rootObject); 26 } catch (OgnlException e) { 27 throw new RuntimeException(e); 28 } 29 } 30 31 /** 32 * 根据OGNL表达式进行赋值操作 33 * 34 * @param expression 35 * ognl表达式 36 * @param ctx 37 * ognl上下文 38 * @param rootObject 39 * ognl根对象 40 * @param value 41 * 值对象 42 */ 43 public static void setValue(String expression, OgnlContext ctx, 44 Object rootObject, Object value) { 45 try { 46 Ognl.setValue(expression, ctx, rootObject, value); 47 } catch (OgnlException e) { 48 throw new RuntimeException(e); 49 } 50 } 51 }
EL表达式和OGNL的区别:
OGNL表达式只对struts标签管用,在HTML标签中还是要使用EL表达式
struts2标签中都是用的OGNL表达式,先从栈顶找,找不到就从map域中找,再找不到直接报错
而常规EL表达式只能从map域中找,不能在栈顶找,找不到什么都不显示。
搜索顺序为:page>request>session>application
但是struts2对HttpRequest对象进行了封装StrutsRequestWrapper,此时EL表达式可以在栈顶搜索
搜索顺序为:page>request>ValueStack>session>application
OGNL的取值与赋值案列
1 public class Demo1 { 2 3 /** 4 * @param args 5 * @throws OgnlException 6 */ 7 public static void main(String[] args) { 8 // 叫小李的员工 9 Employee e = new Employee(); 10 e.setName("小李"); 11 // 张经理的管理 12 Manager m = new Manager(); 13 m.setName("张经理"); 14 15 // 创建OGNL下文,而OGNL上下文实际上就是一个Map对象 16 OgnlContext ctx = new OgnlContext(); 17 18 // 将员工和经理放到OGNL上下文当中去 19 ctx.put("employee", e); 20 ctx.put("manager", m); 21 // 小李是根对象 一个公司有很多老板 只有一个员工小李 22 ctx.setRoot(e);// 设置OGNL上下文的根对象 23 24 /** ********************** 取值操作 *************************** */ 25 // 表达式name将执行e.getName(),因为e对象是根对象(请注意根对象和非根对象表达式的区别) 26 String employeeName = (String) OnglExpression.getValue("name", ctx, e); 27 System.out.println(employeeName); //小李 28 29 // 表达式#manager.name将执行m.getName(),注意:如果访问的不是根对象那么必须在前面加上一个名称空间,例如:#manager.name 30 String managerName = (String) OnglExpression.getValue("#manager.name", 31 ctx, e); 32 System.out.println(managerName); //张经理 33 34 // 当然根对象也可以使用#employee.name表达式进行访问 35 employeeName = (String) OnglExpression.getValue("#employee.name", ctx, 36 e); 37 System.out.println(employeeName); //小李 38 39 /** ********************** 赋值操作 *************************** */ 40 OnglExpression.setValue("name", ctx, e, "小明"); 41 employeeName = (String) OnglExpression.getValue("name", ctx, e); 42 System.out.println(employeeName); //小明 43 44 OnglExpression.setValue("#manager.name", ctx, e, "孙经理"); 45 managerName = (String) OnglExpression.getValue("#manager.name", ctx, e); 46 System.out.println(managerName); //孙经理 47 48 OnglExpression.setValue("#employee.name", ctx, e, "小芳"); 49 employeeName = (String) OnglExpression.getValue("name", ctx, e); 50 System.out.println(employeeName); //小芳 51 } 52 }
输出结果:
OGNL在struts2中的应用
public String test1() { // ValueStack是一个堆栈结构的容器 有压栈操作 先进后出 ValueStack vs = ServletActionContext.getContext().getValueStack(); vs.push(new Employee("张雇员", 2000));// 1 vs.push(new Student("小明同学", "s001"));// 0 System.out.println(vs.findValue("name")); //小明 System.out.println(vs.findValue("salary")); //2000 return "rs"; }
配置文件设置:
<action name="/stack_*" class="com.liuwenwu.test.DemoAction" method="{1}">
<result name="rs">/rs.jsp</result>
</action>
jsp代码:
<a href="${pageContext.request.contextPath }/sy/stack_test1.action?sex=nv">ognl1</a>
输出结果:
证明ValueStack是一个堆栈结构的容器 有压栈操作 先进后出
valueStack的赋值套路
private Cal cal1=new Cal(); private String num1; public String getNum1() { return num1; } public void setNum1(String num1) { this.num1 = num1; } public String accept1() { // cal使用的是ModelDriven赋值 System.out.println("cal1:"+cal1); // num使用的是get/set赋值 System.out.println("num1:"+num1); return "rs"; }
jsp代码:
<a href="${pageContext.request.contextPath }/sy/demo_accept1.action?num1=20&&num2=5">accept1</a>
输出结果:
cal1有值而num1没值 cal1通过ModelDriven接口赋值 num1通过get/set方法赋值 最终压栈的结构 num1在下 cal1在上 所以赋值在cal1上 不会赋值到底部的num1上 所以num1为 null