首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Struts 2 OGNL 進階實戰:方法呼叫、靜態存取、集合操作與投影過濾

     編輯:Java 相關知識

為何 Struts 2 選擇 OGNL?

OGNL 相較其他表達式語言具備五大優勢:

  1. 支援物件方法呼叫:xxx.doSomeSpecial()
  2. 支援類靜態方法/值存取:@java.lang.String@format('foo %s', 'bar')
  3. 支援賦值與表達式串聯:price=100, discount=0.8, calculatePrice()
  4. 存取 OGNL Context 與 ActionContext
  5. 強大的集合物件操作能力

實戰範例一:上下文環境中的 OGNL 存取

public class OGNL1 {
    public static void main(String[] args) {
        Map<String, Object> context = new HashMap<>();
        Person p1 = new Person("zhangsan");
        Person p2 = new Person("lisi");
        Person p3 = new Person("wangwu");
        Person p4 = new Person("zhaoliu"); // 不放入 context

        context.put("person1", p1);
        context.put("person2", p2);
        context.put("person3", p3);

        // 1. 從根物件取 name
        Ognl.getValue("name", context, p2); // lisi

        // 2. 用 # 指定物件取 name
        Ognl.getValue("#person2.name", context, p2); // lisi
        Ognl.getValue("#person1.name", context, p2); // zhangsan

        // 3. 指定 p4 為根物件(p4 不在 context 中)
        Ognl.getValue("name", context, p4); // zhaoliu
        Ognl.getValue("#person4.name", context, p4); // 拋出異常:person4 不在 context
    }
}

關鍵結論:無 # 時從根物件取值;有 # 時從 context 指定鍵取值,且該鍵必須存在於 context 中。

實戰範例二:方法呼叫與靜態存取

public class OGNL2 {
    public static void main(String[] args) {
        OgnlContext context = new OgnlContext();
        People p1 = new People("zhangsan");
        context.setRoot(p1);

        // 成員方法
        Ognl.getValue("name.length()", context, context.getRoot()); // 8
        Ognl.getValue("#people2.name.toUpperCase()", context, context.getRoot()); // LISI

        // 靜態方法
        Ognl.getValue("@java.lang.Math@min(4,10)", context, context.getRoot()); // 4

        // 靜態欄位
        Ognl.getValue("@java.lang.Math@E", context, context.getRoot()); // 2.718...
    }
}

語法重點:@完整類名@方法名(參數) 呼叫靜態方法,@完整類名@欄位名 存取靜態欄位。

實戰範例三:集合操作與建構

public class OGNL3 {
    public static void main(String[] args) {
        OgnlContext context = new OgnlContext();
        Classroom cr = new Classroom();
        cr.getStudents().addAll(Arrays.asList("zhangsan", "lisi", "wangwu"));
        context.setRoot(cr);

        // 存取集合
        Ognl.getValue("students", context, context.getRoot()); // [zhangsan, lisi, wangwu]
        Ognl.getValue("students[0]", context, context.getRoot()); // zhangsan
        Ognl.getValue("students.size()", context, context.getRoot()); // 3

        // Map 存取
        Student stu = new Student();
        stu.getContactWays().put("homeNumber", "110");
        context.put("student", stu);
        Ognl.getValue("#student.contactWays['homeNumber']", context, context.getRoot()); // 110

        // 建構集合
        Ognl.getValue("{'aa','bb','cc'}", context, context.getRoot()); // List
        Ognl.getValue("#{'key1':'value1','key2':'value2'}", context, context.getRoot()); // Map
    }
}

OGNL 視 List 與 Array 同等,建構 List 用 {},建構 Map 用 #{}。

實戰範例四:集合過濾與投影

public class OGNL4 {
    public static void main(String[] args) {
        Humen h = new Humen("qiuyi", "n", 22);
        h.getFriends().addAll(Arrays.asList(
            new Humen("zhangsan", "n", 22),
            new Humen("lisi", "f", 21),
            new Humen("wangwu", "n", 23)
        ));

        OgnlContext context = new OgnlContext();
        context.setRoot(h);

        // 過濾:名字長度 > 7
        Ognl.getValue("friends.{? #this.name.length() > 7}", context, context.getRoot());
        // 結果: [Humen[name=zhangsan, ...]]

        // 投影:取所有名字
        Ognl.getValue("friends.{name}", context, context.getRoot());
        // 結果: [zhangsan, lisi, wangwu]
    }
}
  • 過濾:collection.{? expression},#this 代表當前元素
  • 投影:collection.{expression},類似 SQL SELECT column

Struts 2 標籤中常見 OGNL 困惑總結

1. #、%、$ 符號

Struts 2 將 ValueStack 設為根物件,ValueStack、Parameters、Session、Request、Application、Attr 均在 Context 中。存取非根物件加 #;% 強制字串屬性按 OGNL 求值;$ 用於 XML/國際化檔引用。

2. % 的通用性

不確定標籤處理類是否將屬性視為 OGNL 時,統一加 % 最安全:若處理類視為字串則求值,若視為 OGNL 則忽略 %。

3. 標籤如何取值?

ValueStack 從棧頂向下搜尋,找到含目標屬性 getter/setter 的 Bean。<s:property value="username"/> 相當於遍歷棧中 Action 找 getUsername()。

OGNL 常用存取模式速查表

屬性存取

<s:property value="user.username"/>
<s:property value="user.address.addr"/>

方法呼叫

<s:property value="user.get()"/>

靜態屬性/方法

<s:property value="@struts.action.LoginAction@get()"/>
<s:property value="@java.lang.Math@floor(44.56)"/>
<s:property value="@java.util.Calendar@getInstance()"/>
<s:property value="@struts.vo.Address@TIPS"/>

建構器呼叫

<s:property value="new struts.vo.Student('李曉紅','美女',3,25).username"/>

集合存取

<s:property value="testList"/>           <!-- 整個 List -->
<s:property value="testList[0]"/>        <!-- 索引存取 -->
<s:property value="testMap['m1']"/>      <!-- Map key 存取 -->
<s:property value="testMap.keys"/>       <!-- 所有鍵 -->
<s:property value="testMap.values"/>     <!-- 所有值 -->
<s:property value="testSet.size"/>       <!-- 偽屬性 size -->

集合選擇與投影

<s:property value="stus.{? #this.grade >= 60}"/>                    <!-- 過濾 -->
<s:property value="stus.{? #this.grade >= 60}.{username}"/>        <!-- 過濾後投影 -->
<s:property value="stus.{^ #this.grade >= 60}.{username}"/>        <!-- 第一個符合 -->
<s:property value="stus.{$ #this.grade >= 60}.{username}"/>        <!-- 最後一個符合 -->

Lambda 表達式

<s:property value="#f = :[#this==1?1:#this*#f(#this-1)], #f(4)"/> <!-- 4! = 24 -->

Context 物件存取

<s:property value="#parameters.username"/>  <!-- Request 參數 -->
<s:property value="#session.userId"/>       <!-- Session -->
<s:property value="#application.config"/>   <!-- Application -->

% 與 $ 實戰

<s:property value="%{getText('key')}"/>  <!-- 取國際化訊息 -->
<s:property value="${min}"/>             <!-- 國際化檔/驗證配置 -->

總結

OGNL 是 Struts 2 資料綁定的靈魂。精通上下文機制、掌握三大符號用法、熟練集合操作與投影過濾語法,能讓視圖層程式碼極度精簡。實戰建議:多寫測試案例驗證各種存取路徑,善用 % 避免標籤屬性解析歧義,靈活運用 Lambda 與集合操作處理複雜資料轉換邏輯。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved