• Struts2 框架的值栈


    1. OGNL 表达式

    1.1 概述

    • OGNL(Object Graphic Navigation Language),即对象图导航语言;
    • 所谓对象图,即以任意一个对象为根,通过OGNL可以访问与这个对象关联的其它对象;
    • 通过OGNL表达式,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图等功能;

    1.2 特点

    • OGNL 是一种比 EL 表达式强大很多倍的语言;
    • xwork 提供 OGNL 表达式;
    • ognl-3.0.5包;
    • Struts2 框架使用 OGNL 作为默认的表达式语言;

    1.3 OGNL 提供五大类功能

    • 支持对象方法调用;
    • 支持类静态的方法调用和值访问;
    • 访问 OGNL 上下文(OGNL context) 和 ActionContext;
    • 支持赋值操作和表达式串联;
    • 操作集合对象;
    // 示例:
        public void fun throws OgnlException{
            // 获取上下文对象
            OgnlContext context = new OgnlContext();
            // 获取到根对象
            Object root = context.getRoot();
            // 存入值
            context.put("name","张三");
            // 通过 OGNL 表达式获取值
            Object value = Ognl.getValue("#name",context,root);
            System.out.println(value);
        }
    

    2. 在 Struts2 框架中使用 OGNL 表达式

    2.1 Struts2 引入 OGNL 表达式,主要是在 JSP 页面中获取值栈中的值;

    // 使用 OGNL 表达式的步骤
        // 1. 在 JSP 页面中引入 Struts2 的标签库
            <%@ taglib prefix="s" uri="/struts-tags" %>
    
        // 2. 使用 Struts2 提供的 property 标签, 从值栈中获取值
        //    <s:property value="OGNL表达式"/>
    
            // jsp 页面输出 hello 字符串的长度
            <s:property value="'hello'.length()"/>
    

    3. 值栈

    3.1 值栈的概述

    • 值栈就相当于 Struts2 框架的数据中转站, Web 层向值栈中存入一些数据, JSP 页面从值栈中获取数据;
    • ValueStack 是 Struts2 提供的一个接口; OGNL 表达式通过该接口的实现类 OgnlValueStack(值栈对象)
      从值栈中获取数据.
    • Action 是多例的,每发起一个请求,就会创建一个Action实例,一个ActionContext对象, 一个ValueStack对象;
    • 每个 Action 实例都有一个 ValueStack 对象,其中保存当前 Action 对象和其他相关对象;
    • Struts2 框架将 ValueStack 对象保存在 request 域中,名称为 struts.valueStack
      ValueStack vs = (ValueStack)request.getAttribute("struts.valueStack");

    3.2 值栈的内部结构

    3.2.1 值栈由两部分组成
    1. ValueStack 中存在 root 属性(CompoundRoot), context 属性(OgnlContext);
      • CompoundRoot 就是 ArrayList;
      • OgnlContest 就是 Map;
    2. root: Struts 把动作和相关对象压入到ObjectStack中;
    3. context: Struts 把各种各样的映射关系(一些 Map 类型的对象)压入到ContextMap中;
    4. Struts2 会默认把下面这些映射压入到 ContextMap
      • parameters: 该 Map 中包含当前请求的请求参数;
      • request: 该 Map 中包含当前 request 对象中的所有属性;
      • session: 该 Map 中包含当前 session 对象中的所有属性;
      • application: 该 Map 中包含将当前 application 对象中的所有属性;
      • attr: 该 Map 按如下顺序来检索某个属性, request, session, application;
      • 注意: request 表示 Map 集合中的 key值, value 值其实也是一个 Map 集合;
    3.2.2 OGNL 表达式访问值栈中的数据
    • 访问 root 中的数据时,不需要 #;
    • 访问 context 中的数据时,必须写 #;
    • 操作值栈默认指操作 root 元素;

    3.3 值栈的创建和 ActionContext 对象的关系

    • 值栈对象(ValueStack)是请求时创建的;
    • ActionContext 是绑定在当前的线程上,每个拦截器或者 Action 中获取到的 ActionContext 是同一个;
    • ActionContext 中存在一个 Map 集合,该 Map 集合和 ValueStack 的 context 是同一个地址;
    • ActionContext 中可以获取到 ValueStack 的引用;换句话说,以后使用 ActionContext 对象来获取值栈对象;
      ValueStack vs = ActionContext.getContext().getValueStack();

    3.4 向值栈中保存数据(主要针对 root 栈)

    1. valueStack.push(Object obj)
      • push 方法的底层调用 root 对象的 push 方法(把元素添加到栈顶);
    2. valueStack.set(String key, Object obj)
      • 向栈顶压入 map 集合,把 key 和 obj 存入到 map 集合中;
      • 首先获取栈顶中的值,查看是否是 map 集合, 如果是,直接把 key 和 obj 存入到该 map 集合中;
        如果不是 map 集合,会先创建 HashMap 集合,然后存入 key 和 value 的值.
    3. root栈中存入对象,优先使用push方法; 向root栈中存入集合,优先使用set方法.

    3.5 使用OGNL表达式从值栈中获取数据

    1. JSP 页面中写入 <s:debug></s:debug>,可以查看 valueStack 中存入的数据;

    // 第一种情况: 从 root 栈中取值
    // 如果向值栈中保存字符串
        vs.push("张三");
    // 在 JSP 页面获取栈顶的值
        <s:property value="[0].top"/>
    
    // 如果向值栈中保存 map 集合
        vs.set("msg","测试代码");
    // 在 JSP 页面获取栈顶的值
        <s:property value="[0].top.msg"/>
    
    // 如果向值栈中保存 user 对象
        vs.push(user);
    // 获取栈顶的值
        <s:property value="[0].top.username"/>
        <s:property value="[0].top.password"/>
    
        // 注意: [0].top 关键字可以省略
        // 因此可以简写为
        <s:property value="username"/>
    
    // 向值栈中保存 map 集合
        vs.set("user",user);
    // 获取栈顶的值
        <s:property value="[0].top.user.username"/>
        <s:property value="[0].top.user.password"/>
    
    // 示例:
        public class ValueStackAction extends ActionSupport{
    
            // ValueStackAction 中的属性
            private User user = new User("张三",22);
            public User getUser(){
                return user;
            }
            public void setUser(User user){
                this.user = user;
            }
    
            public String add() throws Exception{
    
                // 获取到值栈对象,要先获取 ActionContext 对象
                ValueStack vs = ActionContext.getContext().getValueStack();
    
                User u2 = new User("李四",22);
                // 向值栈中存入 user 对象
                vs.set("user",u2);
            }
        }
    
        // JSP 页面中取值
        // 从栈顶开始查找user, 找到之后,获取 user 的属性
        <s:property value="user.username"/>  获取到的 username 为"李四"
    
        // [1].top 获取 ValueStackAction 对象中的属性 user
        <s:property value="[1].top.user.username"/> 获取到的 username 为"张三"
    
    // 从JSP页面获取集合中的数据
        public class ValueStackAction extends ActionSupport{
    
            public String add() throws Exception{
    
                // 获取值栈
                ValueStack vs = ActionContext.getContext().getValueStack();
    
                // 向值栈中存入 list 集合
                List<User> ulist = new ArrayList<User>();
                ulist.add(new User("张三",22));
                ulist.add(new User("李四",25));
                ulist.add(new User("王五",33));
    
                vs.push(ulist);
            }
        }
    
        // JSP页面取值
        <s:property value="[0].top[0].username"/>  // 获取到"张三"
    
        // 如果 vs.set("uslist",ulist);
        // JSP 页面取值
        <s:property value="ulist[0].username"/> // 获取到"张三"
    
        // JSP 页面中使用迭代标签<s:iterator>, 该标签中的属性
        //    * value: 要迭代的集合,需要从值栈中获取;
        //    * var: 迭代过程中,遍历的对象;
        //       * 如果有 var, 会把迭代产生的对象默认压入到 context 栈中;从context栈中取值,要加"#"号
        //       * 如果没有 var, 会把迭代产生的对象默认压入到 root 栈中;
        // 带有 var 属性
        <s:iterator value="ulist" var="aaa">
            <s:property value="#aaa.username"/>
            <s:property value="#aaa.age"/>
        </s:iterator>
    
        // 没有 var 属性
        <s:iterator value="ulist">
            <s:property value="username"/>
            <s:property value="age"/>
        </s:iterator>
    
    
    // 第二种情况: 从 context 栈中取值,底层已经封装了 request,session,application等对象
        // 向 context 栈中存入值
        HttpServletRequest request = ServletActionContext.getRequest();
        request.setAttribute("msg","张三");
    
        // JSP 页面获取值
        <s:property value="#request.msg"/>
    
    

    3.6 使用EL表达式从值栈中获取数据

    // 接上面存入的值
        // 在JSP页面使用EL表达是和 JSTL 标签
        // 底层使用的是 装饰者模式, 增强了 getAttribute() 方法
        <c:forEach items="${ulist}" var="user">
            ${user.username}<br/>
            ${user.age}
        </c:forEach>
    

    4. OGNL 表达式的特殊符号

    4.1 "#"的用法

    • 获取 context 栈中的数据: <s:property value="#request.name"/>
    • 构建一个 map 集合: <s:radio name="sex" list="#{'0':'男','1':'女'}"></s:radio>

    4.2 "$"的用法

    • 在配置文件中可以使用 OGNL 表达式,例如: 文件下载的配置文件
    <action name="download" class="cn.itcast.demo.DownloadAction">
        <result name="success" type="stream">
            <param name="contentType">${contentType}</param>
            <param name="contentDisposition">attachment;filename=${downFilename}</param>
        </result>
    </action>
    

    参考资料

  • 相关阅读:
    截取字符串为20个字
    GitFlow
    CSS3盒模型display:box;box-flex:3;
    CSS移动端多行显示多余省略号
    2017年6大热门开源项目
    七周七学习成为数据分析师
    2017-写给5年后的自己
    XGeocoding使用手册
    读书的5个秘诀
    如何快速成为数据分析师?(知乎)
  • 原文地址:https://www.cnblogs.com/linkworld/p/7712296.html
Copyright © 2020-2023  润新知