什么是OGNL表达式?
 

OGNL是Object Graphic Navigation Language 是操作对象属性的开源表达式。 Struts2框架使用OGNL作为默认的表达式语言。

为什么我们学习OGNL

在学习JSP的时候,我们已经学习过了EL表达式。EL表达式用起来也十分简单…我们在Struts2框架中也是可以使用EL表达式的…那么OGNL表达式好在哪里呢??

OGNL是Struts2的默认表达式语言,OGNL是配搭Strut2的标签使用的..我们学习了OGNL表达式,就可以更好地理解Struts2标签的运行以及Struts2内部的存储结构.

valueStack对象

在讲解OGNL表达式之前,我们先来看看valueStack对象…valueStack是Struts2数据存储的核心…我们首先要知道数据是怎么存的,存到哪里,然后才讲解OGNL表达式是怎么取出数据的

valueStack也被称作值栈对象..


获取valueStack对象

    //获取值栈对象的2种方式    private void getVs() {        // 获取值栈对象,方式1:        HttpServletRequest request = ServletActionContext.getRequest();        ValueStack vs1 = (ValueStack) request.getAttribute("struts.valueStack");        // 获取值栈对象,方式2:         ActionContext ac = ActionContext.getContext();        ValueStack vs2 = ac.getValueStack();        System.out.println(vs1 == vs2);//true    }
   private void getVs() {
       // 获取值栈对象,方式1:
       HttpServletRequest request = ServletActionContext.getRequest();
       ValueStack vs1 = (ValueStack) request.getAttribute("struts.valueStack");

       // 获取值栈对象,方式2:
       ActionContext ac = ActionContext.getContext();
       ValueStack vs2 = ac.getValueStack();

       System.out.println(vs1 == vs2);//true
   }

valueStack内部存储结构

上面已经说了,用户访问Action时,会创建Action对象,valueStack对象。Struts2内部会将Action对象存到valueStack对象之中…那么valueStack的存储结构是什么样的呢???我们来看看

Struts2【OGNL、ValueStack】_Struts 这里写图片描述

CompoundRoot

Action对象和Action的成员属性等值都是存到CompoundRoot下的.该CompoundRoot继承着ArrayList,因此它是List结构的

    public class CompoundRoot extends ArrayList {}class CompoundRoot extends ArrayList {}

OgnlContext

OgnlContext对象存储着相关的域对象:request、response、session等数据,实现Map集合,是Map结构..

为了让request、response等域对象可以存储多个值,值也是使用Map结构

public class OgnlContext implements Map {}class OgnlContext implements Map {}

小总结

Struts2【OGNL、ValueStack】_Struts_02 这里写图片描述

CompoundRoot保存着这样的数据:

OgnlContext保存着这样的数据:


OGNL表达式取值

也就是说通过OgnlContext对象可以获取大部分我们需要的数据了。

