今天学习了struts2的值栈正好用博客和大家分享下学习过程。
值栈,我们通过8个问题来总结学习
问题一:什么是值栈(ValueStack)
ValueStack 是 struts2 定义的一个接口规范,struts2 为该接口提供了实现OgnlValueStack(也有人会把值栈叫做ognl上下文对象)
值栈的作用:
值栈的生命周期:
问题二:值栈的内部结构(重点)
ValueStack valueStack = ActionContext.getContext().getValueStack();
我们dbug看一下这个值栈内都有什么。
其中引用的标记为 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 是什么关系(了解)
问题四:如何获得值栈对象ValueStack(了解)
//第一种方式
ValueStack valueStack = ActionContext.getContext().getValueStack();
//第二种方式
HttpServletRequest request = ServletActionContext.getRequest();
request.getAttribute("struts.valueStack");
public static final String STRUTS_VALUESTACK_KEY = "struts.valueStack";
问题五:如何手动向值栈保存数据 (了解)
向root栈存储数据---ArrayList
ValueStack valueStack = ActionContext.getContext().getValueStack();
CompoundRoot root = valueStack.getRoot();
root.add("nanjin2");
root.add(0, "nanjin");
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框架会将哪些数据自动保存到值栈中(重点)
<%@taglib prefix="s" uri="/struts-tags" %>
然后写<s:dbug></s:dbug>这样可以看到值栈内部的数据
作用:可以直接获得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表达式” /> Object object = valueStack.getContext().put("cc", "cc");
jsp:
<s:property value ="cc"/><br>
<s:property value ="#cc"/>
取出集合中的每一个元素
<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能访问值栈中的数据的原因