OGNL入门(转)

来源:互联网 发布:灯光矩阵 编辑:程序博客网 时间:2024/06/11 09:48
  1. package org.darkness.ognl.test;   
  2.   
  3. import java.util.ArrayList;   
  4. import java.util.HashMap;   
  5. import java.util.List;   
  6. import java.util.Map;   
  7.   
  8. import junit.framework.TestCase;   
  9. import ognl.Ognl;   
  10.   
  11. import org.darkness.oa.model.Person;   
  12. import org.darkness.oa.model.User;   
  13.   
  14. public class OgnlTest extends TestCase {   
  15.        
  16.     // ***************** root对象的概念 ******************* //   
  17.     public void testOgnl_01() throws Exception{   
  18.         User user = new User();   
  19.         user.setUsername("暗之幻影");   
  20.            
  21.         //相当于调用user.getUsername()方法   
  22.         String value = (String)Ognl.getValue("username", user);   
  23.         System.out.println(value);   
  24.     }   
  25.        
  26.     public void testOgnl_02() throws Exception{   
  27.         User user = new User();   
  28.         Person p = new Person();   
  29.         p.setName("暗之幻影");   
  30.         user.setPerson(p);   
  31.            
  32.         //相当于调用user.getPerson().getName()方法   
  33.         String value = (String)Ognl.getValue("person.name", user);   
  34.         System.out.println(value);   
  35.     }   
  36.        
  37.     public void testOgnl_03() throws Exception{   
  38.         User user = new User();   
  39.         Person p = new Person();   
  40.         p.setName("暗之幻影");   
  41.         user.setPerson(p);   
  42.            
  43.         //可以使用#root来引用根对象,相当于调用user.getPerson().getName()方法   
  44.         String value = (String)Ognl.getValue("#root.person.name", user);   
  45.         System.out.println(value);   
  46.     }   
  47.        
  48.     // *********************** context的概念 **********************//   
  49.     public void testOgnl_04() throws Exception{   
  50.         Person p1 = new Person();   
  51.         Person p2 = new Person();   
  52.         p1.setName("风");   
  53.         p2.setName("云");   
  54.   
  55.         Map<String,Person> context = new HashMap<String,Person>();   
  56.         context.put("p1", p1);   
  57.         context.put("p2", p2);   
  58.            
  59.         // 需要加上#才表示到context中取数据,否则表示从根目录下取值   
  60.         String value = (String)Ognl.getValue("#p1.name + ',' + #p2.name", context, new Object());   
  61.         System.out.println(value);   
  62.     }   
  63.        
  64.     public void testOgnl_05() throws Exception{   
  65.         Person p1 = new Person();   
  66.         Person p2 = new Person();   
  67.         p1.setName("风");   
  68.         p2.setName("云");   
  69.            
  70.         Map<String,Person> context = new HashMap<String,Person>();   
  71.         context.put("p1", p1);   
  72.         context.put("p2", p2);   
  73.            
  74.         User root = new User();   
  75.         root.setUsername("雨");   
  76.            
  77.         String value = (String)Ognl.getValue("#p1.name + ',' + #p2.name + ',' + username", context, root);   
  78.         System.out.println(value);   
  79.     }   
  80.        
  81.     // ******************* OGNL赋值操作 ************************//   
  82.     public void testOgnl_06() throws Exception{   
  83.         User user = new User();   
  84.            
  85.         //给root对象的属性赋值,相当于调用user.setUsername()   
  86.         Ognl.setValue("username", user, "暗之幻影");   
  87.            
  88.         System.out.println(user.getUsername());   
  89.     }   
  90.        
  91.     public void testOgnl_07() throws Exception{   
  92.         User user = new User();   
  93.   
  94.         Map<String, User> context = new HashMap<String, User>();   
  95.         context.put("u", user);   
  96.            
  97.         //给context中的对象属性赋值,相当于调用user.setUsername()   
  98.         Ognl.setValue("#u.username", context, new Object(), "暗之幻影");   
  99.            
  100.         System.out.println(user.getUsername());   
  101.     }   
  102.        
  103.     public void testOgnl_08() throws Exception{   
  104.         User user = new User();   
  105.            
  106.         Map<String, User> context = new HashMap<String, User>();   
  107.         context.put("u", user);   
  108.            
  109.         //给context中的对象属性赋值,相当于调用user.setUsername()   
  110.         //在表达式中使用=赋值操作符来赋值   
  111.         Ognl.getValue("#u.username = '暗之幻影'",context, new Object());   
  112.            
  113.         System.out.println(user.getUsername());   
  114.     }   
  115.        
  116.     public void testOgnl_09() throws Exception{   
  117.         User user = new User();   
  118.         Person p = new Person();   
  119.            
  120.         Map<String,Object> context = new HashMap<String,Object>();   
  121.         context.put("u", user);   
  122.         context.put("p", p);   
  123.            
  124.         //给context中的对象属性赋值,相当于调用user.setUsername()   
  125.         //在表达式中使用=赋值操作符来赋值   
  126.         Ognl.getValue("#u.username = '风',#p.name = '云'",context, new Object());   
  127.            
  128.         System.out.println(user.getUsername()+","+p.getName());   
  129.     }   
  130.        
  131.     //****************** 使用OGNL调用对象的方法 **********************//   
  132.     public void testOgnl_10() throws Exception{   
  133.         User user = new User();   
  134.         user.setUsername("暗之幻影");   
  135.            
  136.         String value = (String)Ognl.getValue("getUsername()", user);   
  137.         System.out.println(value);   
  138.     }   
  139.        
  140.     public void testOgnl_11() throws Exception{   
  141.         User user = new User();   
  142.            
  143.         Ognl.getValue("setUsername('暗之幻影')", user);   
  144.         System.out.println(user.getUsername());   
  145.     }   
  146.        
  147.     // ******************* OGNL调用类变量、静态方法 *************************//   
  148.     public void testOgnl_12() throws Exception{   
  149.         User user = new User();   
  150.            
  151.         Ognl.getValue("setUsername('暗之幻影')", user);   
  152.         Ognl.getValue("@System@out.println(username)", user);   
  153.     }   
  154.        
  155.     public void testOgnl_13() throws Exception{   
  156.         User user = new User();   
  157.            
  158.         Ognl.getValue("setUsername('暗之幻影')", user);   
  159.         Ognl.getValue("@System@out.println(@org.darkness.struts2.test.Utils@toLowerCase(username))", user);   
  160.     }   
  161.        
  162.     // ********************* OGNL中的this表达式 **********************//   
  163.     public void testOgnl_14() throws Exception{   
  164.         Object root = new Object();   
  165.         Map context = new HashMap();   
  166.            
  167.         List values = new ArrayList();   
  168.         for(int i=0; i<11; i++){   
  169.             values.add(i);   
  170.         }   
  171.         context.put("values", values);   
  172.            
  173.         Ognl.getValue("@System@out.println(#values.size.(#this > 10 ? /"大于10/" : '不大于10'))", context, root);   
  174.            
  175.     }   
  176.        
  177.     public void testOgnl_15() throws Exception{   
  178.         User user = new User();   
  179.            
  180.         Ognl.getValue("setUsername('暗之幻影')", user);   
  181.         Ognl.getValue("@System@out.println(#this.username)", user);   
  182.     }   
  183.        
  184.     public void testOgnl_16() throws Exception{   
  185.         User user = new User();   
  186.            
  187.         Ognl.getValue("setUsername('暗之幻影')", user);   
  188.         Ognl.getValue("@System@out.println(username.(#this.toLowerCase()))", user);   
  189.     }   
  190.        
  191.     // ******************* 如何把表达式的解释结果作为另外一个表达式,OGNL中括号的使用 **********************//   
  192.     public void testOgnl_17() throws Exception{   
  193.         Object root = new Object();   
  194.         Map context = new HashMap();   
  195.         User u = new User();   
  196.         u.setUsername("暗之幻影");   
  197.         context.put("u", u);   
  198.         context.put("fact""username");   
  199.            
  200.         /**  
  201.          * 1、首先把#fact表达式进行解释,得到一个值:username  
  202.          * 2、解释括号中的表达式#u,其结果是user对象  
  203.          * 3、把括号中表达式的结果作为root对象,解释在第一步中得到的结果(即把第一步的结果看成另外一个表达式)   
  204.          */  
  205.         String value = (String)Ognl.getValue("#fact(#u)", context, root);   
  206.         System.out.println(value);   
  207.     }   
  208.        
  209.     public void testOgnl_18() throws Exception{   
  210.         Person person = new Person();   
  211.         Map context = new HashMap();   
  212.         User u = new User();   
  213.         u.setUsername("暗之幻影");   
  214.         context.put("u", u);   
  215.            
  216.         /**  
  217.          * 相当于调用person这个根对象的fact方法,并把#u的解释结果作为参数传入此方法   
  218.          */  
  219.         String value = (String)Ognl.getValue("fact(#u)", context, person);   
  220.         System.out.println(value); //输出是 "暗之幻影,"   
  221.     }   
  222.        
  223.     public void testOgnl_19() throws Exception{   
  224.         Person person = new Person();   
  225.         Map context = new HashMap();   
  226.         User u = new User();   
  227.         u.setUsername("暗之幻影");   
  228.         context.put("u", u);   
  229.            
  230.         /**  
  231.          * 1、先计算表达式fact,得到结果是:username  
  232.          * 2、解释括号中的表达式#u,其结果是user对象  
  233.          * 3、把括号中表达式的结果作为root对象,解释在第一步中得到的结果(即把第一步的结果看成另外一个表达式)  
  234.          */  
  235.         String value = (String)Ognl.getValue("(fact)(#u)", context, person);   
  236.         System.out.println(value); //输出"暗之幻影"   
  237.     }   
  238.        
  239.     // ********************* OGNL访问集合元素 **************************//   
  240.     public void testOgnl_20() throws Exception{   
  241.         Object root = new Object();   
  242.         Map context = new HashMap();   
  243.            
  244.         //用OGNL创建List对象   
  245.         List listvalue = (List)Ognl.getValue("{123,'暗之幻影','风之水影'}", context, root);   
  246.         context.put("listvalue", listvalue);   
  247.            
  248.         //用OGNL创建数组   
  249.         int[] intarray= (int[])Ognl.getValue("new int[]{23,45,67}", context, root);   
  250.         context.put("intarray", intarray);   
  251.            
  252.         //用OGNL创建Map对象   
  253.         Map mapvalue = (Map)Ognl.getValue("#{'listvalue':#listvalue,'intarray':#intarray}", context, root);   
  254.         context.put("mapvalue", mapvalue);   
  255.            
  256.         Ognl.getValue("@System@out.println(#listvalue[0])", context, root);   
  257.         Ognl.getValue("@System@out.println(#intarray[1])", context, root);   
  258.         Ognl.getValue("@System@out.println(#mapvalue['intarray'][2])", context, root);   
  259.         Ognl.getValue("@System@out.println(#mapvalue.intarray[0])", context, root);   
  260.     }   
  261. }  

