Struts2(3):OGNL表达式对值栈的操作

OGNL表达式
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,是一个使用简单、功能强大的、开源的表达式语言,可以方便地操作任何的对象属性、方法等。
Struts2框架使用OGNL作为默认的表达式语言,主要用于页面的取值。它类似于EL表达式语言,但比EL语法强大很多。

OGNL表达式的用法
OGNL表达式是类似于el表达式,用于页面上取后台的值,但是OGNL表达式需要结合s标签来使用。

OGNL最简单的四种用法(先入门)
1、直接显示一个值
2、调用对象的方法或属性
3、可以直接调用类里的静态方法,把调用静态方法的开关打开
4、计算某个表达式的值

注意:在演示ognl调用静态方法时,需要把静态方法调用的开关打开

在struts.xml中开启OGNL调用静态方法的开关

<!-- 打开通过OGNL表达式调用静态方法的开关 -->
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>

案例:
测试ognl几种简单的用法

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>演示ognl的几种用法</h1>
	直接在页面上显示一个值:<s:property value="1"/><br>
	调用对象里的方式:<s:property value="'hello'.toUpperCase()"/><br>
	直接调用类里静态方法:<s:property value="@java.lang.Math@max(10,11)"/><br>
	运算:<s:property value="1+2"/>
</body>
</html>

值栈(重点)
值栈是struts2框架的数据中转站,里面自动保存了当前Action对象和web对象引用(page,request,session,application,attr,paramertes),也可以手动保存自己的对象,同时也可以随时将这些对象从值栈中取出来。

值栈在哪?
每个请求都会产生一个值栈,会放在request域中,名字struts.valueStack。

获取值栈的两种方式:
1、从request域中获取
2、通过ActionContext中的getValueStack方法获取
在这里插入图片描述

案例:
1.新建ValueStackAction类

public class ValueStackAction extends ActionSupport{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	@Override
	public String execute() throws Exception {
		Map<String,Object> req = (Map<String, Object>) ActionContext.getContext().get("request");
		ValueStack valueStack = (ValueStack) req.get("struts.valueStack");
//		System.out.println(valueStack);
		
		ValueStack valueStack1 = ActionContext.getContext().getValueStack();
		System.out.println(valueStack == valueStack1);
		return SUCCESS;
	}

}

2.新建valueStack.jsp页面
3.在struts.xml配置ValueStackAction

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

    <constant name="struts.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="true" />
    <constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
    <constant name="struts.custom.i18n.resources" value="messageResource"></constant>
    <package name="default" namespace="/" extends="struts-default">
        	
        	<action name="valueStack" class="cn.icbc.action.ValueStackAction">
        		<result>
        			/valueStack.jsp
        		</result>
        	</action>
        	
    </package>

</struts>

结果:请求valueStack这个Action,观察打印结果,发现结果为true,证明两种方式获取到的值栈是同一个值栈.

值栈的数据存储结构分析
存储结构图:
在这里插入图片描述

观察值栈的内部结构
1、debug来调试:在ValueStackAction的第21行代码加一个断点,debug启动服务器,访问valueStack这个Action,进入断点,观察值栈的内部结构
在这里插入图片描述
在这里插入图片描述
OgnlContext
在这里插入图片描述
打开OgnlContext的源码,我们发现OgnlContext实现了Map接口,所以OgnlContext其实就是一个Map集合,里面存放键值对。

2、在valueStack.jsp页面中添加<s:debug>标签,来观察值栈结构
在这里插入图片描述
访问valueStack这个action,跳转到valueStack.jsp页面
在这里插入图片描述

点击debug超链接,出现debug页面
在这里插入图片描述
在这里插入图片描述
小结:
1、值栈包含两个逻辑部分:对象栈+上下文栈
2、对象栈(List)存放:Action对象+其它对象
3、上下文栈(Map)存放:Action对象,web对象的引用,其它对象。

值栈的操作(重点)
一、值栈的存放数据
struts2框架会自动将当前Action的对象存放到对象栈中
在这里插入图片描述
向对象栈手动存放数据
对象栈是栈的结构,先进后出,所以后放的元素在上边。
匿名存放
在这里插入图片描述

有名字的存放,实质上存放的是一个Map对象在这里插入图片描述

案例:
1.新建ValueStack1Action类

public class ValueStack1Action extends ActionSupport{

	private static final long serialVersionUID = 1L;
	
	@Override
	public String execute() throws Exception {
		ValueStack valueStack = ActionContext.getContext().getValueStack();
		//向对象栈存放数据(匿名存放)
		valueStack.push("汪峰");
		//向对象栈存放数据(有名字的存放)
		valueStack.set("username", "那英");
		return SUCCESS;
	}

}

2.新建valueStack1.jsp页面
页面中添加<s:debug>标签,来观察值栈结构中的值。
3.在struts.xml的ValueStack1Action类

<action name="valueStack1" class="cn.itcast.action.ValueStack1Action">
        		<result>
        			/valueStack1.jsp
        		</result>
        	</action>

4.在浏览器中请求valueStack1跳转到页面,通过<s:debug>标签查看值栈
在这里插入图片描述

