Struts2总结之第六章ognl与valueStack

Struts2总结之ognl与valueStack

ognl介绍

  • OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。
    xwork 提供 OGNL表达式
    ognl-3.0.5.jar

  • OGNL 是一种比EL 强大很多倍的语言

  • OGNL 提供五大类功能

    1. 支持对象方法调用,如xxx.doSomeSpecial();
    2. 支持类静态的方法调用和值访问
    3. 访问OGNL上下文(OGNL context)和ActionContext; (重点 操作ValueStack值栈 )
    4. 支持赋值操作和表达式串联
    5. 操作集合对象。
  • 在struts2中使用ognl表达式

    • 需要结合struts2的标签使用<s:property value=“ognl表达式”>

    •     <s:property value="'abc'.length()"/>  演示对象调用方法
      	<s:property value="@java.lang.Math@max(10,20)"/> 演示静态成员访问.
      
  • 注意:在struts2中使用静态成员访问,必须设置一个常量:
    struts.ognl.allowStaticMethodAccess=false

#号的用法

  • 用法一:

    代表 ActionContext.getContext() 上下文

    		  <s:property value="#request.name" />  相当于相当于下面的一句
              ActionContext().getContext().getRequest().get("name");
    		  #request
    		  #session
    		  #application
    		  #attr
    		  #parameters 
    
  • 用法二

    不写# 默认在 值栈中root中进行查找

    <s:property value=“name” /> 在root中查找name属性
    查询元素时,从root的栈顶元素 开始查找, 如果访问指定栈中元素
    <s:property value="[1].name" /> 访问栈中第二个元素name属性
    访问第二个元素对象 <s:property value="[1].top" />

  • 用法三 :进行投影映射 (结合复杂对象遍历 )

    1)集合的投影(只输出部分属性

    <h1>遍历集合只要name属性</h1>
    <s:iterator value="products.{name}" var="pname"> 
    <s:property value="#pname"/>
    </s:iterator>
    

    2)遍历时,对数据设置条件

    <h1>遍历集合只要price大于1500商品</h1>
        <s:iterator value="products.{?#this.price>1500}" var="product"> 
            <s:property value="#product.name"/> --- <s:property value="#product.price"/>
        </s:iterator>
    

    3)综合

    <h1>只显示价格大于1500 商品名称</h1>
    <s:iterator value="products.{?#this.price>1500}.{name}" var="pname"> 
        <s:property value="#pname"/>
    </s:iterator>  
    
    

    代码示例:

    <title>演示:进行投影操作</title>
    </head>
    <body>
    	<s:property value="ps" />
    	<br> 1.使用iterator进行遍历
    	<br>
    	<s:iterator value="ps" var="p">
    		名称:<s:property value="#p.name" />
    		<br>
    		价格:<s:property value="#p.price" />
    		<br>
    		数量:<s:property value="#p.count" />
    		<br>
    		<hr>
    	</s:iterator>
    
    	<hr>
    	2.对集合进行投影,只得到指定的属性
    	<br>
    
    	<s:iterator value="ps.{name}" var="pname">
    		<s:property value="#pname" />
    	</s:iterator>
    
    	<hr>
    	3.将ps中价格大于1000的商品得到
    	<br>
    	<s:iterator value="ps.{?#this.price>1000}" var="p">
    		名称:<s:property value="#p.name" />
    		<br>
    		价格:<s:property value="#p.price" />
    		<br>
    		数量:<s:property value="#p.count" />
    		<br>
    		<hr>
    	</s:iterator>
    
    	<hr>
    	4.将ps中价格大于1000的商品名称得到:
    	<br>
    	<s:iterator value="ps.{?#this.price>1000}.{name}" var="pname">
    		<s:property value="#pname" />
    		<br>
    		<hr>
    	</s:iterator>
    
    	<s:debug />
    </body>
    
  • 用法四:使用#构造map集合

    • 经常结合 struts2 标签用来生成 select、checkbox、radio

    • 代码示例:

      <title>演示:构造集合</title>
      
      </head>
      
      <body>
      	1.可以使用#来构建一个Map集合
      	<br>
      	<s:iterator value="#{'name':'tom','age':20}" var="entry">
      		<s:property value="#entry.key" />----<s:property value="#entry.value" />
      		<br>
      	</s:iterator>
      	<hr>
      	
      	2.可以构建List集合
      	<br>
      	<s:iterator value="{'aa','bb','cc'}" var="v">
      		<s:property value="#v" />
      		<br>
      	</s:iterator>
      	<hr>
      	
      	3.手动创建一个集合,在struts2中是结合表单标签使用的
      	<br>
      	<s:form>
      		<s:radio list="{'男','女'}" name="sex"></s:radio>
      		<s:radio list="#{'男':'male','女':'female'}" name="sex"></s:radio>
      		<s:select list="{'a','b','c'}" name="aa"></s:select>
      		<s:select list="#{'a':'aaa','b':'bbb','c':'ccc'}" name="aa"></s:select>
      	</s:form>
      </body>
      </html>
      

