Struts2中OGNL表達式的用法


今天分享的是Struts2框架中的一種ognl表達式語言,主要分兩個目標去學習

      1.理解struts2傳值的優先級

      2.ognl與el的區別

一:ognl表達式語言簡介

  OGNL的全稱是Object Graph Navigation Language(對象圖導航語言),它是一種強大的表達式語言,讓你通過簡單一致的表達式語法來讀取和設置Java對象的屬性值,調用對象的方法,遍歷整個對象的結構圖,實現字段類型轉換等功能。 

  1.1:簡單對 對象圖導航語言舉例分析

     假如現在項目中有兩個實體類:

   Class Book(書本類中有以下屬性) :

    private String bid;
    private String bname;
    private Category c;

   Class Category(書籍分類有以下屬性):   

     private String cid;
      private String name;

  假如我現在有一個需求:

    想在同一個jsp頁面中展示書籍以及書籍類別的信息,

    像平時的話肯定就是寫BookDao然后用list集合接收在jsp中用EL表達式輸出出來

         ${book.bid}/${book.bname}

      然而${book.c.bname} 就是對象圖導航語言

二:ognl表達式語言特點 

  1.支持對象方法調用,形式如:objName.methodName();

  2.支持類靜態的方法調用和值訪問,表達式的格式為@[類全名(包括包路)]@[方法名 |  值名],例如:

    @java.lang.String@add( '11' , 'hahhaha' )

  3.支持賦值操作和表達式串聯,例如:

   number=18, price=100,Total();那么返回1800;

  4.訪問OGNL上下文(OGNL context)其實就是Map (教室、老師、學生)和ActionContext,

    OgnlContext=根對象(1)+非根對象(N)
    老師:根對象 1
    學生:非根對象 n
    非根對象要通過"#key"訪問,根對象可以省略"#key"

    3.4.1:根對象和非根對象的概括

      1、一個上下文中只有一個根對象
      2、取跟對象的值,只需要直接通過根對象屬性即可
      3、非根對象取值必須通過指定的上下文容器中的#key.屬性去取。

    圖解:

    

  ognl取值賦值的方法:

  OnglExpression類

package com.ht.text;

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;

/**
 * 用於OGNL表達計算的一個工具類
 * 
 */
public class OnglExpression {
    private OnglExpression() {
    }

