• Struts2【OGNL、valueStack】就是这么简单


    什么是OGNL表达式?

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

    为什么我们学习OGNL

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

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

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

    valueStack对象

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

    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结构..

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

    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/>一、.构建 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>
    
    

    构建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>
    

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

  • 相关阅读:
    学习第五天
    第四天学习
    学习第三天
    学校键盘键位设置
    学习第二天
    fatal error C1902: 程序数据库管理器不匹配;请检查安装解决
    ffmpeg遇到inttypes.h和UINT64_C
    <ZZ>linux yum命令详解
    <ZZ>Linux rpm 命令参数使用详解[介绍和应用]
    转:Windows下WSH/JS实现SVN服务器钩子脚本阻止提交空日志信息和垃圾文件
  • 原文地址:https://www.cnblogs.com/Java3y/p/8546447.html
Copyright © 2020-2023  润新知