zoukankan      html  css  js  c++  java
  • 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了

    今日分享到此结束,谢谢观看!

  • 相关阅读:
    Delphi 获取不重复随机数《LceMeaning》
    轻松一下
    MS SQL字段类型详解《转》
    Go语言优势与劣势
    go语言特点
    初始go语言
    django 短链接改成长连接
    extjs [1]
    Supervisor安装与配置
    InfluxDB命令使用
  • 原文地址:https://www.cnblogs.com/huangting/p/11105051.html
Copyright © 2011-2022 走看看