一、介绍:
OGNL是Object-Graph Navigation Language的缩写(也称为对象图导航语言),它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性
二、OgnlContext(ongl上下文)其实就是Map (教室、老师、学生)
分为两个对象:根对象(Root)和非根对象
举例:
map : 教室(容器)
OgnlContext=根对象(1)+非根对象(N)
老师 teacher:根对象 (1)
学生 stu:非根对象
非根对象要通过"#key"访问,根对象可以省略"#key"
如果我们想要取老师:String teacher= (String) OnglExpression.getValue(“name”, ctx, e);
由于老师是根对象,所以"#“可以不用
如果我们想取学生:String stu= (String) OnglExpression.getValue(”#stu.name", ctx, e);
由于学生是非根对象,所以要使用"#"
总结:
1、一个上下文中只有一个根对象
2、取跟对象的值,只需要直接通过根对象属性即可
3、非根对象取值必须通过指定的上下文容器中的#key.属性去取。
struts2中ognl结构图:
三、案例测试:
根对象取值和非根对象取值的现象,以及OGNL取值和赋值的案例
实体类:
package com.swxognl;
public class Teacher {
private String name;
private Address address;
private Integer salary;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public Integer getSalary() {
return salary;
}
public void setSalary(Integer salary) {
this.salary = salary;
}
public Teacher(String name, Address address, Integer salary) {
super();
this.name = name;
this.address = address;
this.salary = salary;
}
public Teacher(String name, Integer salary) {
super();
this.name = name;
this.salary = salary;
}
public Teacher() {
super();
}
@Override
public String toString() {
return "Teacher [name=" + name + ", address=" + address + ", salary=" + salary + "]";
}
}
package com.swxognl;
public class Student {
private String name;
private String number;
public Student() {
super();
}
public Student(String name, String number) {
super();
this.name = name;
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
@Override
public String toString() {
return "Student [name=" + name + ", number=" + number + "]";
}
}
测试类:
package com.swxognl;
import ognl.OgnlContext;
/**
* 测试ognl
* @author 10570
*
*/
public class Demo {
public static void main(String[] args) {
Teacher t = new Teacher();
t.setName("晓哥");
Student s = new Student();
s.setName("大飞");
// 创建OGNL下文,而OGNL上下文实际上就是一个Map对象
OgnlContext ctx = new OgnlContext();
// 将老师和学生放到OGNL上下文当中去
ctx.put("teacher", t);
ctx.put("stu", s);
ctx.setRoot(t);// 设置OGNL上下文的根对象
/** ********************** 取值操作 *************************** */
// 表达式name将执行t.getName(),因为t对象是根对象(请注意根对象和非根对象表达式的区别)
String teacherName = (String) OnglExpression.getValue("name", ctx, t);
System.out.println(teacherName);
// 表达式#stu.name将执行s.getName(),注意:如果访问的不是根对象那么必须在前面加上一个名称空间,例如:#stu.name
String stuName = (String) OnglExpression.getValue("#stu.name",
ctx, s);
System.out.println(stuName);
// 当然根对象也可以使用#teacher.name表达式进行访问
teacherName = (String) OnglExpression.getValue("#teacher.name", ctx,
t);
System.out.println(teacherName);
/** ********************** 赋值操作 *************************** */
OnglExpression.setValue("name", ctx, t, "小明");
teacherName = (String) OnglExpression.getValue("name", ctx, t);
System.out.println(teacherName);
OnglExpression.setValue("#stu.name", ctx, s, "孙悟空");
stuName = (String) OnglExpression.getValue("#stu.name", ctx, s);
System.out.println(stuName);
OnglExpression.setValue("#teacher.name", ctx, t, "小芳");
teacherName = (String) OnglExpression.getValue("name", ctx, t);
System.out.println(teacherName);
}
}
结果:
2. OGNL向ValueStack压栈
2.1 值栈
先进后出的数据结构,弹夹 push/pop
2.2 为什么要使用ValueStack作为根对象
放到值栈中的对象都可视为根对象
package com.swxognl;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.util.ValueStack;
public class Demo2 {
/**
*
* 值栈的使用
*
*/
public String test1() {
// 栈:表示一个先进后出的数据结构
ValueStack vs = ActionContext.getContext().getValueStack();
// push方法把项压入栈顶
vs.push(new Teacher("zs", 22));
vs.push(new Teacher("ls", 22));
vs.push(new Teacher("ww", 22));
// pop方法移除栈顶对象并作为此函数的值返回该对象
Teacher e = (Teacher) vs.pop();
System.out.println(e.getName());
e = (Teacher) vs.pop();
System.out.println(e.getName());
e = (Teacher) vs.pop();
System.out.println(e.getName());
return "rs";
}
/**
* 此例用于模拟struts2的值栈计算过程
*
* @param args
*/
public String test2() {
ValueStack vs = ActionContext.getContext().getValueStack();
vs.push(new Teacher("张老师", 2000));// 1
vs.push(new Student("小明同学", "s001"));// 0
System.out.println(vs.findValue("name"));//值栈取值从上往下,取到为止,如果已经拿到,不再往下找。
System.out.println(vs.findValue("salary2"));//属性不存在 所以找不到 为null
System.out.println(vs.findValue("salary"));//一直找,找到该属性为止
ActionContext ac = ActionContext.getContext();
return "rs";
}
}
配置struts-sy.xml
<action name="ognl_*" class="com.swxognl.Demo2" method="{1}">
<result name="rs">/rs.jsp</result>
</action>
前台代码:
<h3>讲解ognl值栈</h3>
<a href="${pageContext.request.contextPath}/sy/ognl_test1.action">测试ognl1</a>
<a href="${pageContext.request.contextPath}/sy/ognl_test2.action">测试ognl2</a>
结果:
注意:
1、ActionContext一次请求创建一次
2、值栈取值从上往下,取到为止,如果已经拿到,不再往下找。
后台定义属性和实现modelDriver接口,并提供get和set方法
package com.swxstruts.jsp;
import com.opensymphony.xwork2.ModelDriven;
/**
* jsp传递参数到后台的三种方式:
* 1、set传参
* 2、实现modeldriven接口传参(自定义mvc做法)
* 3、类实例.属性传参
* @author 10570
*
*/
public class DemoAction implements ModelDriven<User>{
private String sex;
private User user1 = new User();//不给它提供set方法
private User user2;
private String uname;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
@Override
public User getModel() {
// TODO Auto-generated method stub
return user1;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public User getUser2() {
return user2;
}
public void setUser2(User user2) {
this.user2 = user2;
}
/**
* set传参是否成功
* @return
*/
public String test1() {
System.out.println(sex);
return "rs";
}
/**
* modeldriven接口传参是否成功
* @return
*/
public String test2() {
System.out.println(user1);
return "rs";
}
/**
* 类实例.属性传参是否成功
* @return
*/
public String test3() {
System.out.println(user2);
return "rs";
}
}
解释为什么user1.uname有值,而uname却取不到值?
struts后台取值方法有3种,一种实现接口,一种通过get和set方法取,还有一种通过对象点属性名,我已经提供了get方法,其实应该是能取到的,但是取不到。
其实这和ValueStack的压栈有关系了,因为压栈的结构是先进后出,而ValueStack的取值是取到了值就会返回,不会往下取了。
而ValueStack对取值的压栈是先把xxxAction也就是我们通过set和get方法取值的方式先压入栈底,然后再把ModelDriver压入,所有会先取到通过ModelDriver来获取值的,而获取到了就返回了,导致后面的值不会获取了
ValueStack
同一请求中只创建一个上下文
先压action,再呀modeldriven
从上往下找值