Struts2 OGNL使用詳解

jopen 10年前發布 | 20K 次閱讀 Struts2 Web框架

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 解耦。

</tr>

</tbody> </table>

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;
    }
} </div>

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;
    }
} </div>

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;
    }
} </div>

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;
    }
} </div>

< 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 > </div>

OGNL 訪問對象屬性

< s:property  value ="subject" />

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

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

OGNL 調用方法

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

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

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()" /> </div>

OGNL 調用構造方法

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

OGNL 使用索引訪問數組和列表

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

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

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" /> </div>

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]" /> </div>

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" /> </div>

OGNL 訪問集合的偽屬性

名稱 描述
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 對象中檢索屬性的值

</tr>

</tbody> </table>

< 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" /> </div>

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()

</tr>

</tbody> </table>

< 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 > </div>

OGNL 投影

如果把集合中的數據想象成是數據庫表中的數據,那么,投影就是從這張表中選取某一列所構成的一個新的集合。投影的語法:collection.{expression}
< s:property  value ="personList.{name}" />

OGNL 過濾

OGNL 過濾也稱為選擇,就是把滿足 OGNL 表達式的結果選擇出來構成一個新的集合。
過濾的語法:collection.{?expression} 或 collection.{^expression} 或 collection.{$expression}
類型 偽屬性 偽屬性的作用描述
IteratorStatus index 當前元素的索引
IteratorStatus first 當前元素是否是集合的第一個元素
IteratorStatus last 當前元素是否是集合的最后一個元素
IteratorStatus count 當前迭代元素的數量,count = index + 1
IteratorStatus even index + 1 是否為偶數
IteratorStatus odd index + 1 是否為奇數

</tr>

</tbody> </table>

< s:property  value ="array.{?#this > 5}" />

< s:property  value ="array.{^#this > 5}" />

< s:property  value ="array.{$#this > 5}" /> </div>

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}" /> </div>

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" />   <!--  什么都不輸出  --> </div> 第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  --> </div> 再 如 <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進行表達式求值輸出  --> </div> 這是由于 <s:textfield /> 標簽的 value 屬性是 String 類型引起的,凡是非 Object 類型的標簽屬性的值,是不會被當做一個 OGNL 表達式來處理的,
除非你使用了 %{ expression } 語法,執行時環境才會將 expression 當做是一個 OGNL 表達式來處理。
只有當你理解了上面的2個案例,你才能正確的使用 OGNL 表達式。
實際上規則非常簡單,當標簽屬性的類型為 Object 類型時,標簽屬性的值就會被當做是一個 OGNL 表達式來處理,因此可省略 %{} ;
當標簽屬性的類型為 String 類型時,除非你使用了 %{ } 語法告訴執行時環境這是一個 OGNL 表達式,否則,標簽屬性的值會被當做是一個普通的字符串來處理。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!
符號 作用
? 選取與邏輯表達式匹配的所有結果
^ 選取與邏輯表達式匹配的第一個結果
$ 選擇與邏輯表達式匹配的最后一個結果
#this 代表當前迭代的元素
  • sesese色