@liayun
2016-10-03T16:11:42.000000Z
字数 6125
阅读 1363
Struts2框架学习
这时Struts2框架进阶五,本文将详细讲解OGNL表达式语言。
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。Struts2框架使用OGNL作为默认的表达式语言。相对EL表达式,它提供了平时我们需要的一些功能,如:
OGNL有一个上下文(Context)的概念,说白了上下文就是一个Map结构,它实现了java.utils.Map接口,在Struts2中上下文(Context)的实现为ActionContext,下面是上下文(Context)的结构示意图:
插入上下文(Context)的结构示意图
当Struts2接收一个请求时,它迅速创建ActionContext,ValueStack,action对象,然后action被存到ValueStack,所以action的实例变量可以被OGNL访问到。
访问上下文(Context)中的对象需要使用#符号标注命名空间,如#application、#session。
另外OGNL会设定一个根对象(root对象),在Struts2中根对象就是ValueStack(值栈)。如果要访问根对象(即ValueStack)中对象的属性,则可以省略#命名空间,直接访问该对象的属性即可。
在Struts2中,根对象ValueStack的实现类为OgnlValueStack,该对象不是我们想象的只存放单个值,而是存放一组对象。在OgnlValueStack类里有一个List类型的root变量,就是使用它来存放一组对象的。
记得插入图片
在root变量中处于第一位的对象叫栈顶对象。通常我们在OGNL表达式直接写上属性的名称即可访问root变量里对象的属性,搜索顺序是从栈顶对象开始寻找,如果栈顶对象不存在该属性,就会从第二个对象寻找,如果没有找到就从第三个对象寻找,依次往下访问,直到找到为止。
大家注意:在Struts2中,OGNL表达式需要配合Struts2标签才可以使用。如:
<s:property value="name" />
value属性默认接收的是OGNL表达式。
标准的OGNL会设定一个根对象(root对象)。假设使用标准OGNL表达式来求值(不使用Struts2的OGNL表达式),如果OGNL上下文(OgnlContext Map类型)有两个对象:foo对象,在Ognl Context中名称为foo;bar对象,在Ognl Context中名称为bar,同时foo对象被设置为根对象(root),则利用下面的OGNL表达式求值:
#foo.blah // 返回foo.getBlah()
#bar.blah // 返回bar.getBlah()
blah // 返回foo.getBlah(),因为foo为根对象
记住:访问Ognl Context中的对象需要使用#符号标注命名空间,如#bar,如果要访问的属性属于根对象,则可以省略命名空间,直接访问该属性。
由于ValueStack(值栈)是Struts2中OGNL的根对象,如果用户需要访问值栈中的对象,则可以直接通过下面的EL表达式访问ValueStack(值栈)中对象的属性:
${foo } // 获得值栈中某个对象的foo属性 例如:${message }
我们举例来说明这一点。首先在cn.itcast.action包下创建一个Action——PersonListAction.java,该Action类的具体代码如下:
public class PersonListAction {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String execute() {
this.name = "李阿昀";
return "list";
}
}
接下来就在struts.xml配置文件中配置该action。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="itcast" namespace="/itcast" extends="struts-default">
<action name="list" class="cn.itcast.action.PersonListAction">
<result name="list">/WEB-INF/page/personlist.jsp</result>
</action>
</package>
</struts>
顺其自然地,我们要在WEB-INF/page/目录下创建出personlist.jsp页面。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!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>
${name }<br/>
</body>
</html>
我们通过浏览器访问http://localhost:8080/struts2_ognl/itcast/list.action该URL地址,结果为:
记得插入图片
我们可能会思考一个问题,为何使用EL表达式能够访问ValueStack中对象的属性呢?
翻阅Struts2的源码,我们就会发现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.findValue(s);
......
}
}
return attribute;
}
}
所以,如果用户需要访问值栈中的对象,则可以直接通过EL表达式访问ValueStack(值栈)中对象的属性。
如果访问其他Context中的对象,由于不是根对象,在访问时,需要加#前缀。
application对象:用于访问ServletContext,例如
#application.userName
或者
#application['userName']
相当于调用Servlet的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")。
如果需要一个集合元素的时候(例如List对象或者Map对象),可以使用OGNL中同集合相关的表达式。
我们可使用如下代码直接生成一个List对象:
<s:set var="list" value="{'第一个','第二个','第三个'}" />
<s:iterator value="#list">
<s:property /><br>
</s:iterator>
set标签用于将某个值放入指定范围。
property标签用于输出指定值。如:
<s:set name="name" value="'kk'" />
<s:property value="#name"/>
为了验证这一点,我们在WebRoot根目录下创建一个test.jsp页面,如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!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>测试页面</title>
</head>
<body>
<!-- 如何使用ognl表达式来创建一个List类型集合的对象 -->
<s:set var="list" value="{'第一个','第二个','第三个'}" />
<!-- #list为ognl表达式,s:iterator标签在迭代集合时有个特点:会把当前迭代的对象放在值栈的栈顶中 -->
<s:iterator value="#list">
<s:property /><br/>
</s:iterator>
</body>
</html>
注意两点:
<s:iterator>
标签在迭代集合时有个特点:会把当前迭代的对象放在值栈的栈顶中。这样,我们通过浏览器访问http://localhost:8080/struts2_ognl/test.jsp该URL地址,结果是:
记得插图
我们可使用如下代码直接生成一个Map对象:
<s:set var="maps" value="#{'key1':90,'key2':35,'key3':12}" />
<s:iterator value="#maps">
<s:property value="key" />=<s:property value="value" /><br/>
</s:iterator>
为了验证这一点,我们将test.jsp页面的内容修改为:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!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>测试页面</title>
</head>
<body>
<!-- 如何使用ognl表达式来创建一个Map类型集合的对象 -->
<s:set var="maps" value="#{'key1':90,'key2':35,'key3':12}" />
<!-- #maps为ognl表达式,s:iterator标签在迭代集合时有个特点:会把当前迭代的对象放在值栈的栈顶中,就可以采用ognl表达式直接访问对象的属性 -->
<s:iterator value="#maps">
<s:property value="key" />=<s:property value="value" /><br/>
</s:iterator>
</body>
</html>
这样,我们通过浏览器访问http://localhost:8080/struts2_ognl/test.jsp该URL地址,结果是:
记得插图