%号的用法

  • %作用:就是用于设定当前是否要解析其为 ognl表达式.

    • %{表达式} 当前表达式会被做为ognl解析.
    • %{ ’ 表达式 ’ } 当前表达式不会被做为ognl解析。
  • <s:property value=“表达式”> 对于s:property标签,它的value属性会被默认做为ognl.

  • 以后,所有表达式如果想要让其是ognl %{表达式}

<title>演示:%号用法</title>
</head>
<body>
	<%
		request.setAttribute("username", "tom");
	%>
        
	<s:property value="#request.username" default="hello"/><br>
	<s:property value="%{#request.username}"/><br>    //ognl
	<s:property value="%{'#request.username'}"/><br>
	<hr>
	
	<s:textfield name="abc" value="%{#request.username}"/>
</body>

$号的用法

$作用:就是在配置文件中使用ognl表达式来获取valueStack中数据.

  • struts.xml(文件的上传下载)

    <action	name="download"	class="com.syj.action.DownloadAction">
        <result name="input">/download.jsp</result>
        <result>/success.jsp</result>
        <result type="stream" >
            <param name="contentType" > ${contentType}</param> <!-- 调用当前action中的getContentType()方法 -->
            <param name="contentDisposition">attachment;filename=${downloadFileName}</param><!-- 调用当前action中的getDownloadFileName()方法 -->
            <param name="inputStream">${inputStream}</param><!-- 调用当前action中的getInputStream()方法 -->
        </result>
    		</action>
    
  • 在校验文件中使用ActionClassName-regist-validation.xml

    <!--配置名字长度时 -->
    <field-validator type="stringlength">
        <param name="maxLength">12</param>
        <param name="minLength">6</param>
        <message>用户名必须在${minLength}-${maxLength}位之间</message>
    </field-validator>
    

    配置年龄范围时

    <!-- 对age进行校验,规定年龄必须在10-40之间 -->
    <field name="age">
        <field-validator type="int">
            <param name="min">10</param>
            <param name="max">40</param>
            <message>年龄必须在${min}--${max}之间</message>
        </field-validator>
    </field>
    
  • 在国际化文件中使用

    配置临时的国际化配置文件:my.properties

    username=${#request.username}
    

    jsp

    
    <title>演示:$用法</title>
    </head>
    <body>
    	<%
    		request.setAttribute("username", "张三");
    	%>
    	在国际化文件中使用:<br>
    	<s:i18n name="cn.itcast.resource.my">
    		<s:text name="username"/>
    	</s:i18n>
    </body>
    

Ognl的总结:总结: #就是用于获取数据 %就是用于设置是否是ognl表达式 $就是在配置文件中使用ognl.

ValueStack介绍

首先记住此图后面会做解释

在这里插入图片描述

  • 它是一个接口com.opensymphony.xwork2.util.ValueStack。
    我们使用它是将其做为一个容器,用于携带action数据到页面.
    在在页面上通过ognl表达式获取数据。

  • 我么将从下面的留个问题去了解ValueStack

    1. 什么是valueStack?
    2. valueStack结构?
    3. 值栈对象的创建 ,ValueStack 和 ActionContext 是什么关系 ?
    4. 如何获得值栈对象?
    5. 向值栈保存数据 (主要针对 root)
    6. 在JSP中获取值栈的数据

问题一:什么是valueStack?

  • valueStack主要是将action数据携带到页面上,通过ognl获取数据

​ 1.ValueStack有一个实现类叫OgnlValueStack.
​ 2.每一个action都有一个ValueStack.(一个请求,一个request,一个action,一个valueStack) valueStack生命周期就是request生命周期。
​ 3.valueStack中存储了当前action对象以及其它常用web对象(request,session,application.parameters)
​ 4.struts2框架将valueStack以“struts.valueStack”为名存储到request域中。

  • 代码查看

    • 每一次执行请求都会执行过滤器,进而执行StrutsPrepareAndExecuteFilter过滤器中的doFilter方法,让然后执行:

       execute.executeAction(request, response, mapping);
      
    • 执行进入到ExecuteOperations类中的executeAction方法:

       dispatcher.serviceAction(request, response, mapping);
      
    • 执行进入Dispatche类中的serviceAction

      每一个action都有一个ValueStack.

      在这里插入图片描述

      struts2框架将valueStack以“struts.valueStack”为名存储到request域中。

      在这里插入图片描述

问题二:valueStack结构?

  • ValueStack中主要保存有两部分内容:

    • root属性 (CompoundRoot),CompoundRoot 就是ArrayList
    • context 属性 (OgnlContext ),OgnlContext 就是 Map
  • 两部分内容分别存储的内容

    • list集合中存储的是action相关信息
    • map集合中存储的是相关映射信息,包含 paramters,request,session,application attr等。
  • 分别从两部分中取值的方式:

    • 我们想要从list中获取数据,可以不使用#号.(它就是ognl的root)
    • 如果从map中获取数据,需要使用#. (其实在struts2中的map–context其实就是ognlContext)
  • 总论:

    • ValueStack它有两部分 List Map
    • 在struts2中List就是ognlContext.里的root在Map中有引用 Map就是ognlContext.
    • 默认情况下,在struts2中从valueStack获取数据从root中获取。
  • 查看代码

    • ValueStack中的两个方法可以看出保存有两部分内容:分别是List(Root) 和Map(Context)

    •     public abstract Map<String, Object> getContext();
      
    •     public abstract CompoundRoot getRoot();
      	public class CompoundRoot extends CopyOnWriteArrayList<Object> 
      

在这里插入图片描述

问题三:值栈对象的创建 ,ValueStack 和 ActionContext 是什么关系 ?

​ valueStack是每一次请求时,都会创建.
​ 在ActionContext中持有了valueStack的引用。
在这里插入图片描述

问题四:如何获得值栈对象?

  • 对于valueStack获取有两种方式:

    • 1.通过 request获取

      ValueStack vs=(ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

    • 2.通过ActionContext获取.

      ValueStack vs=ActionContext.getContext().getValueStack();

问题五:向值栈保存数据 (主要针对 root)

  • 主要有两个方法

    • push(Object obj)------->底层就是 root.add(0,obj) 将数据存储到栈顶。

    • set(String name,Object obj);----->底层是将数据封装到HashMap中,在将这个HashMap通过push存储。

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

      1. 大致分为两大块分别为root和context
        在这里插入图片描述

问题六:在JSP中获取值栈的数据

  • root中数据不需要#,而context中数据需要#

    • 如果栈顶是一个Map集合,获取时,可以直接通过Map集合的key来获取value.
    <s:property  value="username"/>
    
    • 如果栈顶数据不是一个Map,没有key值,可以使用序号来获取。
    <s:property value="[0]">0的位置向下查找所有。	
    <s:property value="[0].top"> 只查找0位置上数据。
    
  • 如果获取OgnlContext中数据:

    1.request数据 request.setAttribute()
    2.session数据 session.setAttribute()
    3.application数据 application.setAttribute()
    4.attr 依次从request,session.application中查找
    5.parameters 获取请求参数

  • 配置一个简单的Struts2请求

    ValueStackDemo2Action

    public class ValueStackDemo2Action extends ActionSupport {
    	@Override
    	public String execute() throws Exception {
    		// 向valueStack中存储数据(root)
    		ValueStack vc = ActionContext.getContext().getValueStack();
            //下面两行位置不同取值方式不同
    		vc.set("username", "tom");
    		vc.push("syj");
    		return SUCCESS;
    	}
    }
    

    struts.xml配置

    <action name="demo2" class="com.syj.action.ValueStackDemo2Action" >
    			<result >/ognl2.jsp</result>
    </action>
    

    ognl2.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>   
        <%@taglib  prefix="s"  uri="/struts-tags"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>使用ognl来获取valueStack的数据</title>
    </head>
    <body>
    	<h2>1.获取栈顶的map</h2><br>
    	如果栈顶是一个Map集合,获取时,可以直接通过Map集合的key来获取value.<br>
    	<s:property  value="username"  /><br>
    	
    	<hr>
    	<h2>2.获取栈顶非map集合数据</h2><br>0的位置向下查找所有。<br>
    	<s:property  value="[0]"  /><br>
    	只查找0位置上数据。<br>
    	<s:property  value="[0].top"  /><br>
    	只查找1位置上数据。<br>
    	<s:property  value="[1].top"  /><br>
    	<hr>
    	
    	<h2>3.获取OgnlContext中数据</h2>
    	<br>
    	<%
    		request.setAttribute("rname", "rvalue");
    		session.setAttribute("sname", "svalue");
    		application.setAttribute("aname", "avalue");
    	%>
    	<s:property value="#request.rname"/><br>
    	<s:property value="#session.sname"/><br>
    	<s:property value="#application.aname"/><br>
    
    	<!-- 依次从request,session.application中查找 --><br>
    	<s:property  value="#attr.sname" />
    	<hr>
    	
    		<h2>4.获取请求中携带的参数</h2>
    		<!-- #parameters.username获取请求中属性为username的值 -->
    	<s:property  value="#parameters.username" /><br>
    	<!-- #parameters.password获取请求中属性为username的值 -->
    	<s:property  value="#parameters.password" /><br>
    		<hr>
    <s:debug/>
    </body>
    </html>
    

在这里插入图片描述

ValueStack主流应用:解决将action数据携带到jsp页面。

  • action向jsp携带数据,都是什么样的数据?

    • 文本(字符串)

      ​ 1.fieldError 校验数据错误信息提示
      ​ 2.actionError 关于逻辑操作时错误信息(例如登录失败)
      ​ 3.message 就是一个信息.

      this.addFieldError(“msg”, “字段错误信息”);
      this.addActionError(“Action全局错误信息”);
      this.addActionMessage(“Action的消息信息”);

      fieldError 针对某一个字段错误信息 (常用于表单校验)、actionError (普通错误信息,不针对某一个字段 登陆失败)、 actionMessage 通用消息

      在jsp中使用 struts2提供标签 显示消息信息

          <s:fielderror fieldName="msg"/>
          <s:actionerror/>
          <s:actionmessage/>
      
    • 复杂数据

      可以使用valueStack存储.

      在action中存储数据:

          List<User> users = new ArrayList<User>();
          users.add(new User("tom", "123", 20, "男"));
          users.add(new User("james", "456", 21, "男"));
          users.add(new User("fox", "789", 26, "男"));
      
          vs.push(users);
      

      在页面上获取数据:

      使用了<s:iterator>标签来迭代集合。

      <s:iterator value="[0].top" var="user"> 这是将集合中迭代出来每一个元素起个名称叫user,而user是存储在context中,不在root中.
      

      起别名

      <s:iterator value="[0].top" var="user">
          username:<s:property value="#user.username"/><br>
          password:<s:property value="#user.password"/>
          <hr>
      </s:iterator>
      

      如果我们在使用<s:iterator>进行迭代时,没有给迭代出的元素起名.

      <s:iterator value="[0].top">
          username:<s:property value="username"/><br>
          password:<s:property value="password"/>
          <hr>
      </s:iterator>
      
    • 代码示例:

      在acition中往valueStack中存储数据,用到一个User的javabean

      ValueStackDemo3Action

      public class ValueStackDemo3Action extends ActionSupport {
      	@Override
      	public String execute() throws Exception {
      		// 向valueStack中存储数据(root)
      		ValueStack vc = ActionContext.getContext().getValueStack();
      		List<User> users = new ArrayList<User>();
      
      		users.add(new User("tom", "123", 22, "男"));
      		users.add(new User("jame", "abc", 22, "女"));
      		users.add(new User("lucy", "321", 23, "男"));
      		users.add(new User("xiaohong", "ABC", 20, "女"));
      
      		// vc.push(users);
      		vc.set("users", users);
      		return SUCCESS;
      	}
      }
      

      配置struts.xml

      编写jsp代码:

      ognl3.jsp

      <%@ page language="java" contentType="text/html; charset=UTF-8"
          pageEncoding="UTF-8"%>
          
          <%@taglib  prefix="s"  uri="/struts-tags"%>
          
      <!DOCTYPE html>
      <html>
      <head>
      <meta charset="UTF-8">
      <title>使用ognl来获取valueStack中存取的复杂数据</title>
      </head>
      <body>
      
      
      <h1>1.使用push存储数据获取</h1>
      
      	<s:property value="[0].top" />
      	<hr>
      	给获取到的复杂数据起一个别名<br>
      	<font color="red">这是将集合中迭代出来每一个元素起个名称叫user,而user是存储在context中,不在root中.l</font><br>
      	<s:iterator value="[0].top" var="user" >
      		username:<s:property value="#user.username"  /><br>
      		password:<s:property value="#user.password"  /><br>
      		age:<s:property value="#user.age"/><br>
      		gender:<s:property value="#user.gender"/><br>
      	</s:iterator>
      	<hr>
      	不给获取到的复杂数据起别名
      	<s:iterator value="[0].top" >
      		username:<s:property value="username"/><br>
      		password:<s:property value="password"/><br>
      		age:<s:property value="age"/><br>
      		gender:<s:property value="gender"/><br>
      	</s:iterator>
      	<hr>
      	<h1>2.使用set存储数据</h1>
      	<hr>
      	<s:property value="users" /><br>
      	
      	<s:iterator value="users" var="user" >
      		username:<s:property value="#user.username"/><br>
      		password:<s:property value="#user.password"/><br>
      		age:<s:property value="#user.age"/><br>
      		gender:<s:property value="#user.gender"/><br>
      	</s:iterator>
      	<hr>
      	<s:iterator value="users"  >
      		username:<s:property value="username"/><br>
      		password:<s:property value="password"/><br>
      		age:<s:property value="age"/><br>
      		gender:<s:property value="gender"/><br>
      	</s:iterator>
      	<hr>
      <s:debug/>
      </body>
      </html>
      

      运行结果:
      在这里插入图片描述

默认压入到valueStack中的数据.

在执行action和拦截器之前,会将action压入栈中

  • 访问的action对象会被压入到valueStack中.

    • DefaultActionInvocation 的 init方法 stack.push(action);

    • Action如果想传递数据给 JSP,只有将数据保存到成员变量,并且提供get方法就可以了

      我们提供的getXXX方法在默认压栈时会提供XXX的一个Property Name值


      在这里插入图片描述

​ 我们在jsp页面可以通过ognl表达是获取值

  • ModelDriveInterceptor会执行下面操作
    在这里插入图片描述

将实现了ModelDrive接口的action中getModel方法的返回值,也就是我们所说的model对象压入到了valueStack.

  • 有一种情况是声明之后重新赋值,我们应该如何取值:

    在这里插入图片描述

我们应该从model中取得新赋予的值

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值