随笔-126  评论-247  文章-5  trackbacks-0

OGNL

OGNL ( Object Graph Navigation Language ),对象图导航语言。这是一种强大的表达式语言,通过它可以非常方便的来操作对象属性。
在 Struts2 中,OGNL 需要和 Struts2 标签库配套来使用。

OGNL context

                               |
                               | -- application
                               |
                               | -- session
                               |
                               | -- value  stack ( root )
context  map  ---- |
                               | -- request
                               |
                               | -- parameters
                               |
                               | -- attr ( searches page, request, session, then application scopes )
                               |
Struts2 框架将 OGNL context 设置为我们的 ActionContext,并将 ValueStack 作为 OGNL 的根对象。而 Action 则置于 ValueStack 的最顶层。
除此之外,Struts2 框架还把代表 application、request、session 对象的 Map 对象也放到 ActionContext 中,使得 Action 与 Servlet API 解耦。
名称 描述
ValueStack 值栈,作为 OGNL 上下文的根对象。通过 KEY 来访问,非根对象需要用 #KEY 来访问
parameters Map 类型,封装了请求中的所有参数。访问 #parameters.name 相当于调用 HttpServletRequest.getParameter( )
request Map 类型,封装了 request 对象中的所有属性。访问 #request.name 相当于调用 HttpServletRequest.getAttribute( )
session Map 类型,封装了 session 对象中的所有属性。访问 #session.name 相当于调用 HttpSession.getAttribute( )
application Map 类型,封装了 application 对象中的所有属性。访问 #application.name 相当于调用 ServletContext.getAttribute( )
attr Map 类型,依次从 page、request、session、application 对象中检索属性的值

OGNL 访问 Action 中的数据

Action 位于值栈的栈顶位置,而值栈又是 OGNL 的根对象,因此,在 OGNL 表达式中可直接使用属性名称来访问 Action 当中的数据。如:
<s:property value="name" />
实际上,这里是通过调用 Action 当中的 getName( ) 方法来获取得到数据的,而不管 Action 当中是否有一个名称为 name 的属性变量。
因此,如果需要在页面中获取得到 Action 当中的数据,你只需要为你的 Action 类编写 getXX( ) 方法就可以了。

测试环境

package fan.tutorial.model;

import java.util.Set;

public class Person {

    private String sex;
    private String name;
    private IDCard idcard;
    private Set<Address> addressSet;
    public static final double VERSION = 1.0;
    
    public Person(){}
    
    public Person(String name, String sex, IDCard idcard, Set<Address> addressSet){
        this.sex = sex;
        this.name = name;
        this.idcard = idcard;
        this.addressSet = addressSet;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Address> getAddressSet() {
        return addressSet;
    }

    public void setAddressSet(Set<Address> addressSet) {
        this.addressSet = addressSet;
    }

    public IDCard getIdcard() {
        return idcard;
    }

    public void setIdcard(IDCard idcard) {
        this.idcard = idcard;
    }

    public static double getVersion() {
        return VERSION;
    }
}
package fan.tutorial.model;

public class IDCard {

    private long number;
    
    public IDCard(){}
    
    public IDCard(long number){
        this.number = number;
    }

    public long getNumber() {
        return number;
    }

    public void setNumber(long number) {
        this.number = number;
    }
}
package fan.tutorial.model;

public class Address {

    private String name;
    
    public Address(){}
    