那么OGNL表达式是怎么取出OgnlContext对象中数据的呢??下面我们通过硬编码的方式来讲解

    /**     * 1. Ognl表达式语言语言取值,取非根元素的值,必须用#号     * @throws Exception     */    @Test    public void testOgnl() throws Exception {        // 创建一个Ognl上下文对象        OgnlContext context = new OgnlContext();        // 放入数据        User user = new User();        user.setId(100);        user.setName("Jack");        // 【往非根元素放入数据, 取值的时候表达式要用"#"】        context.put("user", user);        // 获取数据(map)        // 先构建一个Ognl表达式, 再解析表达式        Object ognl = Ognl.parseExpression("#user.name");        Object value = Ognl.getValue(ognl, context, context.getRoot());        System.out.println(value);    }    /**     * 2. Ognl表达式语言语言取值,取根元素的值,不用带#号     * @throws Exception     */    @Test    public void testOgn2() throws Exception {        // 创建一个Ognl上下文对象        OgnlContext context = new OgnlContext();        // 放入数据        User user = new User();        user.setId(100);        user.setName("Jack");        // 【往根元素放入数据】        context.setRoot(user);        // 获取数据(map)        // 先构建一个Ognl表达式, 再解析表达式        Object ognl = Ognl.parseExpression("address.province");        Object value = Ognl.getValue(ognl, context, context.getRoot());        System.out.println(value);    }
   @Test
   public void testOgnl() throws Exception {
       // 创建一个Ognl上下文对象
       OgnlContext context = new OgnlContext();
       // 放入数据
       User user = new User();
       user.setId(100);
       user.setName("Jack");
       // 【往非根元素放入数据, 取值的时候表达式要用"#"】
       context.put("user", user);

       // 获取数据(map)
       // 先构建一个Ognl表达式, 再解析表达式
       Object ognl = Ognl.parseExpression("#user.name");
       Object value = Ognl.getValue(ognl, context, context.getRoot());

       System.out.println(value);
   }

   /**
    * 2. Ognl表达式语言语言取值,取根元素的值,不用带#号
    * @throws Exception
    */

   @Test
   public void testOgn2() throws Exception {
       // 创建一个Ognl上下文对象
       OgnlContext context = new OgnlContext();
       // 放入数据
       User user = new User();
       user.setId(100);
       user.setName("Jack");
       // 【往根元素放入数据】
       context.setRoot(user);

       // 获取数据(map)
       // 先构建一个Ognl表达式, 再解析表达式
       Object ognl = Ognl.parseExpression("address.province");
       Object value = Ognl.getValue(ognl, context, context.getRoot());

       System.out.println(value);
   }

也就是说,JSP页面中取出数据的时候,它会先构建一个OGNL表达式,再解析表达式

Struts2【OGNL、ValueStack】_Struts_03 这里写图片描述

例子:

      <!-- 页面: 必须要拿到ValueStack -->     <br/>1. 取根元素的值<br/>     <s:property value="user.id"/>      <s:property value="user.name"/>      <s:property value="user.address"/>      <s:property value="user.address.city"/>      <s:property value="user.address.province"/>       <br/>2. 取非根元素的值<br/>      <s:property value="#request.cn"/>      <s:property value="#session.Session_data"/>      <s:property value="#application.Application_data"/>    <br/>      <!-- 自动找request/session/application,找到后立刻返回 -->      <s:property value="#request_data"/>      <s:property value="#attr.Session_data"/>      <s:property value="#attr.Application_data"/>  <br/>      <!-- 获取请求的参数数据 -->      <s:property value="#parameters.userName"/>     <!-- struts的调试标签:可以观测值栈数据 -->     <s:debug></s:debug>
    <br/>1. 取根元素的值<br/>
    <s:property value="user.id"/>
    <s:property value="user.name"/>
    <s:property value="user.address"/>
    <s:property value="user.address.city"/>
    <s:property value="user.address.province"/>

     <br/>2. 取非根元素的值<br/>
     <s:property value="#request.cn"/>
     <s:property value="#session.Session_data"/>
     <s:property value="#application.Application_data"/>    <br/>

     <!-- 自动找request/session/application,找到后立刻返回 -->
     <s:property value="#request_data"/>
     <s:property value="#attr.Session_data"/>
     <s:property value="#attr.Application_data"/>  <br/>

     <!-- 获取请求的参数数据 -->
     <s:property value="#parameters.userName"/>

    <!-- struts的调试标签:可以观测值栈数据 -->
    <s:debug></s:debug>

OGNL对静态方法的调用
    /**     * 3.Ognl对 静态方法调用的支持     * @throws Exception     */    @Test    public void testOgn3() throws Exception {        // 创建一个Ognl上下文对象        OgnlContext context = new OgnlContext();        // Ognl表单式语言,调用类的静态方法        //Object ognl = Ognl.parseExpression("@Math@floor(10.9)");        // 由于Math类在开发中比较常用,所以也可以这样写        Object ognl = Ognl.parseExpression("@@floor(10.9)");        Object value = Ognl.getValue(ognl, context, context.getRoot());        System.out.println(value);    }
   @Test
   public void testOgn3() throws Exception {
       // 创建一个Ognl上下文对象
       OgnlContext context = new OgnlContext();

       // Ognl表单式语言,调用类的静态方法
       //Object ognl = Ognl.parseExpression("@Math@floor(10.9)");
       // 由于Math类在开发中比较常用,所以也可以这样写
       Object ognl = Ognl.parseExpression("@@floor(10.9)");
       Object value = Ognl.getValue(ognl, context, context.getRoot());
       System.out.println(value);
   }

OGNL创建集合
    <br/>一、.构建 list集合</br>    <s:iterator var="str" value="{'a','b'}">        <s:property value="#str"/>    </s:iterator>     <br/>一、.构建 map集合</br>     <s:iterator var="en" value="#{'cn':'China','usa':'America'}">         <s:property value="#en.key"/>         <s:property value="#en.value"/>  <br/>     </s:iterator></br>
   <s:iterator var="str" value="{'a','b'}">
       <s:property value="#str"/>
   </s:iterator>

    <br/>一、.构建 map集合</br>
    <s:iterator var="en" value="#{'cn':'China','usa':'America'}">
        <s:property value="#en.key"/>
        <s:property value="#en.value"/>  <br/>
    </s:iterator>

构建Map集合的时候,需要使用#号


OGNL 几个特殊的符号

#获取非根元素值  、 动态都建map集合
$  在配置文件取值
%  提供一个ognl表达式运行环境

<body>       <br/>获取request域数据<br/>       <!-- property 标签是对象类型的标签,默认支持ognl表达式, 会从根元素去China名称对应的值 -->       <s:property value="China"/>        <br/>       <!-- 如果直接赋值,需要用单引号 -->       <s:property value="'China'"/>      <br/>       <s:property value="%{#request.cn}"/>       <br/>       <!-- 值类型的标签,value值默认就是值类型,不支持ognl表达式 -->       国家:<s:textfield name="txtCountry" value="%{#request.cn}"></s:textfield>  </body>
      <br/>获取request域数据<br/>
      <!-- property 标签是对象类型的标签,默认支持ognl表达式, 会从根元素去China名称对应的值 -->
      <s:property value="China"/>        <br/>
      <!-- 如果直接赋值,需要用单引号 -->
      <s:property value="'China'"/>      <br/>
      <s:property value="%{#request.cn}"/>       <br/>

      <!-- 值类型的标签,value值默认就是值类型,不支持ognl表达式 -->
      国家:<s:textfield name="txtCountry" value="%{#request.cn}"></s:textfield>
 </body>

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y