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 來訪問
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 表達式,否則,標籤屬性的值會被當做是一個普通的字符串來處理。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章