首页 > 代码库 > struts2 ValueStack(值栈)解析

struts2 ValueStack(值栈)解析

Struts2一个重要点就是值栈。

ValueStack,是用来存储一些在各个action,或者说是通过s标签、el表达式等给前台Jsp等页面展示的东西。

  ValueStack是一个接口,其内部接口非常简单:

  1 /*
  2  * Copyright 2002-2007,2009 The Apache Software Foundation.
  3  * 
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  * 
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  * 
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 package com.opensymphony.xwork2.util;
 17 
 18 import java.util.Map;
 19 
 20 /**
 21  * ValueStack allows multiple beans to be pushed in and dynamic EL expressions to be evaluated against it. When
 22  * evaluating an expression, the stack will be searched down the stack, from the latest objects pushed in to the
 23  * earliest, looking for a bean with a getter or setter for the given property or a method of the given name (depending
 24  * on the expression being evaluated).
 25  */
 26 public interface ValueStack {
 27 
 28     public static final String VALUE_STACK = "com.opensymphony.xwork2.util.ValueStack.ValueStack";
 29 
 30     public static final String REPORT_ERRORS_ON_NO_PROP = "com.opensymphony.xwork2.util.ValueStack.ReportErrorsOnNoProp";
 31 
 32     /**
 33      * Gets the context for this value stack. The context holds all the information in the value stack and it‘s surroundings.
 34      *
 35      * @return  the context.
 36      */
 37     public abstract Map<String, Object> getContext();
 38 
 39     /**
 40      * Sets the default type to convert to if no type is provided when getting a value.
 41      *
 42      * @param defaultType the new default type
 43      */
 44     public abstract void setDefaultType(Class defaultType);
 45 
 46     /**
 47      * Set a override map containing <code>key -> values</code> that takes precedent when doing find operations on the ValueStack.
 48      * <p/>
 49      * See the unit test for ValueStackTest for examples.
 50      *
 51      * @param overrides  overrides map.
 52      */
 53     public abstract void setExprOverrides(Map<Object, Object> overrides);
 54 
 55     /**
 56      * Gets the override map if anyone exists.
 57      *
 58      * @return the override map, <tt>null</tt> if not set.
 59      */
 60     public abstract Map<Object, Object> getExprOverrides();
 61 
 62     /**
 63      * Get the CompoundRoot which holds the objects pushed onto the stack
 64      *
 65      * @return the root
 66      */
 67     public abstract CompoundRoot getRoot();
 68 
 69     /**
 70      * Attempts to set a property on a bean in the stack with the given expression using the default search order.
 71      *
 72      * @param expr  the expression defining the path to the property to be set.
 73      * @param value the value to be set into the named property
 74      */
 75     public abstract void setValue(String expr, Object value);
 76 
 77     /**
 78      * Attempts to set a property on a bean in the stack with the given expression using the default search order.
 79      * N.B.: unlike #setValue(String,Object) it doesn‘t allow eval expression.
 80      * @param expr  the expression defining the path to the property to be set.
 81      * @param value the value to be set into the named property
 82      */
 83     void setParameter(String expr, Object value);
 84 
 85     /**
 86      * Attempts to set a property on a bean in the stack with the given expression using the default search order.
 87      *
 88      * @param expr                    the expression defining the path to the property to be set.
 89      * @param value                   the value to be set into the named property
 90      * @param throwExceptionOnFailure a flag to tell whether an exception should be thrown if there is no property with
 91      *                                the given name.
 92      */
 93     public abstract void setValue(String expr, Object value, boolean throwExceptionOnFailure);
 94 
 95     public abstract String findString(String expr);
 96     public abstract String findString(String expr, boolean throwExceptionOnFailure);
 97 
 98     /**
 99      * Find a value by evaluating the given expression against the stack in the default search order.
100      *
101      * @param expr the expression giving the path of properties to navigate to find the property value to return
102      * @return the result of evaluating the expression
103      */
104     public abstract Object findValue(String expr);
105 
106     public abstract Object findValue(String expr, boolean throwExceptionOnFailure);
107 
108     /**
109      * Find a value by evaluating the given expression against the stack in the default search order.
110      *
111      * @param expr   the expression giving the path of properties to navigate to find the property value to return
112      * @param asType the type to convert the return value to
113      * @return the result of evaluating the expression
114      */
115     public abstract Object findValue(String expr, Class asType);
116     public abstract Object findValue(String expr, Class asType,  boolean throwExceptionOnFailure);
117 
118     /**
119      * Get the object on the top of the stack <b>without</b> changing the stack.
120      *
121      * @return the object on the top.
122      * @see CompoundRoot#peek()
123      */
124     public abstract Object peek();
125 
126     /**
127      * Get the object on the top of the stack and <b>remove</b> it from the stack.
128      *
129      * @return the object on the top of the stack
130      * @see CompoundRoot#pop()
131      */
132     public abstract Object pop();
133 
134     /**
135      * Put this object onto the top of the stack
136      *
137      * @param o the object to be pushed onto the stack
138      * @see CompoundRoot#push(Object)
139      */
140     public abstract void push(Object o);
141 
142     /**
143      * Sets an object on the stack with the given key
144      * so it is retrievable by {@link #findValue(String)}, {@link #findValue(String, Class)}
145      *
146      * @param key  the key
147      * @param o    the object
148      */
149     public abstract void set(String key, Object o);
150 
151     /**
152      * Get the number of objects in the stack
153      *
154      * @return the number of objects in the stack
155      */
156     public abstract int size();
157 
158 }

