struts2值栈&struts ognl表达式---【小白系列】0基础到熟练应用struts2框架(四)

今天学习了struts2的值栈正好用博客和大家分享下学习过程。

值栈,我们通过8个问题来总结学习

问题一:什么是值栈(ValueStack)

ValueStack 是 struts2 定义的一个接口规范,struts2 为该接口提供了实现OgnlValueStack(也有人会把值栈叫做ognl上下文对象)

值栈的作用:

作为Action与页面(jsp)进行数据传递的数据交换站,相当于request作用域(但不可以划等号)

值栈的生命周期:

Action--》ActionContext--》ValueStack
我们知道struts2集成进来时那个过滤器。我们可以跟源码去看dofilter方法,然后看createAction的方法,跟下去的话,发现,值栈是创建ActionContext时被创建的
所以我有一个可能不恰当的比喻 action(人) ActionContext(空白身份证) ValueStack(身份证上的信息) 所以这三个是密不可分的
这里说一句题外话,Action的生命周期类似request,每次访问都创建一个新的action对象。

问题二:值栈的内部结构(重点)

看了上面的介绍,大家应该可以猜到值栈该如何创建了吧。
ValueStack valueStack = ActionContext.getContext().getValueStack();
我们dbug看一下这个值栈内都有什么。


我们只需要注意这两个点,我们可以看一下后面的值,OgnlContext,可以去看一下源码,它实现了Map集合接口,所以本质上就是个Map,CompoundRoot继承ArrayList,所以本质是个list集合。

在context还维护着valueStack的引用

其中引用的标记为 com.opensymphony.xwork2.util.ValueStack.ValueStack

  	     ActionContext context = ActionContext.getContext();
	     ValueStack valueStack = context.getValueStack();
	     Object object = valueStack.getContext().get("com.opensymphony.xwork2.util.ValueStack.ValueStack");
	     System.out.println(object==valueStack);//true


问题三 : 值栈对象何时创建?ValueStack 和 ActionContext 是什么关系(了解)



我们来看一下源码,首先创建一个值栈对象,然后把值栈对象的getContext()当做构造参数给ActionContext,因为我们知道Context中维护了一份值栈的地址,所以ActionContext可以直接获得值栈。

何时创建以及关系,ValueStack随着ActionContext的创建而创建,随着ActionContext的消失而消失

问题四:如何获得值栈对象ValueStack(了解)

	        //第一种方式
		ValueStack valueStack = ActionContext.getContext().getValueStack();
		//第二种方式
		HttpServletRequest request = ServletActionContext.getRequest();
		request.getAttribute("struts.valueStack");

其中第二种方式是跟踪源码得知的,这里我提供一下追源码的思路,有兴趣的同学可以试一下

StrutsPrepareAndExecuteFilter这个类的dofilter方法中的 execute.executeAction(request, response, mapping);
查看实现,dispatcher.serviceAction(request, response, mapping);查看实现 request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
查看STRUTS_VALUESTACK_KEY可以得知它在request域中存了个值栈,名字叫

 public static final String STRUTS_VALUESTACK_KEY = "struts.valueStack";

问题五:如何手动向值栈保存数据 (了解)

向root栈存储数据---ArrayList


因为本质是ArrayList,所以我们可以直接使用list的add方法
          
		ValueStack valueStack = ActionContext.getContext().getValueStack();
	  	 CompoundRoot root = valueStack.getRoot();
	 	  root.add("nanjin2");
	 	  root.add(0, "nanjin");


我们的值栈也提供了专门的方法,push pop peek
root.push("nj");
这句话的意思把nj压进栈顶,相当于add(0,"nj")
root.peek();
获取栈顶的数据,相当于get(0)
root.pop();
弹栈,相当于remove(0)

向context栈存储数据---Map

	    ValueStack valueStack = ActionContext.getContext().getValueStack();
	    Map<String, Object> context = valueStack.getContext();
	    context.put("name", "nanjin");


直接使用ValueStack对象存储数据

在开发中,我们常说的向值栈中存入数据,实际上就是在操作root栈,

	     ValueStack valueStack = ActionContext.getContext().getValueStack();
	     valueStack.push("hello i'm nanjin ");//root.push
	     Object peek = valueStack.peek();//root.peek()
	     Object pop = valueStack.pop();//root.pop()
             valueStack.set("name", "nanjin");//存到栈顶有标记的那个map

