前言
OGNL表达式的全称是Object Graph Navigation Language,就是对象导航图语言。使用OGNL表达式可以使用简单的语法设置以及读取Java对象的值,还包括调用对象的方法,实现类型转换等功能。而且,OGNL表达式的强大还不止于此。我们知道在JSP中已经内置了表达式语言,那么使用OGNL表达式的优势是什么呢?主要是语法变得更简单以及功能的更强大。这两点会在后面的内容加以体现。
对象的操作
使用OGNL表达式实现对象的操作,包括以下几个方面:
1、访问JavaBean属性
2、调用对象的方法
3、调用静态方法和静态字段
4、调用构造方法
1、访问JavaBean属性
这是Struts2中最常使用的功能了,首先创建如下的JavaBean:
package com.rhwayfun.struts2.model;
public class User {
private Address address;
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
那么实现访问JavaBean属性有以下两个表达式:name
和addre.street
。第一个表达式的Java实现代码是user.getName()
,第二个表达式的Java实现代码是user.getAddress().getStreet()
。
2、访问对象的普通方法
访问JavaBean属性的时候,实际上就是调用了对象的getter方法,所以需要调用对象的普通方法的时候就可以使用类似Java代码的方式直接访问对象的方法。比如,需要把User对象的name属性转为大写的形式,那么OGNL表达式可以写为name.toUpperCase()
。
3、调用静态方法和静态字段
访问静态字段和方法的时候,需要使用如下的语法格式:
//访问静态方法
@class@method(args) //访问静态字段 @class@filed /* 需要注意的是,class需要给出完整的类名,如果省略不写的话,默认访问的是java.lang.Math类。 */
4、访问构造方法
访问构造方法的时候,可以使用new关键字创建一个对象,但是在使用的时候必须指出类的完整包名。
集合的操作
集合的操作是web开发中经常使用到的,下面对使用OGNL表达式创建集合做一个小结:
1、创建列表
比如需要创建一个列表,语法就是使用花括号,列表元素之间使用逗号隔开,比如:
{"liubei","guanyu","zhaoyun"}
其实现的Java代码就是创建一个ArrayList对象,把这三个元素添加到List中。访问列表元素的时候,使用索引就可以成功访问,比如需要访问第一个元素,那么表达式可以写成{"liubei","guanyu","zhaoyun"}[0]
。
2、创建数组
在OGNL中创建数组的语法与Java中是一致的,比如创建三个元素的整型数组:new int[]{1,2,3}。那么访问数组元素的时候同样是使用索引,比如访问第一个元素:new int[]{1,2,3}[0]。
3、创建Map
创建Map的语法与Java中不太一样,使用的语法如下:
#{"key1":"value1","key2":"value2",....}
在使用上述语法创建的Map与在Java中创建HashMap是一样的,然后把其中的元素放入其中。当然可以使用@class@{"key1":"value1",...}
的语法创建指定类型的Map。访问Map元素是通过key访问的,比如访问Map的第一个元素,使用表达式map["first"]
或者map.first
。
OGNL表达式实战
首先我们需要创建一个Action类,代码如下:
package com.rhwayfun.struts2.action;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.rhwayfun.struts2.model.User;
public class OgnlAction extends ActionSupport{
private static final long serialVersionUID = 1L;
private List<User> users;
private static String str = "ognl";
public String execute(){
//获取web元素,以便访问Servlet API
ActionContext context = ActionContext.getContext();
//获取request对象
@SuppressWarnings("unchecked")
Map<String, String> request = (Map<String, String>) context.get("request");
//获取session对象
Map<String, Object> session = context.getSession();
//获取Application对象
Map<String, Object> application = context.getApplication();
//分别在三个域对象中设置一个值
request.put("msg", "我是request元素");
session.put("msg", "我是session元素");
application.put("msg", "我是application元素");
//创建两个User对象
users = new ArrayList<User>();
User u1 = new User();
u1.setName("zhaoyun");
u1.setAge(23);
User u2 = new User();
u2.setName("zhangfei");
u2.setAge(26);
//添加到集合中
users.add(u1);
users.add(u2);
return SUCCESS;
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
然后在struts.xml文件配置该action,如下:
<!-- OGNL表达式测试 -->
<action name="ognl" class="com.rhwayfun.struts2.action.OgnlAction">
<result>/ognl.jsp</result>
</action>
接着编写ognl.jsp页面,代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>OGNL表达式</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<p>1、访问web元素中的值</p>
<p>request:<s:property value="#request.msg"/></p>
<p>session:<s:property value="#session.msg"/></p>
<p>application:<s:property value="#application.msg"/></p>
<hr>
<p>2、访问list</p>
<p>
<s:iterator value="users" var="u">
<s:property/><br>
</s:iterator>
</p>
<p>3、通过OGNL表达式直接创建列表并访问</p>
<p>
创建一个列表:{'赵云','刘备','张飞'}<br>
<s:set name="list" value="{'赵云','刘备','张飞'}"></s:set>
<!-- 遍历该创建的列表 -->
<s:iterator value="#list" var="o">
<s:property/><br>
</s:iterator><br>
访问列表的元素个数:<s:property value="#list.size()"/><br>
访问列表的第二个元素:<s:property value="#list[1]"/>
</p>
<p>4、创建一个数组并访问</p>
<p>
<s:set name="array" value="new int[]{1,2,3}"></s:set>
<s:iterator value="#array" var="o">
<s:property/>
</s:iterator>
</p>
<p>5、构造map并访问</p>
<p>
<s:set name="map" value="#{'中国':'北京','美国':'纽约','俄罗斯':'莫斯科' }"></s:set>
<!-- 遍历该map -->
遍历该map(第一种方式):
<s:iterator value="#map" var="m">
<s:property/>
</s:iterator>
<br>
遍历该map(第二种方式):
<s:iterator value="#map" var="m">
<s:property value="key"/>=<s:property value="value"/>
</s:iterator>
<br>
访问第一个元素(不使用%):<s:property value="#map['中国']"/><br>
访问第一个元素(使用%):<s:property value="%{#map['中国']}"/><br>
获取该map所有的key:<s:property value="#map.keys"/><br>
获取该map所有的value:<s:property value="#map.values"/>
</p>
<p>6、访问静态方法和字段</p>
<p>
<code>访问Math类的floor方法(由于Math类是Struts2中默认的类<br>,
所以在调用此类方法的时候,其中的class可以不写出)</code><br>
访问静态方法::
<s:property value="@java.lang.Math@floor(32.56)"/>
等价于
<s:property value="@@floor(32.56)"/>
<br>
<s:property value="@java.util.Calendar@getInstance()"/><br>
访问静态属性:
<s:property value="@com.rhwayfun.struts2.action.OgnlAction@str"/>
</p>
<p>7、访问构造方法</p>
<p>
访问User类的有参构造方法:
<s:property value="new com.rhwayfun.struts2.model.User('张角',43).name"/>
</p>
<p>8、if/else判断语句</p>
<p>
<s:if test="'关羽'in {'关羽','赵云','黄忠'}">
关羽在集合中
</s:if>
<s:elseif test="'赵云' in {'赵云','关羽','黄忠'}">
赵云在集合中
</s:elseif>
<s:else>
关羽不在集合中
</s:else>
<br>
<s:if test="#request.msg not in #list">
请求消息不在集合中
</s:if>
</p>
<p>9、迭代标签完整版</p>
<p>
创建一个list列表:abcde<br><s:set name="list2" value="{'a','b','c','d','e'}"></s:set>
<s:iterator value="#list2" var="c" status="s">
索引:<s:property value="#s.getIndex()"/> 值:<s:property/>
当前迭代数量:<s:property value="#s.getCount()"/><br>
</s:iterator>
</p>
<p>10、获取属性范围内的值</p>
<p>
<% request.setAttribute("req", "request对象"); request.getSession().setAttribute("ses", "session对象"); request.getSession().getServletContext().setAttribute("app", "application对象"); %>
request:<s:property value="#request.req"/><br>
session:<s:property value="#session.ses"/><br>
application:<s:property value="#application.app"/>
</p>
</body>
</html>
通过以上的ognl.jsp页面对平时开发中经常使用的语法进行了归类和测试,具体的内容已经在代码给出注释了,这里不再赘述。
Struts 2中的值栈
值栈就是用来存放对象的,类似于正常的栈,符合先进后出的特性。在值栈中可以存放、查询和删除对象。值栈是Struts 2框架的核心。值栈实际上是一个接口(该接口是com.opensymphony.xwork2.util.ValueStack),我们平时在开发是使用的<s:debug>
标签实际上使用的是该接口的实现类,也就是com.opensymphony.xwork2.ognl.OgnlValueStack类。