04.Struts2中的值栈-02

04.Struts2中的值栈-02

一 什么是值栈

值栈: struts2中提供的一种类似于域对象的工具, 用于struts2中的存值和取值.

每次访问Action的时候, 都会创建一个action对象, 而每个action对象中都存在一个值栈对象

值栈对象的声明周期与Action的生命周期(第一次访问action的时候被创建, 当action中方法返回值时被销毁)致.

二 Action中值栈对象的获取方法

每个action只对应一个值栈对象. 值栈对象可以通过ActionContext对象中的方法获取.

​ ActionContext context = ActionContext.getContext();
​ ValueStack valueStack = context.getValueStack();

三 值栈的结构

值栈内部主要由两部分构成: root和context;

root --> compoundroot extends ArrayList --> root是由list集合构成的

context --> ognlcontext implements Map --> context是由map集合构成的

可以通过ognl表达式中的 <<s:debug> >标签查看值栈的内部结构

在值栈中, 操作的数据一般是root数据(默认的在action中没有任何操作时, root栈顶元素就是action的引用). 而context中主要存放的是一些对象的引用.

OgnlContext的主要结构为:request, session, application, parameters, attr, 他们对应的值分别是:request对象的引用, HttpSession的引用, ServletContext对象的引用, 请求参数(action后面的请求参数), 获取域对象.

四 值栈中存放数据

4.1 通过值栈对象中的set方法

//1.通过值栈中的set方法,往值栈的root中存值
ActionContext context = ActionContext.getContext();
ValueStack stack = context.getValueStack();
stack.set("key", "value");

4.2 通过值栈对象中的put方法存值

//2.通过值栈中的push方法,往栈顶添加值
stack.push("TopstackElement");

4.3 在action中定义成员变量并生成相应的set方法

1> 值栈中存放基本数据类型
package com.rodge.stack;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

public class SaveValueStack extends ActionSupport {
    //设置序列化版本号
    private static final long serialVersionUID = 1L;
    private String username = "";
    public String getUsername() {
        return username;
    }
    @Override
    public String execute() throws Exception {     
        //3.通过成员变量+get方法,设置值栈中的值,不用单独分配内存空间
        username = "stackValue";
        return "save";
    }
}

2> 值栈中存放对象
package com.rodge.stack;
import com.opensymphony.xwork2.ActionSupport;
public class SaveObjectInStack extends ActionSupport {
    private static final long serialVersionUID = 1L;
    private User user = new User();
    public User getUser() {
        return user;
    }
    @Override
    public String execute() throws Exception {
        user.setUsername("小新");
        user.setAddress("Japen");
        user.setDesc("6毛");
        return "save";
    }  
}

3> 将集合存放在值栈中
package com.rodge.stack;
import java.util.ArrayList;
import java.util.List;
import com.opensymphony.xwork2.ActionSupport;
public class ListStackAction extends ActionSupport {
 static final long serialVersionUID = 1L;
    private List<User> list = new ArrayList<User>();
    public List<User> getList() {
        return list;
    }
    @Override
    public String execute() throws Exception {
        User user1 = new User();
        user1.setUsername("小明");
        user1.setAddress("北京");
        user1.setDesc("教师外面");


        User user2 = new User();
        user2.setUsername("小王");
        user2.setAddress("隔壁");
        user2.setDesc("小王叔叔");


        list.add(user1);
        list.add(user2);
        return "list";
    }
}

五 在jsp页面中获取值栈数据

使用struts2标签和ognl表达式获取值栈数据

<%@ taglib uri="/struts-tags" prefix="s" %>

5.1 获取值栈中的字符串数据

<s:property value=“username” />

5.2 获取值栈中存放的对象数据

<s:property value="user.username" />
<s:property value="user.address" />
<s:property value="user.desc" />

5.3 获取值栈中存放的list集合

<!-- 第一种获取list集合的方法 -->
<s:property value="list[0].username" />
<s:property value="list[0].address" />
<s:property value="list[0].desc" />
<hr/>
<!-- 第二种获取list集合中数据的方法 -->
<s:iterator value="list">
    <s:property value="username" />
    ----
    <s:property value="address" />
    ----
    <s:property value="desc" />
    <br/>
</s:iterator>
<hr/>

<!-- 第三种获取list集合中数据的方法 -->
<s:iterator value="list" var="user">
    <s:property value="#user.username" />
    --------
    <s:property value="#user.address" />
    --------
    <s:property value="#user.desc" />
    <br/>
</s:iterator>

5.4 值栈中获取其他数据

1> 获取始终值栈对象的set方法存放在值栈中的数据stack.set("key", "value");
<s:property value="key" />

2>使用值栈对象里面的push方法把数据放到值栈里面

<!-- 获取push方法存放到值栈中的数据 -->
    获取push方法存放到值栈中的数据:
    <s:property value="[0].top" />

3> 位什么EL表达式可以获取值栈中的数据

  EL表达式并不是直接获取值栈中的数据. 是因为struts2中增强了reqeust总的getAttribute方法, 增强的getAttribute方法首先会在request域中寻找是否有值, 如果request域中有, 则直接返回; 如果域对象里面如果没有值,得到值栈对象,从值栈对象里面把值获取到,最后放到域对象里面.

六 Ognl中#和%的使用

1 #: 获取context里面的数据

在这里插入图片描述

2 %: 的使用

(1)使用struts2的表单标签,显示值,使用ognl表达式

写ognl作为字符串显示出来,没有作为ognl表达式执行

(2)使用%让表单标签里面值作为ognl执行

*值栈的内部结构*

OnglValueStack源码

public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessValueStack {
    CompoundRoot root;
    transient Map<String, Object> context;
}

