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="list" status="li"> <s:property value="name"/> <s:property value="title"/> <s:property value="content"/> <s:property value="lastDate"/> <form action="reply.action"> <input type="hidden" name="leaveWord_id" value="${id}"> <input type="submit" value="回复"> </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的生命周期
博文为原创,如需转载,请标注原处,谢谢。