经常有同事问我关于Struts2标签中,OGNL的使用问题,最近抽空整理了理解和使用OGNL的要点,分享一下

1、理解Struts2中的ValueStack

ValueStack实际是一个接口,在Struts2中利用OGNL时,实际上使用的是实现了该接口的OgnlValueStack类,这个类是Struts2利用OGNL的基础。OgnlValueStack类的主要属性关系图如下:

                                                           |
                                                          |--application
                                                          |
                                                           |--session
context map (OgnlValueStack属性)--|
                                                          |--value stack (OgnlValueStack的root属性,实际是个ArrayList)
                                                          |
                                                          |--request
                                                          |
                                                          |--parameters
                                                          |
                                                          |--attr (searches page, request, session, then application scopes)

OgnlValueStack类包含两个重要的属性,一个root和一个context。其中root本质上是一个ArrayList,而context是一个Map(更确切的说是一个OgnlContext对象)。在这个OgnlContext对象(context)中,有一个默认的顶层对象root,OGNL访问context中这个默认顶层对象中的元素时,是不需要#号的,直接通过元素的名称来进行访问,而访问其他对象时,如request、session、attr等,则需要#号引用。Struts2将OgnlValueStack的root对象赋值给了context中的root对象,在OgnlValueStack的root对象中,保存着调用Action的实例,因此,在页面上通过Struts2标签访问Action的属性时,就不需要通过#号来引用。