CompoundRoot源码

public class CompoundRoot extends ArrayList {
    public CompoundRoot() {
    }
    public CompoundRoot(List list) {
        super(list);
    }
    public CompoundRoot cutStack(int index) {
        return new CompoundRoot(subList(index, size()));
    }
    public Object peek() {
        return get(0);
    }
    public Object pop() {
        return remove(0);
    }
    public void push(Object o) {
        add(0, o);
    }
}

由以上源码可以看出,OnglValueStack有两部分,一部分是继承ArrayList实现的一个栈结构,一个就是之前介绍过的,在《ContextMap详解》中介绍过的ContextMap。

关于ContextMap的介绍,这里不再给出,可以参考之前的博客《ContextMap详解》,这里分析下栈结构,也就是CompoundRoot,也就是OGNL三大要素之一的根对象(root),可以参考《ONGL基本使用 》。

*CompoundRoot*

  • CompoundRoot:存储了action实例,它作为OgnlContext的Root对象。

CompoundRoot继承ArrayList 实现压栈和出栈功能,拥有栈的特点,先进后出,后进先出,最后压进栈的数据在栈顶。

struts2对原OGNL作出的改进就是Root使用CompoundRoot(自定义栈),使用OnglValueStack

的findValue方法可以在CompoundRoot中从栈顶向栈底查找对象的属性值。

CompoundRoot作为OgnlContext的Root对象,并且在CompoundRoot中action实例位于栈顶, 当读取achon的属性值时会先从栈顶对象中查找对应的属性,如果找不到则继续查找栈中的其它对象, 如果未找到则到ContextMap中去查找,未找到,则返回null。

案例

package com.pc.web.action;
 
import com.itheima.domain.Student;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;
 
/**
 * ValueStack存值取值操作
 * @author Switch
 * 当我们不操作值栈时,默认的栈顶对象是:当前执行的动作类
 */
public class ActionTest2 extends ActionSupport {
 
    private String name="泰斯特";
    /**
     * @return
     */
    public String demo2(){
        //1.获取ActionContext
        //从当前线程上获取
        ActionContext context = ActionContext.getContext();
        //2.使用ActionContext中的方法获取ValueStack
        //context.get(ValueStack.VALUE_STACK)
        //context.get("com.opensymphony.xwork2.util.ValueStack.ValueStack");
        // 
        //也可以通过request域获取值栈
        //ServletActionContext.getRequest().getAttribute("struts.valueStack");
        ValueStack vs = context.getValueStack();
        //3.压栈操作:把一个学生对象压入栈顶
        Student s = new Student();
        s.setName("switch");
        s.setAge(20);
        //压栈操作
        vs.push(s);
 
        return SUCCESS;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
}
<%@page import="com.opensymphony.xwork2.util.ValueStack"%>
<%@page import="com.opensymphony.xwork2.ActionContext"%>
<%@ 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>ValueStack的操作</title>
</head>
<body>
<%--1、取出ValueStack中第一个name属性的值
借助s:property标签来获取。
取值栈中的数据:直接写属性名称,获取的就是属性值。不需要使用#号。
OGNL表达式在获取值栈数据时,默认情况下都是从栈顶逐个对象往下寻找,寻找属性一致的,把属性值取出来。
只要找到之后,就不再继续寻找。
OGNL表达式获取值栈中的数据,只能是根据属性名称获取属性值。
--%>
Name:<s:property value="name"/><br/>
Age:<s:property value="age"/>
<hr/>
<%--2、获取指定位置属性值
    使用的OGNL表达式是:[x].name
    x指的是值栈中对象的索引位置。
--%>
Name1:<s:property value="[0].name"/><br/>
Name2:<s:property value="[1].name"/><br/>
<hr/>
<%--3、当我们使用s:property标签时,没有使用value属性,获取的是栈顶对象。
    当我们不操作值栈时,默认的栈顶对象是:当前执行的动作类
 --%>
<s:property/>
<hr/>
<%--4、OGNL表达式在OGNL上下文中查找数据时涉及的方法
    不管是在Map中找,还是在值栈中找,对应的方法只有一个。
    ValueStack的对象中的findValue(String expr)方法。参数的含义:是一个OGNL表达式
 --%>
 <% ActionContext context = ActionContext.getContext();
     ValueStack vs = context.getValueStack();
     Object o1 = vs.findValue("name");
     out.println("name is "+o1);
     out.println("<br/>");
     Object o2 = vs.findValue("[1].name");
     out.println("name1 is "+o2);
     out.println("<br/>");
     Object o3 = vs.findValue("#session.sessionMap3");
     out.println(o3);
     out.println("<br/>");
     Object o4 = vs.findValue("#application.applicationAttr");
     out.println(o4);%>
<s:debug></s:debug>
</body>
</html>

OgnlValueStack中push和set的区别

public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessValueStack {
    CompoundRoot root;
    public void push(Object o) {
        root.push(o);
    }
 
    public void set(String key, Object o) {
        //set basically is backed by a Map pushed on the stack with a key being put on the map and the Object being the value
        Map setMap = retrieveSetMap();
        setMap.put(key, o);
    }
 
    private Map retrieveSetMap() {
        Map setMap;
        Object topObj = peek();
        if (shouldUseOldMap(topObj)) {
            setMap = (Map) topObj;
        } else {
            setMap = new HashMap();
            setMap.put(MAP_IDENTIFIER_KEY, "");
            push(setMap);
        }
        return setMap;
    }
 
    public Object peek() {
        return root.peek();
    }
 
    private boolean shouldUseOldMap(Object topObj) {
        return topObj instanceof Map && ((Map) topObj).get(MAP_IDENTIFIER_KEY) != null;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值