概述
目录
- 目录
- Servlet和Action的区别
- 什么是值栈
- 获取值栈对象
- 值栈的内部结构
- 向值栈存放数据
- 向值栈存放对象
- 向值栈存放List集合
- 从值栈获取数据
- 获取字符串
- 获取对象
- 获取List集合
- 其他操作
- EL表达式获取值栈数据
Servlet和Action的区别
在正式讲解值栈之前,我们先来了解下Servlet和Struts2中Action中的区别:
- 对于Servlet而言,默认在第一次请求访问时被创建,创建成功后驻留在内存中,直到Web应用关闭。后续对该Servlet的请求,将都使用原先创建的Servlet对象进行处理。
- 对于Action,则每次请求访问Action时,均会创建新的Action对象处理请求。
什么是值栈
在Servlet中,我们使用域对象存放数据,然后在页面中使用EL表达式获取数据。在Struts2中同样支持这样的存取操作。同时,Struts2中还提供了另一种存储机制——值栈,类似于域对象,可以存值也可以取值。如在Action中我们可以数据存储到值栈中,在页面中我们可以获取到值栈中的数据。
值栈存储的位置
每次请求访问Action时,均会创建新的Action对象处理请求。此时,在每个Action对象中都有且只有一个值栈对象。
获取值栈对象
获取值栈对象有多种方式,常用方式是通过调用ActionContext对象的getValueStack方法获取值栈对象。如:
// 1. 获取ActionContext对象
ActionContext context = ActionContext.getContext();
// 2. 调用ActionContext对象的方法获取值栈对象
ValueStack valueStack = context.getValueStack();
在每个Action对象中只有一个值栈对象。如:
ActionContext context = ActionContext.getContext();
ValueStack valueStack1 = context.getValueStack();
ValueStack valueStack2 = context.getValueStack();
System.out.println(valueStack1 == valueStack2); // 同一值栈对象
值栈的内部结构
debug标签的使用
使用struts2中的标签debug,我们可以查看值栈结构和存储值。使用如下:
通过访问Action,执行Action中的方法,返回结果,匹配返回值对应转发的JSP页面,在该JSP页面中使用该标签。(为什么不“将该标签放置为JSP页面后直接访问JSP页面”呢?因为值栈对象存在于Action中,访问Action同时也是创建Action的过程,Action对象将拥有一个值栈对象。)
VSDebugAction.java
package com.wm103.action;
import com.opensymphony.xwork2.ActionSupport;
public class VSDebugAction extends ActionSupport {
@Override
public String execute() throws Exception {
return SUCCESS;
}
}
在struts.xml中的配置:
<package name="demo1" extends="struts-default" namespace="/">
<action name="debug" class="com.wm103.action.VSDebugAction">
<result name="success">/debug.jsp</result>
</action>
</package>
debug.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--导入struts标签库--%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<html>
<head>
<title>debug标签的使用</title>
</head>
<body>
<%--使用struts2标签查看值栈结构--%>
<s:debug></s:debug>
</body>
</html>
将应用部署到服务器后访问VSDebugAction,显示debug.jsp页面,如下:
值栈内部结构
值栈分为两部分:
第一部分为root部分,以List集合方式存储数据(我们一般也是操作root这一部分的数据),如:
第二部分为context部分,以Map集合方式存储数据。如:
注:我们会发现值栈的root部分:在Action没有进行任何操作时,root部分栈顶为Action对象的引用。我们可以知道Action对象中有值栈对象,同时值栈对象中也存放着Action对象的应用。
向值栈存放数据
在Struts2中,向值栈中存放数据有多种方式:
(1)获取值栈对象,调用值栈对象的set方法存放数据。如:
ActionContext context = ActionContext.getContext();
ValueStack valueStack = context.getValueStack();
valueStack.set("vs-key", "vs-value");
debug标签显示调用set方法存放数据后值栈的结构如下(数据被存到Map集合中,最后压入值栈中,如果后续还有调用set方法存值的话,将用刚保存数据的Map集合再次保存数据):
(2)获取值栈对象,调用值栈对象的push方法存放数据。如:
ActionContext context = ActionContext.getContext();
ValueStack valueStack = context.getValueStack();
valueStack.push("abcd");
debug标签显示调用push方法存放数据后值栈的结构如下:
(3)【常用方式!】在Action定义变量,生成变量的get方法。如:
这里定义了一个username变量。
package com.wm103.action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;
/**
* Created by DreamBoy on 2017/5/27.
*/
public class ValueStackAction extends ActionSupport {
private String username;
public String getUsername() {
return username;
}
@Override
public String execute() throws Exception {
// 第一种 调用值栈的set方法存放数据
ActionContext context = ActionContext.getContext();
ValueStack valueStack = context.getValueStack();
valueStack.set("vs-key", "vs-value");
// 第二种 调用值栈的push方法存放数据
valueStack.push("abcd");
// 第三种 在Action定义变量,生成变量的get方法
this.username = "DreamBoy";
return SUCCESS;
}
}
debug标签显示存放数据后值栈的结构如下:
可以发现数据以Action成员变量的形式存入值栈中。
向值栈存放对象
实现步骤:
(1)定义对象变量(可以初始化);
(2)生成变量的get方法;
(3)在Action执行方法中给对象设置值。
案例如下:
ObjectAction.java
package com.wm103.action;
import com.opensymphony.xwork2.ActionSupport;
import com.wm103.entity.User;
public class ObjectAction extends ActionSupport {
private User user = new User();
public User getUser() {
return user;
}
@Override
public String execute() throws Exception {
this.user.setUsername("DreamBoy");
this.user.setPassword("123456");
return SUCCESS;
}
}
向值栈存放List集合
实现步骤:
(1)定义List集合变量(可以初始化);
(2)生成变量的get方法;
(3)在Action执行方法中给List集合设置值。
案例如下:
ListAction.java
package com.wm103.action;
import com.opensymphony.xwork2.ActionSupport;
import com.wm103.entity.User;
import java.util.ArrayList;
import java.util.List;
public class ListAction extends ActionSupport {
private List<User> list = new ArrayList<>();
public List<User> getList() {
return list;
}
@Override
public String execute() throws Exception {
User user1 = new User();
user1.setUsername("DreamBoy");
user1.setPassword("123456");
User user2 = new User();
user2.setUsername("DreamBoy223333");
user2.setPassword("223333");
list.add(user1);
list.add(user2);
return SUCCESS;
}
}
从值栈获取数据
使用struts2的标签property
和OGNL表达式获取值栈中的数据:<s:property value="OGNL表达式"/>
。
以下案例的Action类:
VSGetDataAction.java
package com.wm103.action;
import com.opensymphony.xwork2.ActionSupport;
public class VSGetDataAction extends ActionSupport {
// 在这里定义存入值栈中的变量
// 对应的get方法
@Override
public String execute() throws Exception {
// 在这里设置变量的值
return SUCCESS;
}
}
在struts.xml中Action的配置:
<package name="demo1" extends="struts-default" namespace="/">
<action name="vsGetData" class="com.wm103.action.VSGetDataAction">
<result name="success">/data.jsp</result>
</action>
</package>
data.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--导入struts标签库--%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<html>
<head>
<title>从值栈中获取数据</title>
</head>
<body>
<%--在这里写从值栈中获取数据的案例--%>
</body>
</html>
获取字符串
在VSGetDataAction中定义字符串并存入值栈,如下:
private String username;
public String getUsername() {
return username;
}
@Override
public String execute() throws Exception {
this.username = "Hello Struts2!";
return SUCCESS;
}
在data.jsp中获取值栈中的数据:
<s:property value="username"/>
获取对象
在VSGetDataAction中定义对象并存入值栈,如下:
private User user = new User();
public User getUser() {
return user;
}
@Override
public String execute() throws Exception {
this.user.setUsername("DreamBoy");
this.user.setPassword("123456");
return SUCCESS;
}
在data.jsp中获取值栈中的数据:
<s:property value="user.username"/>
<s:property value="user.password"/>
获取List集合
在VSGetDataAction中定义List集合对象并存入值栈,如下:
private List<User> list = new ArrayList<>();
public List<User> getList() {
return list;
}
@Override
public String execute() throws Exception {
User user1 = new User();
user1.setUsername("DreamBoy");
user1.setPassword("123456");
User user2 = new User();
user2.setUsername("DreamBoy223333");
user2.setPassword("223333");
list.add(user1);
list.add(user2);
return SUCCESS;
}
在data.jsp中获取值栈中的数据:
<%--从值栈中获取List集合数据--%>
<!--第一种方式-->
<s:property value="list[0].username"/> <s:property value="list[0].password"/><br/>
<s:property value="list[1].username"/> <s:property value="list[1].password"/>
<br/>
<!--第二种方式-->
<%--使用struts2标签中类似jstl的forEach标签的 iterator 标签,用来遍历值栈中的List集合--%>
<s:iterator value="list">
<%--遍历List得到List中每个User对象--%>
<s:property value="username"/> <s:property value="password"/><br/>
</s:iterator>
<br/>
<!--第三种方式-->
<s:iterator value="list" var="user">
<%--
遍历值栈中的List集合对象,得到每个user对象。每次遍历出来的user对象会被放到值栈中的context部分进行存储。
根据context部分数据的特点,需要写OGNL表达式,使用特殊符号#
--%>
<s:property value="#user.username"/> <s:property value="#user.password"/><br/>
</s:iterator>
其他操作
(1)调用值栈的set方法向值栈中存数据后从值栈中获取,如:
向值栈中存数据
ActionContext context = ActionContext.getContext();
ValueStack valueStack = context.getValueStack();
valueStack.set("setKey", "setValue");
从值栈中取数据
<%--调用值栈的set方法向值栈中存数据后从值栈中获取--%>
<s:property value="setKey"/>
(2)调用值栈的push方法向值栈中存数据后从值栈中获取,如:
向值栈中存数据
ActionContext context = ActionContext.getContext();
ValueStack valueStack = context.getValueStack();
valueStack.push("pushValue");
从值栈中取数据
<%--调用值栈的push方法向值栈中存数据后从值栈中获取--%>
<%--**注:向值栈中放入数据后,值栈会放数据存放到一个数组中去,并把数组名称为top,可以数组的名称获取值。**--%>
<s:property value="[0].top"/>
EL表达式获取值栈数据
这里以上述中提及的从值栈中获取List集合数据为例,使用JSTL标签和EL表达式的方式中值栈中获取数据,如:
<!--使用EL表达式获取-->
<c:forEach items="${list}" var="user">
${user.username} ${user.password}<br/>
</c:forEach>
这我就好奇了?EL表达式不是从域对象获取到数据吗?它居然可以从值栈中获取到数据?
需要明确的是,EL表达式确实是从域对象中获取值的,且是通过调用域对象的getAttribute方法获取到值的。那么它为什么能从值栈中获取值呢?
原因是struts底层增强了request对象中的getAttribute方法:从request域对象获取值时,调用了原来的getAttribute方法,如果获取到则直接返回;如果获取不到则从值栈中把值取出来(ValueStack的findValue方法获取值),再返回结果值。
那struts底层在哪里增强request对象的getAttribute方法呢?在struts2的过滤器 org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
的 doFilter
方法中开始增强的操作。
最后
以上就是无私睫毛膏为你收集整理的Struts2框架自学之路——值栈目录Servlet和Action的区别什么是值栈获取值栈对象值栈的内部结构向值栈存放数据从值栈获取数据EL表达式获取值栈数据的全部内容,希望文章能够帮你解决Struts2框架自学之路——值栈目录Servlet和Action的区别什么是值栈获取值栈对象值栈的内部结构向值栈存放数据从值栈获取数据EL表达式获取值栈数据所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复