问题六 : struts2框架会将哪些数据自动保存到值栈中(重点)

首先我们可以新建一个jsp页面,并由action跳转到此jsp,jsp页面需要引入struts标签库
  <%@taglib prefix="s" uri="/struts-tags" %>

然后写<s:dbug></s:dbug>这样可以看到值栈内部的数据

1)会将当前访问的Action对象放到Root栈中
作用:可以直接获得Action的属性值
在开发中 可以将需要存储的数据 作为该Action的属性并提供get方法
        
private String test ="test1";
	public String getTest() {
		return test;
	}


2)会将当前的模型对象放到root栈中
作用:根据模型对象的属性名 直接获得属性值
	private Customer c =new Customer();
	@Override
	public Customer getModel() {
		// TODO Auto-generated method stub
		return c;
	}
注意压栈顺序

Action先压栈

模型对象在压栈

手动压栈

自动向context栈保存的数据 (了解)

  request对象

                  respone对象

                  servletContext对象

                  session、application域

                  attr 所有域数据(主要就是那些mime)

                  parameters 请求参数

                  valueStack

自己去页面的值栈里面看看就行。。


问题七 : 如何取值栈的数据(重点)

findValue(key/propertyName);

从值栈的栈顶依次搜索key或propertyName 直到匹配成功 不在向下搜索

上述例子,找到北京之后, 直接打印,不再打印天津

页面取值:(重点)


页面取值我们采用struts2标签和ognl表达式

<s:property value=”ognl表达式” />

我们这里的value,直接写action里面你put的名字,例如
 Object object = valueStack.getContext().put("cc", "cc");
jsp:
<s:property value ="cc"/><br>
<s:property value ="#cc"/>

#代表从值栈的context中取值

取出集合中的每一个元素

<s:iterator value=集合 var=x>    ---x每次循环放到context栈中

<s:property value=”#x” />

</s:iterator>

 

<s:iterator value=集合>  

<s:property value=“propertyName” />

</s:iterator>

不管是否写上var 都会将集合中的每一个元素在栈顶临时存储一份

注意:

<s:property value=”ognl表达式” />

ognl表达式 不加#代表从root栈中匹配propertyName

ognl表达式 加#代表从context栈中匹配key


ognl特殊字符

     #:加上#代表从context取值  不加#从root取值

                  %:

                       struts标签默认支持ognl解析的 加上%让其不支持ognl

                       struts标签默认不支持ognl解析的 加上%让其支持ognl

                  $:在xml中解析ognl表达式

<h1>模拟体统for循环</h1>
	<s:iterator begin="1" end="5" var="i" status="status" step="2">
		<%-- <s:property value="#i"/> --%>
		<s:property value="#status.count"/>
	</s:iterator>


	<h1>struts2的if标签</h1>
	<s:if test="1>num">
		1大于3
	</s:if>
	<s:elseif test="1==num">
		1等于3
	</s:elseif>
	<s:else>
		1小于3
	</s:else>
	
	<h1>%的使用  让property不支持ognl表达式解析</h1>
	<s:property value="%{'city'}"/>
	<h1>%的使用  让表单标签支持ognl表达式解析</h1>
	<s:textfield value="city"></s:textfield>
	<s:textfield value="%{city}"></s:textfield>
	
	
	<h1>通过el取值</h1>
	${city }

问题八 :为什么 EL也能访问值栈中的数据(重点)

这里我们直接来撸一波源码
---StrutsPrepareAndExecuteFilter
---doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
---request = prepare.wrapRequest(request);
---request = dispatcher.wrapRequest(request);
---request = new StrutsRequestWrapper(request, disableRequestAttributeValueStackLookup);

---
		public Object getAttribute(String key){
				//从request域获得数据
				Object attribute = super.getAttribute(key);
				//从request域获得数据是null
				if (attribute == null){
					ValueStack stack = ctx.getValueStack();
					attribute = stack.findValue(key);
				}
				return attribute;
		}

这里我们可以看到装饰者设计模式的影子。增强了getAttribute的方法,先调用父类的getAttribute方法,如果没有找到值得花,再从值栈中找,所以这就是为什么el能访问值栈中的数据的原因


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LawsonJin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值