    /**
     * 根據OGNL表達式進行取值操作
     * 
     * @param expression
     *            ognl表達式
     * @param ctx
     *            ognl上下文
     * @param rootObject
     *            ognl根對象
     * @return
     */
    public static Object getValue(String expression, OgnlContext ctx, Object rootObject) {
        try {
            return Ognl.getValue(expression, ctx, rootObject);
        } catch (OgnlException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 根據OGNL表達式進行賦值操作
     * 
     * @param expression
     *            ognl表達式
     * @param ctx
     *            ognl上下文
     * @param rootObject
     *            ognl根對象
     * @param value
     *            值對象
     */
    public static void setValue(String expression, OgnlContext ctx, Object rootObject, Object value) {
        try {
            Ognl.setValue(expression, ctx, rootObject, value);
        } catch (OgnlException e) {
            throw new RuntimeException(e);
        }
    }
}

四:值棧ValueStack 

  valueStack是struts2的值棧空間,是struts2存儲數據的空間

  根據棧的制度,它是先進后出的數據結構,彈夾 push/pop

  之所以把它作為根對象主要是因為  放到值棧中的對象都可視為根對象

  4.1:ValueStack簡介

  4.1.1.ValueStack是一個接口,在struts2中使用OGNL(Object-Graph Navigation Language)表達式實際上是使用實現了ValueStack接口的類OgnlValueStack.

  4.1.2.ValueStack貫穿整個action的生命周期,每一個action實例都擁有一個ValueStack對象,其中保存了當前action對象和其他相關對象.

  4.1.3.struts2把ValueStack對象保存在名為:struts.valueStack的request域中.即ValueStack作用域為request.當action創建的時候,ValueStack就創建了,action被銷毀的時候,ValueStack就銷毀了

  4.1.4.ValueStack中的數據分兩部分存放:root(棧結構,CompoundRoot)和context(map形式,OgnlContext)

  (1)其中的root對象是CompoundRoot,CompoundRoot繼承了ArrayList,提供了額外的方法:push(),和pop()方法,                 

用來對root對象中所包含的數據進行存取.正是由於這兩個方法,CompoundRoot變成了一個棧結構. struts2中,一個請求在最終到達Action的方法之前,Action對象本身會被壓入ValueStack(實際上就是放到ValueStack的CompoundRoot中),所以action對象是CompoundRoot中的一個元素.        

  (2)其中的context對象是OgnlContext,它實現了map接口,在valuestack的默認實現類中,即OgnlValueStack類中,                

調用ongl中的方法:Ognl.createDefaultContext(..)給context賦值,此方法返回的是一個OgnlContext對象.    

  ValueStack內存結構圖如下:

  4.2 struts2中傳遞數據

  可以使用作用域,但更多的是利用ValueStackActionContext

  然而作用域取值有規律的他是從小到大的

   page -> request -> session -> application

  ActionContext就相當於一個大容器,同一請求中只創建一個上下文;

  ValueStack就是根對象容器,它的取值是從上至下的;

  parameters,request ,session ,application就是非根對象容器

  注意:

  1、ActionContext一次請求創建一次
  2、值棧取值從上往下,取到為止,如果已經拿到,不再往下找。

五:ognl與el區別

  因為OGNL表達式是struts2的默認表達式語言所以只對struts2標簽管用,然而el在html中也可以用

   struts2標簽用的都是ognl表達式語言,所以它多數都是去棧頂找值,找不到再去作用域

   el卻相反,它都是去map集合作用域中找

  

 

  ognl的取值賦值案例示范

  

public class Demo1 {
 2 
 3     /**
 4      * @param args
 5      * @throws OgnlException
 6      */
 7     public static void main(String[] args)  {
 8 //        叫小李的員工
 9         Employee e = new Employee();
10         e.setName("小李");
11 //         張經理的管理
12         Manager m = new Manager();
13         m.setName("張經理");
14 
15         // 創建OGNL下文,而OGNL上下文實際上就是一個Map對象
16         OgnlContext ctx = new OgnlContext();
17 
18         // 將員工和經理放到OGNL上下文當中去
19         ctx.put("employee", e);
20         ctx.put("manager", m);
21 //        小李是根對象   一個公司有很多老板   只有一個員工小李
22         ctx.setRoot(e);// 設置OGNL上下文的根對象  
23 
24         /** ********************** 取值操作 *************************** */
25         // 表達式name將執行e.getName(),因為e對象是根對象(請注意根對象和非根對象表達式的區別)
26         String employeeName = (String) OnglExpression.getValue("name", ctx, e);
27         System.out.println(employeeName); //小李
28 
29         // 表達式#manager.name將執行m.getName(),注意:如果訪問的不是根對象那么必須在前面加上一個名稱空間,例如:#manager.name
30         String managerName = (String) OnglExpression.getValue("#manager.name",
31                 ctx, e);
32         System.out.println(managerName);  //張經理
33 
34         // 當然根對象也可以使用#employee.name表達式進行訪問
35         employeeName = (String) OnglExpression.getValue("#employee.name", ctx,
36                 e);
37         System.out.println(employeeName);  //小李
38 
39         /** ********************** 賦值操作 *************************** */
40         OnglExpression.setValue("name", ctx, e, "小明");
41         employeeName = (String) OnglExpression.getValue("name", ctx, e);
42         System.out.println(employeeName);  //小明
43 
44         OnglExpression.setValue("#manager.name", ctx, e, "孫經理");
45         managerName = (String) OnglExpression.getValue("#manager.name", ctx, e);
46         System.out.println(managerName);  //孫經理
47 
48         OnglExpression.setValue("#employee.name", ctx, e, "小芳");
49         employeeName = (String) OnglExpression.getValue("name", ctx, e);
50         System.out.println(employeeName);  //小芳
51     }
52 }

  控制台上輸出結果順序與下面一致就對了

小李
張經理
小李
小明
孫經理
小芳

  ognl在struts2中的應用

  創建一個測試類

/**
     * 此例用於模擬struts2的值棧計算過程
     * ValueStack是一個堆棧結構的容器  有壓棧操作   先進后出
     * @param args
     */
    public String test1(String[] args) {
        ValueStack vs =ServletActionContext.getContext().getValueStack();
        vs.push(new Employee("張雇員", 2000));// 1
        vs.push(new Student("小明同學", "s001"));// 0
        System.out.println(vs.findValue("name"));//小明
        System.out.println(vs.findValue("salary2")); //2000
        return "rs";
    }

  struts-sy.xml配置文件

<action name="/stack_*"  class="com.ht.text.Demo7" method="{1}">
            <result name="rs">/rs.jsp</result>
        </action>

jsp中代碼

<a href="${pageContext.request.contextPath }/sy/stack_test1.action?sex=nv">ognl1</a>

輸出結果為

小明同學
2000

現在來用實例證明一下ValueStack有壓棧,先進后出的賦值套路

  創建一個類來寫action代碼,記得繼承ModelDriven接口

private Cal cal1=new Cal();

    private String num1;

    public String getNum1() {
        return num1;
    }

    public void setNum1(String num1) {
        this.num1 = num1;
    }

    public String accept1() {
//        cal使用的是ModelDriven賦值
        System.out.println("cal1:"+cal1);
//        num使用的是get/set賦值
        System.out.println("num1:"+num1);
        return "rs";    
    }

jsp代碼

<a href="${pageContext.request.contextPath }/sy/demo_accept1.action?num1=20&&num2=5">accept1</a>

輸出結果

值棧中cal1變量比num1變量更靠近棧頂,所以她接收到了值,但是前台參數已經賦值,所以num1沒有接收到值就為null了

 

今日分享到此結束,謝謝觀看!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM