OGNL使用详解

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 来访问
parametersMap 类型,封装了请求中的所有参数。访问 #parameters.name 相当于调用 HttpServletRequest.getParameter( )
requestMap 类型,封装了 request 对象中的所有属性。访问 #request.name 相当于调用 HttpServletRequest.getAttribute( )
sessionMap 类型,封装了 session 对象中的所有属性。访问 #session.name 相当于调用 HttpSession.getAttribute( )
applicationMap 类型,封装了 application 对象中的所有属性。访问 #application.name 相当于调用 ServletContext.getAttribute( )
attrMap 类型,依次从 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
iteratorList.iterator()
Set.iterator()
Mapkeys
values
Map.keySet()
Map.values()
Iteratornext
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 迭代集合

类型伪属性伪属性的作用描述
IteratorStatusindex当前元素的索引
IteratorStatusfirst当前元素是否是集合的第一个元素
IteratorStatuslast当前元素是否是集合的最后一个元素
IteratorStatuscount当前迭代元素的数量,count = index + 1
IteratorStatusevenindex + 1 是否为偶数
IteratorStatusoddindex + 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 表达式,否则,标签属性的值会被当做是一个普通的字符串来处理。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值