    public Address(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package fan.tutorial.action;

import java.util.Map;
import java.util.Set;
import java.util.List;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import fan.tutorial.model.IDCard;
import fan.tutorial.model.Person;
import fan.tutorial.model.Address;
import com.opensymphony.xwork2.Action;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.interceptor.ApplicationAware;

public class DataAction implements Action, RequestAware, SessionAware, ApplicationAware {
    
    private String author;
    private String subject;
    private Person person;
    private List<Person> personList;
    private Map<String, String> map;
    private Map<String, Object> request;
    private Map<String, Object> session;
    private Map<String, Object> application;
    private int[] array = {8, 0, 9, 1, 3, 4, 2, 5, 7, 6};

    public String execute() throws Exception {
        
        subject = "fan-tutorial";
        
        Set<Address> addressSet = new HashSet<Address>(2);
        addressSet.add(new Address("广东茂名"));
        addressSet.add(new Address("广东广州"));
        person = new Person("fan", "male", new IDCard(3115981L), addressSet);
        
        personList = new ArrayList<Person>(3);
        addressSet = new HashSet<Address>(1);
        addressSet.add(new Address("云南丽江"));
        personList.add(person);
        personList.add(new Person("chen", "female", new IDCard(3575982L), addressSet));
        addressSet = new HashSet<Address>(1);
        addressSet.add(new Address("广东潮汕"));
        personList.add(new Person("chai", "female", new IDCard(3115983L), addressSet));
        
        map = new LinkedHashMap<String, String>(2);
        map.put("username", "fan");
        map.put("password", "yun");
        
        request.put("message", "hey request");
        session.put("message", "hey session");
        application.put("message", "hey application");
        
        return SUCCESS;
        
    }

    public String getSubject() {
        return subject;
    }

    public Person getPerson() {
        return person;
    }

    public List<Person> getPersonList() {
        return personList;
    }

    public int[] getArray() {
        return array;
    }

    public Map<String, String> getMap() {
        return map;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public void setRequest(Map<String, Object> request) {
        this.request = request;
    }

    public void setSession(Map<String, Object> session) {
        this.session = session;
    }

    public void setApplication(Map<String, Object> application) {
        this.application = application;
    }
}
<struts>

  <constant name="struts.ognl.allowStaticMethodAccess" value="true"/>
  
  <package name="default" extends="struts-default">
    <default-action-ref name="defaultAction" />
    <action name="defaultAction">
      <result type="redirect">test?author=fan</result>
    </action>
    <action name="test" class="fan.tutorial.action.DataAction">
      <result>/index.jsp</result>
    </action>
  </package>

</struts>

OGNL 访问对象属性

<s:property value="subject"/>
<s:property value="person.name"/>
<s:property value="person.idcard.number"/>

OGNL 调用方法

<s:property value="person.getName()"/>
<s:property value="person.name.toUpperCase()"/>

OGNL 调用静态属性

<s:property value="@fan.tutorial.model.Person@VERSION"/>

OGNL 调用静态方法

<!-- 在 struts.xml 中添加下面这行配置 -->
<!-- <constant name="struts.ognl.allowStaticMethodAccess" value="true"/> -->
<s:property value="@fan.tutorial.model.Person@getVersion()"/>

OGNL 调用构造方法

<s:property value="new fan.tutorial.model.Address('广东茂名').name"/>

OGNL 使用索引访问数组和列表

<s:property value="array[0]"/>
<s:property value="personList[0].name"/>

OGNL 操作符运算

<s:property value="array[0] + 1"/>
<s:property value="array[0] - 1"/>
<s:property value="array[0] * 2"/>
<s:property value="array[0] / 2"/>
<s:property value="array[0] % 3"/>

OGNL 逻辑运算符

<s:set name="x" value="5"/>
<s:property value="#x in array"/>
<s:property value="#x not in array"/>
<s:property value="#x > array[0]"/>
<s:property value="#x >= array[0]"/>
<s:property value="#x < array[0]"/>
<s:property value="#x <= array[0]"/>
<s:property value="#x == array[0]"/>
<s:property value="#x != array[0]"/>

OGNL 访问命名对象 ( parameters、request、session、application、attr )

<s:property value="#parameters.author"/>
<s:property value="#request.message"/>
<s:property value="#session.message"/>
<s:property value="#application.message"/>
<s:property value="#attr.message"/>

OGNL 访问集合的伪属性

类型 伪属性 伪属性对应的 Java 方法
List
Set
Map
size
isEmpty
List.size()        List.isEmpty()
Set.size()        Set.isEmpty()
Map.size()       Map.isEmpty()
List
Set
iterator List.iterator()
Set.iterator()
Map keys
values
Map.keySet()
Map.values()
Iterator next
hasNext
Iterator.next()
Iterator.hasNext()
<s:property value="personList.size"/>
<s:property value="personList.isEmpty"/>
<s:property value="map.keys"/>
<s:property value="map.values"/>
<s:property value="personList.iterator.hasNext"/>
<s:property value="personList.iterator.next.name"/>
<s:property value="person.addressSet.iterator.hasNext"/>
<s:property value="person.addressSet.iterator.next.name"/>

OGNL 迭代集合

类型 伪属性 伪属性的作用描述
IteratorStatus index 当前元素的索引
IteratorStatus first 当前元素是否是集合的第一个元素
IteratorStatus last 当前元素是否是集合的最后一个元素
IteratorStatus count 当前迭代元素的数量,count = index + 1
IteratorStatus even index + 1 是否为偶数
IteratorStatus odd index + 1 是否为奇数
<table>
  <tr align="center">
    <td width="2%">索引</td>
    <td width="5%"></td>
    <td width="8%">当前迭代的数量</td>
    <td width="8%">迭代奇偶性</td>
    <td width="8%">集合第一个元素</td>
    <td width="8%">集合最后一个元素</td>
  </tr>
  <s:iterator value="array" var="a" status="status">
    <tr align="center">
      <td>
        <s:property value="#status.index"/>
      </td>
      <td>
        <s:property/>
      </td>
      <td>
        <s:property value="#status.count"/>
      </td>
      <td>
        <s:if test="#status.even"></s:if>
        <s:if test="#status.odd"></s:if>
      </td>
      <td>
        <s:if test="#status.first"></s:if>
        <s:else></s:else>
      </td>
      <td>
        <s:if test="#status.last"></s:if>
        <s:else></s:else>
      </td>
    </tr>
  </s:iterator>
</table>

OGNL 投影

如果把集合中的数据想象成是数据库表中的数据,那么,投影就是从这张表中选取某一列所构成的一个新的集合。投影的语法:collection.{expression}
<s:property value="personList.{name}"/>

OGNL 过滤

OGNL 过滤也称为选择,就是把满足 OGNL 表达式的结果选择出来构成一个新的集合。
过滤的语法:collection.{?expression} 或 collection.{^expression} 或 collection.{$expression}
符号 作用
? 选取与逻辑表达式匹配的所有结果
^ 选取与逻辑表达式匹配的第一个结果
$ 选择与逻辑表达式匹配的最后一个结果
#this 代表当前迭代的元素
<s:property value="array.{?#this > 5}"/>
<s:property value="array.{^#this > 5}"/>
<s:property value="array.{$#this > 5}"/>

OGNL 投影和过滤

<s:property value="personList.{?#this.sex.equals('female')}.{name}"/>
<s:property value="personList.{^#this.sex.equals('female')}.{name}"/>
<s:property value="personList.{$#this.sex.equals('female')}.{name}"/>

OGNL %{ } 语法

对于 ${ } 也许你并不会陌生,${ } 是 EL 表达式的语法,这里的 %{ } 是 OGNL 表达式的语法。
也许你开始困惑,上面示例不是都在使用 OGNL 表达式吗?!没见 %{ } 出现过啊!好眼力!凡是属于 OGNL 表达式的串,你都可以使用 %{ } 来将它们包裹住,但这不是必须的。例如 <s:property value="expression" /> 中的 expression 在任何时候都是被当做 OGNL 表达式来处理的。
<s:property value="subject"/>  <!-- subject被OGNL进行表达式求值输出 -->
<s:property value="i love java so much"/>  <!-- 什么都不输出 -->
第2行之所以什么都不输出,是因为执行时环境把 i love java so much 这个字符串也当做是一个 OGNL 表达式来处理了,但在 OGNL 上下文中并找不到与这个 KEY 对应的值,因此什么都没有输出。
这是由于 <s:property /> 标签的 value 属性是 Object 类型引起的,凡是 Object 类型的标签属性的值,都会被当做是一个 OGNL 表达式来处理。
这种情况下的解决办法是:使用单引号将它们引起来,表明这是一个普通的字符串,而不是 OGNL 表达式。
<s:property value="'subject'"/>  <!-- 输出 subject -->
<s:property value="'i love java so much'"/>  <!-- 输出 i love java so much -->
再如 <s:textfield value="expression" /> 中的 expression 什么时候被当做 OGNL 表达式来处理就要取决于你是否使用了 %{ } 语法,如果使用了,那么它就是一个 OGNL 表达式,如果没有使用,那么它就只是一个普通的字符串而已。
<s:textfield value="author"/>         <!-- author被当做普通字符串原样输出 -->
<s:textfield value="%{author}"/>      <!-- author被OGNL进行表达式求值输出 -->
<s:textfield value="person.name"/>    <!-- person.name被当做普通字符串原样输出 -->
<s:textfield value="%{person.name}"/> <!-- person.name被OGNL进行表达式求值输出 -->
这是由于 <s:textfield /> 标签的 value 属性是 String 类型引起的,凡是非 Object 类型的标签属性的值,是不会被当做一个 OGNL 表达式来处理的,
除非你使用了 %{ expression } 语法,执行时环境才会将 expression 当做是一个 OGNL 表达式来处理。
只有当你理解了上面的2个案例,你才能正确的使用 OGNL 表达式。
实际上规则非常简单,当标签属性的类型为 Object 类型时,标签属性的值就会被当做是一个 OGNL 表达式来处理,因此可省略 %{} ;
当标签属性的类型为 String 类型时,除非你使用了 %{ } 语法告诉执行时环境这是一个 OGNL 表达式,否则,标签属性的值会被当做是一个普通的字符串来处理。

文章示例源码下载

struts-ognl.zip




  
posted on 2014-03-17 20:04 fancydeepin 阅读(4779) 评论(5)  编辑  收藏

评论:
# re: Struts2 OGNL 表达式 2014-03-18 08:53 | 鹏达锁业
支持博主分享、、、、、、、、、、、、、  回复  更多评论
  
# re: Struts2 OGNL 表达式 2014-03-19 09:17 | 零柒锁业

支持博主分享  回复  更多评论
  
# re: Struts2 OGNL 表达式 2014-03-19 10:22 | 乳酸菌
辛苦了。谢谢分享  回复  更多评论
  
# re: Struts2 OGNL 表达式 2014-03-19 10:24 | 金利锁业
期待更新啊  回复  更多评论
  
# re: Struts2 OGNL 表达式 2014-04-16 17:11 | 铝板
谢谢分享,辛苦了  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: