Strut2的Action类通过属性可以获得所有相关的值,如请求参数属性值等。要获得这些参数值,我们要做的唯一一件事就是在Action类中声明与参数同名的属性。在Struts2调用Action类的Action方法(默认是execute方法)之前,就会为相应的Action属性赋值。要完成这个功能,有很大程度上,Struts2要依赖于ValueStack对象。这个对象贯穿整个Action的生命周期,每个Action类的对象实例会拥有一个ValueStack对象。
当Struts2接收到一个.action的请求后,会先建立Action类的对象实例,但并不会调用Action方法,而是先将Action类的相应属性放到ValueStack对象的顶层节点(ValueStack对象相当于一个栈)。只是所有的属性值都是默认的值,如String类型的属性值为null,int类型的属性值为0等。在处理完上述工作后,Struts 2就会调用拦截器链中的拦截器,这些拦截器会根据用户请求参数值去更新ValueStack对象顶层节点的相应属性的值,最后会传到Action对象,并将ValueStack对象中的属性值,赋给Action类的相应属性。当调用完所有的拦截器后,才会调用Action类的Action方法。ValueStack会在请求开始时被创建,请求结束时消亡。
1. 关于值栈:
1). helloWorld 时, ${productName} 读取 productName 值, 实际上该属性并不在 request 等域对象中, 而是从值栈中获取的.
2). ValueStack:
I. 可以从 ActionContext 中获取值栈对象
II. 值栈分为两个逻辑部分
> Map 栈: 实际上是 OgnlContext 类型, 是个 Map, 也是对 ActionContext 的一个引用. 里边保存着各种 Map:
requestMap, sessionMap, applicationMap, parametersMap, attr
> 对象栈: 实际上是 CompoundRoot 类型, 是一个使用 ArrayList 定义的栈. 里边保存各种和当前 Action 实例相关的对象.
是一个数据结构意义的栈.
这三个方法就是栈的理解
public Object peek(){
return get(0); //获取第一个对象
}
public Object pop(){
return remove(0); //出栈,把第一个对象取出来
}
public void push(Object o){
add(0,o); //压栈,把对象放到第一个位置。
}
2. Struts2 利用 s:property 标签和 OGNL 表达式来读取值栈中的属性值
1). 值栈中的属性值:
> 对于对象栈: 对象栈中某一个对象的属性值
> Map 栈: request, session, application 的一个属性值 或 一个请求参数的值.
2). 读取对象栈中对象的属性:
> 若想访问 Object Stack 里的某个对象的属性. 可以使用以下几种形式之一:
object.propertyName ; object['propertyName'] ; object["propertyName"]
> ObjectStack 里的对象可以通过一个从零开始的下标来引用. ObjectStack 里的栈顶对象可以用 [0] 来引用,
它下面的那个对象可以用 [1] 引用.
[0].message
> [n] 的含义是从第 n 个开始搜索, 而不是只搜索第 n 个对象
> 若从栈顶对象开始搜索, 则可以省略下标部分: message
> 结合 s:property 标签: <s:property value="[0].message" /> <s:property value="message" />
3). 默认情况下, Action 对象会被 Struts2 自动的放到值栈的栈顶.
例子步骤:
·1:index.jsp主页面上
<a href="studentAction">ValueStack</a> //对应的是struts.xml中 action中的name
2:struts.xml
<package name="testValueStack" extends="struts-default"> <action name="studentAction" class="com.struts2.students.StudentAction"> <result name="success" >/pages/testValueStack.jsp</result> </action> </package>
3:创建一个student对象。
package com.struts2.students; public class Student { private String Name; private String Age; private String Banji; public String getName() { return Name; } public void setName(String name) { Name = name; } public String getAge() { return Age; } public void setAge(String age) { Age = age; } public String getBanji() { return Banji; } public void setBanji(String banji) { Banji = banji; } @Override public String toString() { return "Student [Name=" + Name + ", Age=" + Age + ", Banji=" + Banji + "]"; } }
然后写一个StudentAction
package com.struts2.students; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.util.ValueStack; public class StudentAction { public String execute(){ //1:获取值栈 ValueStack vs=ActionContext.getContext().getValueStack(); //2:创建对象,并赋值 Student student=new Student(); student.setAge("19"); student.setBanji("二班"); student.setName("陈王"); //3:把student放到Value Stack中 /*vs.getRoot().add(student);*/ vs.push(student); //这两种方式都是放到Value Stack 中 //4:把student放到Stack Context中 vs.getContext().put("student", student);
// 默认放到request中 <s:property value="#request.student2.Name"/> return "success"; } }
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="s" uri="/struts-tags" %> <!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>TestValueStack</title> </head> <body> <h1>TestValueStack</h1> A:<s:property value="[0].Name"/><br/> <!--存在ValueStack中的,取属性的值。可以直接取,也可以用下标 --> B:<s:property value="Age"/><br/> C:<s:property value="Banji"/><br/> <s:debug></s:debug> <s:property value="#student.Name"/> <!-- 存在Stack Context中的。用#引用.属性值 --> <s:property value="#request.student2.Name"/> 是同样的结果
</body> </html>
这是两个放到值栈和Stack Context中。
放到Stack Context中 值栈就没有值
放到值栈中
**当两个对象分别放到Value Stack 和Stack Context 中的时候。取的是值栈中的内容
public class StudentAction { public String execute(){ //1:获取值栈 ValueStack vs=ActionContext.getContext().getValueStack(); //2:创建对象,并赋值 Student student=new Student(); Student student2=new Student(); student2.setAge("20"); student2.setBanji("三班"); student2.setName("毅力"); student.setAge("19"); student.setBanji("二班"); student.setName("陈王"); //3:把student放到Value Stack中 /*vs.getRoot().add(student);*/ vs.push(student); //4:把student放到Stack Context中 vs.getContext().put("student2", student2); return "success"; } }
student 放到值栈中。student2放到Context中
同一个对象放到值栈,或者Stack Context中的时候。谁在后面显示谁。
Student student=new Student(); Student student2=new Student(); student.setAge("29"); student.setBanji("三班"); student.setName("陈毅"); student2.setAge("20"); student2.setBanji("三班"); student2.setName("毅力"); student.setAge("19"); student.setBanji("二班"); student.setName("陈王");
这里显示的是陈王
**:把值放到sessionMap中,Action类实现SessionAware接口。
package com.struts2.students; import java.util.Map; import org.apache.struts2.interceptor.SessionAware; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.util.ValueStack; public class StudentAction implements SessionAware{ private Map<String,Object> session; public void setSession(Map<String, Object> arg0) { this.session=arg0; } public String execute(){ //1:获取值栈 ValueStack vs=ActionContext.getContext().getValueStack(); //2:创建对象,并赋值 Student student=new Student(); student.setAge("19"); student.setBanji("二班"); student.setName("陈王"); /*//3:把student放到Value Stack中 vs.getRoot().add(student); vs.push(student);*/ //4:把student放到Stack Context中 session.put("student", student); return "success"; } }
在页面上取值:
<s:property value="#session.student.Name"/>