和一个普通的栈没多大区别。

他的实现类就比较复杂了(其实也不复杂...)

 public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessValueStack { 

这里贴一部分。

现在来说说值栈的具体作用:

当用户发出一个请求,对应一个action,这个时候你要用相应的Action类实例化相应的action去处理,这个时候,如果你在这个Action中,加上一个ActionContext(或者其他的几个接口),如下:

 ActionContext.getContext().put("list", leaveWordsList); 

这个时候,这个list就会被放入值栈(为什么list会放入值栈将在后面写出)。

然后,你就能在另一个Action,或者是jsp页面(通过el表达式等)得到值栈中的属性。

private LeaveWordDao leaveWordDao;
    
    private LeaveWord leaveWord;
    
    private LeaveWord resultLeaveWord;
    
    public void setResultLeaveWord(LeaveWord resultLeaveWord) {
        this.resultLeaveWord = resultLeaveWord;
    }
    
    @Override
    public void setSession(Map<String, Object> arg0) {
        sessionMap = arg0;
    }
    
    @Override
    public void setApplicationContext(ApplicationContext arg0) throws BeansException {
        this.applicationContext = arg0;
    }

 

通过你在另一个Action中的属性以及setXX方法去得到,当然,这只是会得到栈顶开始出栈的第一个匹配的同名属性,如果你要得到第二个,第三个,还有别的方法。

当然,你也可以在jsp页面中得到,也就是ognl,如下:

<%@ 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>Insert title here</title>
</head>
<body>
    <s:iterator value="http://www.mamicode.com/list" status="li">
        <s:property value="http://www.mamicode.com/name"/>
        <s:property value="http://www.mamicode.com/title"/>
        <s:property value="http://www.mamicode.com/content"/>
        <s:property value="http://www.mamicode.com/lastDate"/>
        <form action="reply.action">
        <input type="hidden" name="leaveWord_id" value="http://www.mamicode.com/${id}">
            <input type="submit" value="http://www.mamicode.com/回复">
        </form>
        </br>
    </s:iterator>
</body>
</html>

 

 

接下来,说说为什么ActionContext起到这样的作用:

1    /**
2      * Sets the OGNL value stack.
3      *
4      * @param stack the OGNL value stack.
5      */
6     public void setValueStack(ValueStack stack) {
7         put(VALUE_STACK, stack);
8     }

这是ActionContext中的一部分,可以看到,它持有了ValueStack实例,既然持有实例,那么将属性存储进去就很容易了吧。

 

另外,值栈的生命周期 = Request的生命周期

博文为原创,如需转载,请标注原处,谢谢。

 

struts2 ValueStack(值栈)解析