2、OgnlValueStack与ActionContext的关系

在Struts2中,OgnlValueStack是ActionContext的基础,在ActionContext中,有一个Map类型的属性context,而这个context就是OgnlValueStack的context对象,ActionContext中的getSession()、getApplication()等方法,底层都是通过context.get()来实现的。

OGNL全称为Object-Graph Navigation Language,是一种表达式语言(EL)。

EL的支持者认为,在JSP页面中应尽可能地避免 <% %> 这样的标记,而代之以Tag,以使页面更简洁,并体现页面与后台代码分离的设计原则。对此我持保留意见,因为我并不认为使用Tag后的页面的可读性要高于使用<% %>。

Struts 2支持如下几种EL:

  • OGNL(Object-Graph Navigation Language): 可以方便地操作对象属性的开源表达式语言
  • JSTL(JSP Standard Tag Library): JSP 2.0集成的标准的表达式语言
  • Groovy: 基于Java平台的动态语言,它具有时下比较流行的动态语言(如Python、Ruby和Smarttalk等)的一些新特性
  • Velocity: 严格来说不是表达式语言,它是一种基于Java的模板匹配引擎,据说其性能要比JSP好

Struts 2默认的表达式语言是OGNL,原因是它相对其它表达式语言具有下面几大优势:

  • 支持对象方法调用,如xxx.doSomeSpecial();
  • 支持类静态的方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名 | 值名],例如: @java.lang.String@format('foo %s', 'bar')或 @tutorial.MyConstant@APP_NAME;
  • 支持赋值操作和表达式串联,如price=100, discount=0.8, calculatePrice(),这个表达式会返回80;
  • 访问OGNL上下文(OGNL context)和ActionContext;
  • 操作集合对象。

OGNL是通常要结合Struts 2的标志一起使用,如<s:property value="xx" />等。大家经常遇到的问题是#、%和$这三个符号的使用。下面我讲述这个问题:

4.1 “#”的用途

访问OGNL上下文和Action上下文

#相当于ActionContext.getContext();下表有几个ActionContext中有用的属性:

  • parameters:包含当前HTTP请求参数的Map,#parameters.id[0]作用相当于request.getParameter("id")
  • request:包含当前HttpServletRequest的属性(attribute)的Map,#request.userName相当于request.getAttribute("userName")
  • session:包含当前HttpSession的属性(attribute)的Ma, #session.userName相当于session.getAttribute("userName")
  • application:包含当前应用的ServletContext的属性(attribute)的Map,#application.userName相当于application.getAttribute("userName")
  • attr:用于按request > session > application顺序访问其属性(attribute),#attr.userName相当于按顺序在以上三个范围(scope)内读取userName属性,直到找到为止

过滤和投影(projecting)集合

如books.{?#this.price<100}

构造Map

如#{'foo1':'bar1', 'foo2':'bar2'}

在此我演示一下这三种用途:

Book.java

这是一个Bean,用于描述一本书的信息

package example;

public class Book {
private String isbn;
private String title;
private double price;

public Book() {
}

public Book(String isbn, String title, double price) {
this.isbn = isbn;
this.title = title;
this.price = price;
}

public String getIsbn() {
return isbn;
}

public void setIsbn(String isbn) {
this.isbn = isbn;
}

public double getPrice() {
return price;
}

public void setPrice(double price) {
this.price = price;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}
}

BookDao.java

一个伪DAO类

package example;

import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class BookDao
{
private static final BookDao instance;
private static final ConcurrentMap<String, Book> data;

static {
instance = new BookDao();
data = new ConcurrentHashMap<String, Book>();
data.put("978-0735619678", new Book("978-0735619678", "Code Complete, Second Edition", 32.99));
data.put("978-0596007867", new Book("978-0596007867", "The Art of Project Management", 35.96));
data.put("978-0201633610", new Book("978-0201633610", "Design Patterns: Elements of Reusable Object-Oriented Software", 43.19));
data.put("978-0596527341", new Book("978-0596527341", "Information Architecture for the World Wide Web: Designing Large-Scale Web Sites", 25.19));
data.put("978-0735605350", new Book("978-0735605350", "Software Estimation: Demystifying the Black Art", 25.19));
}

private BookDao() {}

public static BookDao getInstance() {
return instance;
}

public Collection<Book> getBooks() {
return data.values();
}

public Book getBook(String isbn) {
return data.get(isbn);
}

public void storeBook(Book book) {
data.put(book.getIsbn(), book);
}

public void removeBook(String isbn) {
data.remove(isbn);
}

public void removeBooks(String[] isbns) {
for(String isbn : isbns) {
data.remove(isbn);
}
}
}

OgnlAction.java

演示OGNL的Servlet类

package example;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.util.ServletContextAware;

import com.opensymphony.xwork2.ActionSupport;

public class OgnlAction extends ActionSupport implements ServletRequestAware, SessionAware, ServletContextAware {
private static final long serialVersionUID = 1L;

private HttpServletRequest request;
private Map<String, String> session;
private ServletContext application;
private List<Book> books;

public void setServletRequest(HttpServletRequest request) {
this.request = request;
}

@SuppressWarnings("unchecked")
public void setSession(Map session) {
this.session = session;
}

public void setServletContext(ServletContext application) {
this.application = application;
}

public List<Book> getBooks() {
return books;
}

@Override
public String execute() {
request.setAttribute("userName", "Max From request");
session.put("userName", "Max From session");
application.setAttribute("userName", "Max From application");

books = new LinkedList<Book>();
books.add(new Book("978-0735619678", "Code Complete, Second Edition", 32.99));
books.add(new Book("978-0596007867", "The Art of Project Management", 35.96));
books.add(new Book("978-0201633610", "Design Patterns: Elements of Reusable Object-Oriented Software", 43.19));
books.add(new Book("978-0596527341", "Information Architecture for the World Wide Web: Designing Large-Scale Web Sites", 25.19));
books.add(new Book("978-0735605350", "Software Estimation: Demystifying the Black Art", 25.19));

return SUCCESS;
}
}

Ognl.jsp

演示OGNL的JSP

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Struts OGNL Demo</title>
</head>
<body>
<h3>访问OGNL上下文和Action上下文</h3>
<p>parameters: <s:property value="#parameters.userName" /></p>
<p>request.userName: <s:property value="#request.userName" /></p>
<p>session.userName: <s:property value="#session.userName" /></p>
<p>application.userName: <s:property value="#application.userName" /></p>
<p>attr.userName: <s:property value="#attr.userName" /></p>
<hr />
<h3>用于过滤和投影(projecting)集合</h3>
<p>Books more than $35</p>
<ul>
<s:iterator value="books.{?#this.price > 35}">
<li><s:property value="title" /> - ___FCKpd___3lt;s:property value="price" /></li>
</s:iterator>
</ul>
<p>The price of "Code Complete, Second Edition" is: <s:property value="books.{?#this.title=='Code Complete, Second Edition'}.{price}[0]"/></p>
<hr />
<h3>构造Map</h3>
<s:set name="foobar" value="#{'foo1':'bar1', 'foo2':'bar2'}" />
<p>The value of key "foo1" is <s:property value="#foobar['foo1']" /></p>
</body>
</html>

example.xml

struts2 的MVC配置文件

<action name="Ognl" class="example.OgnlAction">
<result>/Ognl.jsp</result>
</action>

4.2 %的用法

“%”符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。例如在Ognl.jsp中加入以下代码:

<h3>%的用途</h3>
<p><s:url value="#foobar['foo1']" /></p>
<p><s:url value="%{#foobar['foo1']}" /></p>

刷新页面,显示以下内容

%的用途

#foobar['foo1']

bar1

4.3 $的用法

“$”有两个主要的用途:

  1. 用于在国际化资源文件中,引用OGNL表达式
  2. Struts 2配置文件中,引用OGNL表达式,如
<action name="AddPhoto" class="addPhoto">
<interceptor-ref name="fileUploadStack" />
<result type="redirect">ListPhotos.action?albumId=${albumId}</result>
</action>

原创粉丝点击