前言:上次与大家分享了SSH框架之Struts的知识,今天就接着之前的分享,今天要分享的知识是Ognl。
一、明确目标:
1、弄清楚之前遗留的问题(user中的uname属性有值,而Demo1Action中的uanme属性没有值?)
2、Struts的优先级
二、情景再现:
在之前的demo1action界面中加一个uname属性,并且生成get和set方法。在demo1中再写set方法传值的代码。
Demo1Action界面:
Demo1界面:
当我运行 Demo1界面,为什么user中的uname属性有值,而Demo1Action中的uanme属性没有值?
这就涉及到了Struts的优先级。
三、Struts的优先级。
Struts的优先级与我们今天的题目有非常大的联系,struts中的jar包是依赖ognl,有着依赖关系,所以讲Struts的优先级时可以围绕着ognl的两大特点来进行分享。从而解决昨天遗留的问题。
ognl的两大特点:
1、值栈是先进后出的特点:
2、计数是从上至下的:
在讲特点之前,先跟大家讲解关于ognl的知识:
1、ognl定义:
OGNL全称是Object Graph Navigation Language(对象图导航语言)是一种强大的表达式语言。其中有一个名词非常的重要------OgnlContext(Ognl上下文)
2、OgnlContext:
OgnlContext=根对象(1)+非根对象(N)在OgnlContext中只有一个根对象,但是非根对象有很多个。比如在某一间教室上课往往只有一个老师在上课,很多同学在该教室听老师讲课,在这里老师就是根对象,而很多同学就是非根对象。下面会用一个实例来说明该知识点。
Demo1:
在demo1中我将小明设为根对象。其他的为非根对象,会进行一系列的替换值:(下面代码中有些代码乱码了)
package com.zking.test;
import ognl.OgnlContext;
import ognl.OgnlException;
public class Demo1 {
/**
* @param args
* @throws OgnlException
*/
public static void main(String[] args) {
Employee e = new Employee();
e.setName("小明");
Manager m = new Manager();
m.setName("张经理�");
// 鍒涘缓OGNL涓嬫枃,鑰孫GNL涓婁笅鏂囧疄闄呬笂灏辨槸涓�涓狹ap瀵硅薄
OgnlContext ctx = new OgnlContext();
// 灏嗗憳宸ュ拰缁忕悊鏀惧埌OGNL涓婁笅鏂囧綋涓幓
ctx.put("employee", e);
ctx.put("manager", m);
ctx.setRoot(e);// 璁剧疆OGNL涓婁笅鏂囩殑鏍瑰璞�
/** ********************** 鍙栧�兼搷浣� *************************** */
// 琛ㄨ揪寮弉ame灏嗘墽琛宔.getName()锛屽洜涓篹瀵硅薄鏄牴瀵硅薄(璇锋敞鎰忔牴瀵硅薄鍜岄潪鏍瑰璞¤〃杈惧紡鐨勫尯鍒�)
String employeeName = (String) OnglExpression.getValue("name", ctx, e);
System.out.println(employeeName);//小明
// 琛ㄨ揪寮�#manager.name灏嗘墽琛宮.getName()锛屾敞鎰忥細濡傛灉璁块棶鐨勪笉鏄牴瀵硅薄閭d箞蹇呴』鍦ㄥ墠闈㈠姞涓婁竴涓悕绉扮┖闂达紝渚嬪锛�#manager.name
String managerName = (String) OnglExpression.getValue("#manager.name",
ctx, e);
System.out.println(managerName);//张经理
// 褰撶劧鏍瑰璞′篃鍙互浣跨敤#employee.name琛ㄨ揪寮忚繘琛岃闂�
employeeName = (String) OnglExpression.getValue("#employee.name", ctx,
e);
System.out.println(employeeName);//小明
/** ********************** 璧嬪�兼搷浣� *************************** */
OnglExpression.setValue("name", ctx, e, "小李");
employeeName = (String) OnglExpression.getValue("name", ctx, e);
System.out.println(employeeName);
OnglExpression.setValue("#manager.name", ctx, e, "孙经理");
managerName = (String) OnglExpression.getValue("#manager.name", ctx, e);
System.out.println(managerName);
OnglExpression.setValue("#employee.name", ctx, e, "小芳");
employeeName = (String) OnglExpression.getValue("name", ctx, e);
System.out.println(employeeName);
}
}
从结果可以看出,无论怎么替换值,根对象有且只有一个(和一个良好的xml文件的起其中一个特点是相同的)
3、Ognl的特点:
1、值栈是先进后出的特点:
用一个案列来讲解这一个特点,我有一个大容器,往里面增加三个用户,先是增加了张三,之后是李四,在之后是王五,代码如下:
Demo1:
public String ognl1() {
// 栈:表示一个先进先出的数据结构:
ValueStack vs = ActionContext.getContext().getValueStack();
// push把项压入栈顶
vs.push(new Employee("zs", 22));
vs.push(new Employee("ls", 22));
vs.push(new Employee("ww", 22));
// pop移除栈顶对象并作为此函数值的值返回改对象
Employee e = (Employee) vs.pop();
System.out.println(e.getName());
e = (Employee) vs.pop();
System.out.println(e.getName());
e = (Employee) vs.pop();
System.out.println(e.getName());
return "bookEdit";
}
struts-sy.xml:
示意图如下:
运行结果:
Ognl的这一特点与List结合中的LinkedList的堆栈的特点是一样的。
2、计数是从上至下的:
同样的与讲上一特点用一个案列来讲解,有两个人物,一个是张雇员,薪资为2000,另一个是小明同学,编号为s001,我从中找出name和salary的值就验证了这一特点。
Demo1.jsp:
*/
public String ognl2() {
ValueStack vs = ActionContext.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"));
ActionContext ac = ActionContext.getContext();
return "bookEdit";
}
Student类:
package com.zking.test;
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 + "]";
}
}
Employee类:
package com.zking.test;
public class Employee {
private String name;
private Address address;
private Integer salary;
public Employee() {
super();
}
public Employee(String name, Integer salary) {
super();
this.name = name;
this.salary = salary;
}
public Integer getSalary() {
return salary;
}
public void setSalary(Integer salary) {
this.salary = 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;
}
@Override
public String toString() {
return "Employee [name=" + name + ", address=" + address + ", salary=" + salary + "]";
}
}
Ognl.jsp:
运行结果:
将两个人物装入一个容器时,小明同学在上面,张雇员在下面,计数的时候先要取出小明同学看有没有这个值,如果有就会把对应属性的值取出来,如果没有就会进行下一步,把一个人物取出来,看有没有这个值,同样的,有对应属性的值就会取出来,没有就会一直找,直到找到为止。取值的时候也体现出了ognl的特点一。
解释昨天的问题:
ognl.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>ognl特点</h3>
<a href="${pageContext.request.contextPath }/sy/demo7_ognl1.action">先进先出的特点</a>
<br>
<a href="${pageContext.request.contextPath }/sy/demo7_ognl2.action">取值是从上至下的特点</a>
<br>
</body>
</html>
首先先看一张示意图:
示意图阐释: 在Demo1Action中,有一个user对象,以及uname这一个属性,而user对象是ModelDriven接口用来定义模型的,而uname这一属性是属于Demo1Action这一个类的。在最开始的时候,我创建Demo1Action这一个类时,就已经将Demo1Action这一个类装到的一个容器的底部,之后我再实现ModerDriven接口的时候,我同样将ModerDriven接口装进了刚刚那个容器里面,同理可得:映射出一个一模一样的容器,对应的属性就装到了容器里面(首先是Demo1Action对应的uname属性,其次是ModerDriven对应的user1对象),当我把uname=ognl这一属性值加入到容器中时,首先是计数是从上至下的和先进后出的特点,将ognl值加入到ModerDriven的uname属性中,Demo1Action的uname属性就没有值了,当运行ognl.jsp时,运行出的结果往往符合了Ognl的第一特点,先进后出的特点。自然而然的uname就为null。解释昨天遗留问题正好用Ognl的两大特点验证了。