Struts2第九篇【OGNL、valueStack详解】

什么是OGNL表达式?

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

为何咱们学习OGNL

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

  • 支持对象方法调用,如xxx.doSomeSpecial()
  • 支持类静态的方法调用和值访问,表达式的格式【例如:”@@floor(10.9)”就是调用Math.floor()的方法了】
  • 支持赋值操做和表达式串联【这个其实EL表达式也能作】
  • 访问OGNL上下文(OGNL context)和ActionContext
  • 操做集合对象【EL只能遍历集合,OGNL能够建立集合】

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

valueStack对象

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

valueStack也被称做值栈对象..框架

  • 当用户访问Action,都会建立一个Action对象,ActionContext对象、valueStack对象..
  • Struts2把Action对象放进valueStack对象之中
  • 将valueStack放进request域中,传入JSP页面(key: struts.valueStack)
  • JSP页面就可使用OGNL表达式获取值栈中的数据了

这里写图片描述

获取valueStack对象

  • 在Action中咱们能够手动获取值栈对象,有两种方式获取
//获取值栈对象的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
    }

valueStack内部存储结构

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

这里写图片描述

CompoundRoot

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

public class CompoundRoot extends ArrayList {}

OgnlContext

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

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

public class OgnlContext implements Map {}

小总结

这里写图片描述

CompoundRoot保存着这样的数据:代理

  • Action对象以及Action对象的成员属性数据
  • 使用ValueStack对象.push()进去的数据
  • 使用ValueStack对象.set()进去的数据
  • 其余代理对象的数据

OgnlContext保存着这样的数据:

  • 维护了CompoundRoot中全部的数据
  • request、response等域对象全部的数据

OGNL表达式取值

  • Struts2会将valueStack对象封装进request对象域中,传入JSP页面。
  • valueStack存储着OgnlContext对象。
  • OgnlContext对象维护了CompoundRoot对象的数据
  • CompoundRoot存储着Action等数据

也就是说经过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);
    }

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

  • 若是是CompoundRoot类的数据,表达式不须要带#号
  • 若是不是CompoundRoot类的数据,表达式须要带#号

这里写图片描述

例子:

 <!-- 页面: 必需要拿到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> 

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);
    }

OGNL建立集合

<br/>1、.构建 list集合</br>
    <s:iterator var="str" value="{'a','b'}">
        <s:property value="#str"/>
    </s:iterator>

     <br/>1、.构建 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>
相关文章
相关标签/搜索