向上下栈里手动存放数据
在这里插入图片描述

在浏览器中请求valueStack1跳转到页面,通过<s:debug>标签观察值栈
在这里插入图片描述

二、值栈的获取数据
注意:获取值栈中数据需要通过OGNL表达式结合s标签来获取
1.获取对象栈里的数据 规律:不需要加#

a.根据属性名取值:<s:property value=“username”/>
在这里插入图片描述
b.根据序号取值
在这里插入图片描述
[0].top表示取对象栈里的第一个元素,因为栈顶是一个map,我们需要取出map里username这个key的值,所以这么写[0].top.username

<body>
	取对象栈里的数据:<s:property value="username"/><br>
	取对象栈里匿名的数据:<s:property value="[1].top"/><br>
	取对象栈栈顶的元素:<s:property value="[0].top.username"/><br>
	<s:debug></s:debug>

2.取上下文栈里的数据 规律:加#号来取上下文栈中的数据
在这里插入图片描述

值栈的搜索顺序
1、如果不加#号,先搜索对象栈,再搜索上下文栈,如果都都搜索不到,就不显示;如果中途搜索到,立即停止搜索;
2、如果加#号,直接搜索上下文栈,如果搜索不到,就不显示;
在这里插入图片描述

实际项目开发中,我们把数据放到对象栈中有两种方法
1、可以手动获取值栈,手动把值存放进去
在这里插入图片描述

2、因为当前Action对象会自动保存到对象栈中,那么直接在Action类中定义属性并提供getter方法,也能把数据存放到对象栈中。
在这里插入图片描述
在这里插入图片描述

值栈的创建过程
1、请求被过滤器过滤,创建值栈(参考过滤器第89行,参考PrepareOperation类第80行),把web对象的引用放入上下文栈中;(参考PrepareOperation类第81行)此时对象栈为空;
StrutsPrepareAndExecuteFilter类
在这里插入图片描述
PrepareOperations类
在这里插入图片描述
Dispatcher类
在这里插入图片描述
2、当访问Action时,会创建ActionProxy来增强Action(参考Dispatcher第553行代码);
在创建ActionProxy时,会创建ActionInvocation(参考efaultActionProxyFactory的第56行代码);
接着会调用ActionProxy的prepare方法做增强的准备工作(参考DefaultActionProxyFactory的第70行代码);
在prepare方法中,会初始化ActionInvocation(参考DefaultActionProxy的第194行代码),在init方法中,把当前Action对象压入栈顶(参考DefaultActionInvocation的第398行代码)此时对象栈的栈顶为当前Action对象
在这里插入图片描述
3、然后,把值栈对象放入request中(参考dispatcher第557行代码)
Dispatcher类
在这里插入图片描述
4、在初始化ActionProxy之后,会调用层层的拦截器,在执行ModelDriven拦截器时,会先判断该Action是否实现了ModelDriven接口(参考ModelDrivenInterceptor的第94行代码),如果实现了ModelDriven接口,则把model压入栈顶,此时,位于栈顶的是model对象。
在这里插入图片描述
5、然后,调用params拦截器,参考第303行代码,把参数值按照名字设置到对象的属性里,因为model对象在栈顶,所以先给model对象的属性赋值,Action中的属性就不会赋值。

创建过程的简单表述
1.请求被过滤器StrutsPrepareAndExecuteFilter过滤,创建一个空值栈。
2.过滤器调用PrepareOperations类的方法,把web对象的引用放入context中。
3.当访问Action时调用了ActionInvocation.init(),把当前Action对象压入栈顶。
4.然后,调用Dispatcher类中的方法,把值栈对象放入request中。
5.初始化ActionProxy后,会调用层层的拦截器,判断该Action是否实现了ModelDriven接口,若实现则把model压入栈顶。
6.调用params拦截器,把参数值按照名字设置到对象的属性里。

值栈的生命周期

1、每一个请求都会产生一个值栈对象,放在request的域中,名字叫struts.valueStack
2、值栈的生命周期同request的生命周期,如果请求的是action,值栈的生命周期同action的生命周期
3、值栈贯穿整个Action的生命周期

三、OGNL表达式对值栈的操作方法
1.Struts2支持的表达式语言
在这里插入图片描述
2.#号的用法(重点)

  • 作用:从值栈的上下文栈中取值。如果不加#,就是优先从对象栈里取;
  • 可以取pageContext,request,session,application,attr,parameters;
  • attr:依次寻找pageContext---->request---->session----->application
  • parameters:取请求中的参数值,取出的是一个数组,再通过[0]取出具体的值
    在这里插入图片描述
    在测试时,访问ValueStack2Action要带上一个参数,这样才能取到参数值
    在这里插入图片描述
    在这里插入图片描述

#还可以用来构造Map集合和List集合
在这里插入图片描述
在这里插入图片描述

%号的用法
在这里插入图片描述

$号的用法
作用:用于在配置文件(struts.xml )里取值栈里的值。

<action name="valueStack3" class="cn.icbc.action.ValueStack3Action">
			<result type="redirect">
				/valueStack3.jsp?username=${username}
			</result>
</action>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值