zoukankan      html  css  js  c++  java
  • Struts2基础学习(七)—值栈和OGNL

    目录:

    一、值栈

    二、OGNL表达式

    一、值栈(ValueStack)

    1.定义

         ValueStack贯穿整个Acton的生命周期,每个Action类的对象实例都拥有一个ValueStack对象,相当于一个数据中转站,在其保存当前的Action对象和其他对象。

    2.结构

         在ValueStack对象内部有两个逻辑部分。

          ObjectStack:  root属性,是一个ArrayList,包含Action对象和其他对象。

          ContextMap:  context属性,是一个Map,默认压入内容(request、session、application、attr、parameters)。

         image

                   image

         当Struts2接受一个请求时,会创建ActionContext、ValueStack、Action实例。然后action存放进ValueStack,所以Action的实例变量可以被OGNL访问。OGNL表达式需要配合Struts标签才可以使用。

         Struts 的 property 标签用来输出值栈中的一个属性值。

    <s:property value="username"/>

         详细流程

        Struts2接受到一个action请求后,会创建Action类的实例,但是并不会调用Action方法,而是先将Action类的相应属性放到ValueStack对象的栈顶,所有的属性值都是默认值。然后Struts2会调用拦截器中链中的拦截器,当调用完所有的拦截器后,最后会调用Action类的Action方法。在调用Action方法之前,会将ValueStack中属性值赋给Action类中的相应属性。可以知道在Struts2的Action类可以获得与属性同名的参数值就是通过不同的拦截器来处理的,如获得请求参数的拦截器是params,获得Action配置参数的拦截器是staticParam等。在这些拦截器内部读取相应的值,然后更新到ValueStack对象栈顶的相应属性。

    3.值栈的相关操作

    (1)如何获取值栈对象

    		ValueStack vs1 = (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");
    		ValueStack vs2 = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
    		ValueStack vs3 = ActionContext.getContext().getValueStack();

    (2)向值栈保存数据

    A: valueStack.push(Object obj);

         push方法的底层调用root对象的push方法(把元素添加到0位置)。

    B:valueStack.set(String key, Object obj);

         获取map集合(map有可能是已经存在的,有可能是新创建的),把map集合push到栈中,再把数据存入到map集合中。

    (3)EL表达式为什么也能访问值栈中的属性

         在核心过滤器中有个doFilter方法。

         image

         在核心过滤器的doFilter方法中,调用request的包装方法wrapRequest,返回request对象。

         image

         image

         在Dispatcher类中的request对象的包装类中首先判断request对象是否已经被该类包装,如果已经被包装,不需要再次包装,直接返回即可,如果没有被包装,执行下面的if-else语句,在if的判断中,判断其是否是文件上传,如果是创建文件上传的包装类对象,在此我们不讨论这种情况。如果不是文件上传,创建request对象的包装类StrutsReuqestWrapper对象,在参数中传入需要包装的request对象。按住Ctrl键,查看该包装类。

    因为上面的每个方法都返回request对象,那么如果执行到这里,核心过滤器中的request对象就是StrutsReuqestWrapper类的实例对象。

    StrutsReuqestWrapper该类中有个getAttribute方法,就是这个方法判断从Servlet容器中取值还是从值栈中取值。

       image

         总结就是获取request的包装类StrutsReuqestWrapper,获得该类的实例对象。类中有getAttribute方法,在该方法中判断是从Servlet容器中取值,还是从值栈中取值。先调用父类javax.servlet.ServletRequestWrapper的 getAttribute方法,如果获取不到值,就获取值栈对象,调用值栈对象的findValue方法取值。

    二、OGNL

         在JSP页面可以利用OGNL(Object-Graph-Navigation-Language)对象导航图语言来访问值栈中的对象属性。

         如希望访问值栈中ContextMap中的数据,需要在表达式加上一个前缀#,如果没有前缀#,则将在ObjecStack里进行。

    1.如果访问其他Context中的对象,由于它们不是根对象,所以在访问时,需要添加#前缀

         image

    Action中代码

    		ServletActionContext.getRequest().setAttribute("username","username_request");
    		ServletActionContext.getContext().getSession().put("username","username_session");
    		ServletActionContext.getServletContext().setAttribute("username","username_application");
    		ValueStack valueStack = ServletActionContext.getContext().getValueStack();
    		valueStack.set("username","username_valueStack");

    Jsp页面

    	<!-- username_request -->
    	request: <s:property value="#request.username"/><br>
    	
    	<!-- username_session -->
    	session:  <s:property value="#session.username"/> <br>
    	
    	<!-- username_application -->
    	application:  <s:property value="#application.username"/>  <br>
    	
    	<!-- username_request -->
    	attr: <s:property value="#attr.username"/>  <br>
    	
    	<!-- username_valueStack -->
    	valueStack: <s:property value="username"/>  <br>
    	
    	<!-- Lynx -->
    	parameters: <s:property value="#parameters.username[0]"/>  <br>

         image

         (1)在OgnlValueStack类里有一个List类型的root变量,他存放了一组对象。

         (2)处于第一位的对象叫栈顶对象。

         (3)通常我们在OGNL表达式里直接写上属性的名称即可访问root变量里对象的属性。

         (4)搜索顺序是从栈顶对象开始寻找,如果栈顶对象不存在该属性,就会从第二个对象寻找,如果没有找到就从第三个对象寻找,依次往下访问,直到找到为止。

    2.集合的过滤

    有三种方式:

    (1)"?#" : 过滤所有符合条件的集合。user.{?#this.age > 19}

    (2)"^#" : 过滤第一个符合条件的元素。

    (3)"$#" : 过滤最后一个符合条件的元素。

    this表示集合中的元素。

    Action代码

    		List<Person> list = new ArrayList<Person>();
    		list.add(new Person("AAA",22));
    		list.add(new Person("BBB",23));
    		list.add(new Person("CCC",19));
    		list.add(new Person("DDD",17));
    		ServletActionContext.getRequest().setAttribute("list",list);

    显示页面

    	<!--  "?#":过滤所有符合条件的集合  -->
    	<!-- AAA:22--BBB:23 -->
    	<s:iterator value="#request.list.{?#this.age > 20}" var="person">
    		${person.username} : ${person.age} <br>
    	</s:iterator>
    	
    	<!--  "$#" : 过滤最后一个符合条件的元素。-->
    	<!--  DDD:17 -->
    	<s:iterator value="#request.list.{$#this.age < 20}" var="person">
    		${person.username} : ${person.age} <br>
    	</s:iterator>
    	
    	<!--  "^#" : 过滤第一个符合条件的元素。-->
    	<!--  CCC:19 -->
    	<s:iterator value="#request.list.{^#this.age < 20}" var="person">
    		${person.username} : ${person.age} <br>
    	</s:iterator>

    3.%的用法

         "%"用途是告诉执行环境%{}里的是OGNL表达式。

    Action中的代码

    ServletActionContext.getRequest().setAttribute("username","username_request"); 

    JSP页面

    <s:textfield name="name" label="%{#request.username} "/>
    运行结果
    username_request : <input type="text" name="name" value="" id="name"/>

    4.$的用法

         (1)用于在国际化资源文件中,引用OGNL表达式。

         (2)在Struts2配置文件中,引用OGNL表达式。

         在struts2配置文件中引用ognl表达式 ,引用request等作用域中的值

         在项目中使用重定向Action的时候,在此时request作用域失效,可使用该方法传值。

  • 相关阅读:
    Vue请求参数转换(qs的使用---对象序列化)
    Vue中使用async/await解决异步请求问题
    数据结构:set
    数据结构:map (不是数组的map方法)
    数组方法-reduce 和 ES6扩展运算符
    数据分析相关
    Hadoop委任和解除节点
    Oozie调度Sqoop报错
    Oozie调度Sqoop的两种方式
    MySql数据表直接到Hive表操作
  • 原文地址:https://www.cnblogs.com/yangang2013/p/5489650.html
Copyright © 2011-2022 走看看