day33Struts2Day03(OGNL表达式、值栈)

回顾
一、Servlet的API
    ActionContext对象
    ServletActionContext对象
二、结构类型的跳转
    全局结果
    局部结构 type属性
三、数据的封装
    属性驱动方式
    模型驱动方式 实现ModelDrivern 接口
四、拦截器(自定义拦截器)

OGNL表达式概述
一、OGNL是Object Navigation Language(对象图导航语言)
    所谓对象图,即以任意一个对象为根,经过OGNL能够访问与这个对象关联的其余对象 
    经过它简单一致的表达式语法,能够存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转换等功能。使用相同的表达式去存取对象的属性

二、Struts2框架使用OGNL做为默认的表达式语言
    OGNL是一种比EL强大不少倍的语言
    xwork提供OGNL表达式
    ognl-3.0.5.jar

三、OGNL提供五大类功能
    支持对象方法调用
    支持类静态的方法调用和值访问
    访问OGNL上下文(OGNL context)和ActionContext
    支持赋值操做和表达式串联
    操做集合对象

一、什么是值栈
    值栈就至关于Struts2框架的数据的中转站,向值栈存入一些数据,从值栈中获取到数据
    ValueStack 是Struts2提供一个接口,实现类OgnlValueStack--值栈对象(OGNL是从值栈中获取数据的)
    Action是多例的,有一块儿请求,建立Action实例,建立一个ActionContext对象,表明的是Action的上下文对象,还会建立一个ValueStack对象
    每一个Action实例都有一个ValueStack对象(一个请求,对应一个ValueStack对象)
    在其中保存当前Action对象和其余相关对象
    Struts框架把ValueStack对象保存在名为“struts.valueStack”的请求属性中,request中(值栈对象是request一个属性)
        ValueStack vs = (ValueStack)request.getAttribute("struts.valueStack");

二、值栈的内部结构
    值栈由两部分组成
        root        Struts把动做和相关对象压入ObjectStack中--List
        context     Struts把各类各样的映射关系(一些Map类型的对象)压入ContextMap中

    Struts会默认把下面这些映射压入ContextMap(Context)中
        request表明的是Map集合的key值,value值其实也是一个Map值
        parameters:该Map中包含当前请求的请求参数?name=xxx&password=123
        request:该Map中包含当前request对象中的全部属性
        session:该Map中包含当前session对象中的全部属性
        application:该Map中包含当前application对象中的全部属性
        attr:该Map按以下顺序来检索某个属性:request、session、application

    ValueStack存在root属性(CompoundRoot)context属性(OgnlContext)、
        CompoundText就是ArrayList
        OgnlContext就是Map

    context对应Map引入root对象
        context中还存在request、session、application、attr、parameters对象引用

        OGNL表达式访问值栈中的数据
            访问root中数据时,不须要#
            访问request、session、application、attr、parameters对象数据必须写#
        操做值栈默认指操做root元素

三、值栈对象的建立,ValueStack和ActionContext是什么关系
    值栈对象是请求时建立的
    ActionContext是绑定到当前的线程上,那么在每一个拦截器或者Action中获取的ActionContext是同一个
    ActionContext中存在一个Map集合,该Map集合和ValueStack的contextMap是同一个地址
    ActionContext中能够获取到ValueStack的引用

四、获取值栈对象
    (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");
    (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

    ActionContext.getContext().getValueStack();

五、向值栈保存数据(主要针对root栈)
    valueStack.push(Object obj)
        push方法的底层调用root对象的push方法(把元素添加到0位置)

    valueStack.set(String key,Object obj)
        源码获取map集合(map多是已经存在的,有多是新建立的)把map集合push到栈顶,再把数据存入到map集合中

    在jsp中经过<s:debug/>查看值栈的内容

六、从值栈中获取值
    访问root中数据 不须要#
    访问context其余对象数据 加#
    若是向root中存入对象的话 优先使用push方法
    若是向root中存入集合的话,优先要使用set方法

    在OGNLContext中获取数据
        在Action中向与对象中存入值
        xxxx:<s:property value="#xxxx.属性"/>
        request、session、application、attr、parameters

七、获取到值栈中的数据
    为何EL也能访问值栈中的数据
        StrutsPreparedAndExecuteFilter的doFilter代码中 request = prepare.wrapRequest(request)
        对request对象进行了保证,StrutsRequestWrapper
    org.apache.struts2.dispatcher.StrutsRequestWrapper  
        加强了request的getAttribute
             Object attribute = super.getAttribute(key);
              if (ctx != null && attribute == null) {
            boolean alreadyIn = isTrue((Boolean) ctx.get(REQUEST_WRAPPER_GET_ATTRIBUTE));

            // note: we don't let # come through or else a request for
            // #attr.foo or #request.foo could cause an endless loop
            if (!alreadyIn && !key.contains("#")) {
                try {
                    // If not found, then try the ValueStack
                    ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.TRUE);
                    ValueStack stack = ctx.getValueStack();
                    if (stack != null) {
                        attribute = stack.findValue(key);
                    }
                } finally {
                    ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.FALSE);
                }
            }
        访问request范围的数据时,若是数据找不到,在值栈中找
        request对象 具有访问值栈数据的能力(查找root的数据)

OGNL的特殊符号
一、#符号的用法
    获取contextMap中的数据
        <s:property value="#xxxx.属性"/>
        request/session/application/attr/parameters
    构建一个集合
        性别<s:radio name="sex" list="{'男','女'}"></s:radio> 
        性别<s:radio name="sex" list="#{'1':'男','2':'女'}"></s:radio>

二、%符号的用法
    强制字符串解析成OGNL表达式
        例如:在request域中存入值,而后在文本框(<s:textfield>)中取值,如今到value上
        <s:textfield value="%{#request.msg}"/>
    {}中值用''引发来,此时再也不是ognl表达式,而是普通的字符串
        <s:property value="%{'#request.msg'}"/>
        <s:property value="'aaa'"/> 
三、$符号的用法
    在配置文件中可使用OGNL表达式,例如:文件下载的配置文件
    <action name="download" class="my.demo2.DownLoadAction">
            <result>
                <param name="contentType">${contentType}</param>
                <param name="contentDisposition">attachment:filename=${downFilename}</param>
            </result>
        </action>