一、概述
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。Struts2框架使用OGNL作为默认的表达式语言。相对于EL表达式来说它比较适合Struts2框架,本身的内置对象也做了很大的封装,可以作为开发了解。
二、quickstart
action.java
package cn.zjy.OGNL;
import java.io.Serializable;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class OGNLtest1 extends ActionSupport implements Serializable {
public String name;
private String password;
@Override
public String execute() throws Exception {
System.out.println("running");
name="zhangsan";
password="123";
ActionContext actioncontext = ActionContext.getContext();
actioncontext.put("name", "wangwu");
actioncontext.put("username", "wangwu1");
//存放于context上下文中
//Returns the ActionContext specific to the current thread
actioncontext.getSession().put("username","lisi" );
// context.put(key, value); action中维护的一个map
return SUCCESS;
}
}
1.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP '`.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<s:property value="[0].name"/><br>
<s:property value="username"/><br/>
<!-- valueStack中的栈顶action 中的 name 属性 如果找不到 则会去寻找context中的 name-->
<s:property value="#parameters.username[0]"/>
<s:property value="#session.username"/>
<s:property value="#session.name"/>
<!-- 其余都需要加引用范围 -->
<s:debug></s:debug>
<!-- 使用el表达式 -->
${name}<br/>
${username}<br/>
<!-- el表达式也可以访问action中的属性 struts属性中封装了其 方法-->
${requestScope.username}<br/>
${requestScope.name}<br/>
<!-- request - valuestack(action) - actioncontext 这里struts2 框架对request已经包装 先使用request的name-->
${sessionScope.username}<br/>
${paramValues.a}
<!-- http://127.0.0.1:8080/struts2-day03/ognl1/ognl1.action?a=1&a=2 -->
</body>
</html>
结果显示
可以看到如同el表达式,一样,ognl的内置对象显示了在action中包装的属性,
quickstat之后看不懂的地方可以归纳为以下两点
一、
ActionContext actioncontext = ActionContext.getContext();
actioncontext.put("name", "wangwu");
actioncontext.put("name", "wangwu");
actionContext是什么,内部是一个什么样的结构
二、
<s:property value="#parameters.username[0]"/> 是一种什么样的机制来显示,和el表达式有什么相似之处
三、原理概述
接下来我们先来了解一下,ActionContext中一个叫做上下文的概念,
Ognl有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现了java.utils.Map接口,在Struts2中上下文(Context)的实现为ActionContext,下面是上下文(Context)的结构示意图
当struts接受一个请求时,会迅速创建ActionContext,ValueStack,action。然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问。
了解了Context中的结构,我们了解一下其使用
访问上下文(Context)中的对象需要使用#符号标注命名空间,如#application、#session
另外OGNL会设定一个根对象(root对象),在struts2中根对象就是ValueStack(值栈)。如果要访问根对象(即ValueStack)中对象的属性,则可以省略#命名空间,直接访问该对象的属性即可。
在Struts2中,根对象ValueStack的实现类为OgnlValueStack,该对象不是我们想象的只存放单个值,而是存放一组对象。在OgnlValueStack类里有一个List类型的root变量,就是使用它存放一组对象。
在root变量中处于第一位的对象叫栈顶对象。通常我们在OGNL表达式里直接写上属性的名称即可访问root变量里对象的属性,搜索顺序是从栈顶对象开始寻找,如果栈顶对象不存在该属性,就会从第二个对象寻找,如果没有找到就从第三个对象寻找,依次往下访问,直到找到为止。
注意:Struts2中,OGNL表达式需要配合Struts标签才可以使用。如:<s:property value=“name”/>
在Struts2中,根对象ValueStack的实现类为OgnlValueStack,该对象不是我们想象的只存放单个值,而是存放一组对象。在OgnlValueStack类里有一个List类型的root变量,就是使用它存放一组对象。
在root变量中处于第一位的对象叫栈顶对象。通常我们在OGNL表达式里直接写上属性的名称即可访问root变量里对象的属性,搜索顺序是从栈顶对象开始寻找,如果栈顶对象不存在该属性,就会从第二个对象寻找,如果没有找到就从第三个对象寻找,依次往下访问,直到找到为止。
注意:Struts2中,OGNL表达式需要配合Struts标签才可以使用。如:<s:property value=“name”/>
由于ValueStack(值栈)是Struts2中OGNL的根对象,如果用户需要访问值栈中的对象,在JSP页面可以直接通过下面的EL表达式访问ValueStack(值栈)中对象的属性:
${foo}//获得值栈中某个对象的foo属性。
如果访问其他Context中的对象,由于他们不是根对象,所以在访问时,需要添加#前缀
application对象:用于访问ServletContext,例如#application.userName或者#application[‘userName’],相当于调用ServletContext的getAttribute(“username”)。
application对象:用于访问ServletContext,例如#application.userName或者#application[‘userName’],相当于调用ServletContext的getAttribute(“username”)。
session对象:用来访问HttpSession,例如#session.userName或者#session[‘userName’],相当于调用session.getAttribute(“userName”)。
request对象:用来访问HttpServletRequest属性(attribute)的Map,例如#request.userName或者#request[‘userName’],相当于调用request.getAttribute(“userName”)。
parameters对象:用与访问HTTP的请求参数,例如#parameters.userName或者#parameters[‘userName’],相当于调用request.getParameter(“username”)。
attr对象:用于按pagerequestsessionapplication顺序访问其属性。
看了以上一大段文字其实归纳起点就一点,el表达式中的11大内置对象在ognl表达式中换了个面孔,多了一个context ,它里面维护了session,application,request等相关对象,如果需要访问action中放在对应map中是属性,需要#对应范围来进行引用。
当然 上面的式子里面有一个特殊的例子 我们这里来重点看一下
action有自带属性name ,通过上面的例子我们可以直接用<s:property value="[0].name"/><br>来使用,但是
actioncontext.put("username", "wangwu1");到底是放在了哪里了?
看一张图<s:debug></s:debug>
很明显,他放在了context维护的那个map中,这样我们怎么访问呢?
<s:property value="username"/><br/>
<!-- valueStack中的栈顶action 中的 username 属性 如果找不到 则会去寻找context中的 username-->
接下来我们在看看el表达式
<!-- 使用el表达式 -->
${name}<br/>
${username}<br/>
<!-- el表达式也可以访问action中的属性 struts属性中封装了其 方法 如果找不到 则会去寻找context中的 name-->
${requestScope.name}<br/>
${requestScope.username}<br/>
同样的el表达式也可以达到刚才的效果,其中比较特殊的就是request,他也可以访问action ->context属性
原因是Struts2对HttpServletRequest作了进一步的封装。简略代码如下:
public class StrutsRequestWrapper extends HttpServletRequestWrapper{
public StrutsRequestWrapper(HttpServletRequest req){
super(req);
}
public Object getAttribute(String s){
…
ActionContext ctx = ActionContext.getContext();
Object attribute = super.getAttribute(s);//先从request范围获取属性值
if(ctx!=null){
if(attribute==null){//如果从request范围没有找到属性值,即从ValueStack中查找对象的属性值
…
ValueStack stack = ctx.getValueStack();
attribute = stack.findValues(s);
…
}
}
return attribute;
}
}
看完了上述几点,差不多ognl 表达式的原理已经摸的差不多了,接下来就是熟练的问题了。
四、标签使用
既然ognl标签差不多已经入门,那么我们就来用几个例子来熟悉一下
一、创建集合
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP '2.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<s:set var="map" value="#{'1':'aa','2':'bb'}" scope="session"><!-- 默认scope在context中 -->
</s:set>
<s:iterator value="#sessionScope.map" var="me">
<s:property value="#me,key"/>
</s:iterator>
<!--
<c:forEach items="${pageScope.map}" var="var">
${var.key} = ${var.value}<br/>
</c:forEach>
-->
${sessionScope.map}<!-- struts2中最好还是用他自己的标签 无法引用-->
</body>
</html>
如果需要一个集合元素的时候(例如List对象或者Map对象),可以使用OGNL中同集合相关的表达式。使用如下代码直接生成一个List对象:
<s:set name=“list” value=“{‘a’,’b’,’c’}”/>
<s:iterator value=“#list”>
<s:property/><br/>
</s:iterator>
scope:指定变量被放置的范围,该属性可以接受application、session、request、page或action。如果没有设置该属性,则默认放置在OGNL Context中。
value:赋给变量的值。如果没有设置该属性,则将ValueStack栈顶的值赋给变量。
生成一个Map对象:
二、if判断
<s:set name=“foobar” value=“#{‘foo1’:’bar1’,’foo2’:’bar2’}”/>
<s:iterator value=“#foobar”>
<s:property value=“key”/>=<s:property value=“value”/><br/>
</s:iterator>
二、if判断
对于集合类型,OGNL表达式可以使用in和not in两个元素符号。其中,in表达式用来判断某个元素是否在指定的集合对象中;not in判断某个元素是否不在指定的集合对象中,如下所示:
in表达式:
in表达式:
<s:if test=“’foo’ in {‘foo’,’bar’}”
在
</s:if>
<s:else>
不在
</s:else>
not in 表达式:
<s:if test=“’foo’ in {‘foo’,’bar’}”
不在
</s:if>
<s:else>
在
</s:else>