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 {
这里贴一部分。
现在来说说值栈的具体作用:
当用户发出一个请求,产生一个request,随即产生一个valueStack,然后Action中的setXX()方法,添加到值栈中,然后struts2根据响应的内容跳转到下一个jsp页面中,这个页面可以通过s标签或者el表达式去获取属性值。
<%@ 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>
最后,详细的说一下s标签或者el表达式是如何拿到属性值的(值栈的工作原理):
1 /** 2 * Gets the override map if anyone exists. 3 * 4 * @return the override map, <tt>null</tt> if not set. 5 */ 6 public abstract Map<Object, Object> getExprOverrides(); 7 8 /** 9 * Get the CompoundRoot which holds the objects pushed onto the stack 10 * 11 * @return the root 12 */ 13 public abstract CompoundRoot getRoot();
上面的root是一个真正的栈结构,而Map就是ActionContext.
当s标签获取属性值时,先从root中找,看有没有,然后再从map中找。
另外,值栈的生命周期 = Request的生命周期,ActionContext的生命周期 = session的生命周期
博文为原创,如需转载,请标注原处,谢谢。