Struts2 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 表达式,否则,标签属性的值会被当做是一个普通的字符串来处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值