Struts2中的ActionContext和ValueStack详解
ActionContext
我们知道Servlet是单例多线程的,容器会在线程池中为每一次请求分配一个线程。而在struts2中,每个线程会创建一个Action上下文即ActionContext,它由当前线程创建并与线程绑定在一起,也就是说依赖于请求,所以在请求未发生时,里面时没有储存信息的。作为Servlet Api的封装,ActionContext以Map容器的结构储存了哪些信息,又是怎样获取的呢?
一.获取ActionContext和存取信息
ActionContext如同一个Map类型的数据中心,不管是在jsp Action类还是非Action类均可非常方便的获取ActionContext
1)在jsp中
在jsp中无需获得ActionContext,将字符串"amy"存入ActionContext,key是"myKey":<s:set value=%{"amy"} var="myKey"/>
取出这个字符串:<s:property value="#myKey"/>
将java对象存入ActionContext,key是"myObject" :<s:bean name=%{"com.my.User"} var="myObject"/>(当OGNL表达式不能解析时使用%{ })
取出这个对象:<s:property value="#myObject"/>
其中有一些对象是由容器存入的如(这些对象是Map类型):
<s:property value="#request"/>
<s:property value="#session"/>
<s:property value="#application"/>
<s:property value="#params"/>
2)Action中
由拦截器注入或ActionContext.getContext()获得
// 存入值 Person person = new Person();// ActionContext.getContext().put("person", person); // 获取值 Object object = ActionContext.getContext().get("person");
3)过滤器中
1 publicclass MyInterceptor extends AbstractInterceptor { 2 3 public String intercept(ActionInvocation invocation) throws Exception { 4 // 获得ActionContext 5 ActionContext actionContext = invocation.getInvocationContext(); 6 // 存入值 7 Person person = new Person(); 8 actionContext.put("person", person); 9 // 获取值 10 Object value = actionContext.get("person"); 11 // 获取HttpServletRequest 12 HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST); 13 // 获取request的Map,即HttpServletRequest.getAttribute(...)和HttpServletRequest.setAttribute(...)所操作的值 14 Map requestMap = (Map) actionContext.get("request"); 15 // 其他代码 16 // ...... 17 return invocation.invoke(); 18 } 19 }
二,ActionContext中的提供方法
package com.opensymphony.xwork2; import com.opensymphony.xwork2.inject.Container; import com.opensymphony.xwork2.util.ValueStack; import java.io.Serializable; import java.util.HashMap; import java.util.Locale; import java.util.Map; public class ActionContext implements Serializable { static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>(); /** * Constant for the name of the action being executed. */ public static final String ACTION_NAME = "com.opensymphony.xwork2.ActionContext.name"; /** * Constant for the {@link com.opensymphony.xwork2.util.ValueStack OGNL value stack}. */ public static final String VALUE_STACK = ValueStack.VALUE_STACK; /** * Constant for the action's session. */ public static final String SESSION = "com.opensymphony.xwork2.ActionContext.session"; /** * Constant for the action's application context. */ public static final String APPLICATION = "com.opensymphony.xwork2.ActionContext.application"; /** * Constant for the action's parameters. */ public static final String PARAMETERS = "com.opensymphony.xwork2.ActionContext.parameters"; /** * Constant for the action's locale. */ public static final String LOCALE = "com.opensymphony.xwork2.ActionContext.locale"; /** * Constant for the action's type converter. */ public static final String TYPE_CONVERTER = "com.opensymphony.xwork2.ActionContext.typeConverter"; /** * Constant for the action's {@link com.opensymphony.xwork2.ActionInvocation invocation} context. */ public static final String ACTION_INVOCATION = "com.opensymphony.xwork2.ActionContext.actionInvocation"; /** * Constant for the map of type conversion errors. */ public static final String CONVERSION_ERRORS = "com.opensymphony.xwork2.ActionContext.conversionErrors"; /** * Constant for the container */ public static final String CONTAINER = "com.opensymphony.xwork2.ActionContext.container"; private Map<String, Object> context; /** * Creates a new ActionContext initialized with another context. * * @param context a context map. */ public ActionContext(Map<String, Object> context) { this.context = context; } /** * Sets the action invocation (the execution state). * * @param actionInvocation the action execution state. */ public void setActionInvocation(ActionInvocation actionInvocation) { put(ACTION_INVOCATION, actionInvocation); } /** * 获得当前action的代理 * * @return the action invocation (the execution state). */ public ActionInvocation getActionInvocation() { return (ActionInvocation) get(ACTION_INVOCATION); } /** * Sets the action's application context. * * @param application the action's application context. */ public void setApplication(Map<String, Object> application) { put(APPLICATION, application); } /** * 获得Map类型的application * * @return a Map of ServletContext or generic application level Map */ public Map<String, Object> getApplication() { return (Map<String, Object>) get(APPLICATION); } /** * Sets the action context for the current thread. * * @param context the action context. */ public static void setContext(ActionContext context) { actionContext.set(context); } /** * Returns the ActionContext specific to the current thread. * * @return the ActionContext for the current thread, is never <tt>null</tt>. */ public static ActionContext getContext() { return actionContext.get(); } /** * Sets the action's context map. * * @param contextMap the context map. */ public void setContextMap(Map<String, Object> contextMap) { getContext().context = contextMap; } /** * Gets the context map. * * @return the context map. */ public Map<String, Object> getContextMap() { return context; } /** * Sets conversion errors which occurred when executing the action. * * @param conversionErrors a Map of errors which occurred when executing the action. */ public void setConversionErrors(Map<String, Object> conversionErrors) { put(CONVERSION_ERRORS, conversionErrors); } /** * Gets the map of conversion errors which occurred when executing the action. * * @return the map of conversion errors which occurred when executing the action or an empty map if * there were no errors. */ public Map<String, Object> getConversionErrors() { Map<String, Object> errors = (Map) get(CONVERSION_ERRORS); if (errors == null) { errors = new HashMap<String, Object>(); setConversionErrors(errors); } return errors; } /** * Sets the Locale for the current action. * * @param locale the Locale for the current action. */ public void setLocale(Locale locale) { put(LOCALE, locale); } /** * Gets the Locale of the current action. If no locale was ever specified the platform's * {@link java.util.Locale#getDefault() default locale} is used. * * @return the Locale of the current action. */ public Locale getLocale() { Locale locale = (Locale) get(LOCALE); if (locale == null) { locale = Locale.getDefault(); setLocale(locale); } return locale; } /** * Sets the name of the current Action in the ActionContext. * * @param name the name of the current action. */ public void setName(String name) { put(ACTION_NAME, name); } /** * Gets the name of the current Action. * * @return the name of the current action. */ public String getName() { return (String) get(ACTION_NAME); } /** * Sets the action parameters. * * @param parameters the parameters for the current action. */ public void setParameters(Map<String, Object> parameters) { put(PARAMETERS, parameters); } /** * Returns a Map of the HttpServletRequest parameters when in a servlet environment or a generic Map of * parameters otherwise. * * @return a Map of HttpServletRequest parameters or a multipart map when in a servlet environment, or a * generic Map of parameters otherwise. */ public Map<String, Object> getParameters() { return (Map<String, Object>) get(PARAMETERS); } /** * Sets a map of action session values. * * @param session the session values. */ public void setSession(Map<String, Object> session) { put(SESSION, session); } /** * Gets the Map of HttpSession values when in a servlet environment or a generic session map otherwise. * * @return the Map of HttpSession values when in a servlet environment or a generic session map otherwise. */ public Map<String, Object> getSession() { return (Map<String, Object>) get(SESSION); } /** * Sets the OGNL value stack. * * @param stack the OGNL value stack. */ public void setValueStack(ValueStack stack) { put(VALUE_STACK, stack); } /** * Gets the OGNL value stack. * * @return the OGNL value stack. */ public ValueStack getValueStack() { return (ValueStack) get(VALUE_STACK); } /** * Gets the container for this request * * @param cont The container */ public void setContainer(Container cont) { put(CONTAINER, cont); } /** * Sets the container for this request * * @return The container */ public Container getContainer() { return (Container) get(CONTAINER); } public <T> T getInstance(Class<T> type) { Container cont = getContainer(); if (cont != null) { return cont.getInstance(type); } else { throw new XWorkException("Cannot find an initialized container for this request."); } } /** * Returns a value that is stored in the current ActionContext by doing a lookup using the value's key. * * @param key the key used to find the value. * @return the value that was found using the key or <tt>null</tt> if the key was not found. */ public Object get(String key) { return context.get(key); } /** * Stores a value in the current ActionContext. The value can be looked up using the key. * * @param key the key of the value. * @param value the value to be stored. */ public void put(String key, Object value) { context.put(key, value); } }
1)get方法
ActionContext actionContext=ActionContext.getContext(); //提供静态的方法获得实例对象,保证一次请求中数据同步,线程安全。
get("key")可以获取开发者放入的String 或自定义类型的数据,也可以获取容器已经放入的范围对象和容器。
Map类型的"范围对象":
Map<String,Object> requestMap=(Map<String,Object>)actionContext.get("request");
Map<String,Object> sessionMap=(Map<String,Object>)actionContext.get("session");
HttpServlet原生的范围对象:
HttpServletRequest request=(HttpServletRequest)actionContext.get(StrutsStatics.HTTP_REQUEST);
requestMap是Struts对request的封装,request方法setAttribute(key,vakue)对应的值放入requestMap中,实现对Servlet的解耦。除此之外他们的作用范围和生命周期是相同的。类似的还有HttpServletSession类型的session 和Map类型的sessionMap HttpServletContext类型的context和Map类型的applicationMap request.getParameter("")获得的参数和paramters类型的Map
2)public ActionInvocation getActionInvocation()
获得当前Action的代理对象,其底层也是get方法实现的,其中的参数是事先定好的常量。
3)public Map<String, Object> getApplication()
底层实现:(Map<String, Object>) get(APPLICATION)
4)public Map<String, Object> getContextMap()
获得上下文对应的容器
5) public Locale getLocale() { //获得本地对象
Locale locale = (Locale) get(LOCALE);
if (locale == null) {
locale = Locale.getDefault();
setLocale(locale);
}
6) public Container getContainer() { //获得请求容器
return (Container) get(CONTAINER);
}
7)public Map<String, Object> getParameters() {
return (Map<String, Object>) get(PARAMETERS);
}
由请求参数和请求值封装而成的Map容器。
8)public Map<String, Object> getSession()
同上
9) public ValueStack getValueStack() { return (ValueStack) get(VALUE_STACK); }
获得值栈对象
10) public String getName() { return (String) get(ACTION_NAME);}
获得当前action的名字
三,ValueStack
ValueStack是struts的栈值对象接口。在发生请求时随Action的创建而产生,每一个Action对应一个ValueStack,在Action移除时消失。他的作用是储存数据,一个变量对应一个值(这里先不讨论他的实现类)
1,获得当前ValueStack的方法
1)jsp中:无需获取,直接使用标签即可
2)在java代码中,ValueSatck valueStack=ActionContext.getContext().getValueStack();
2,提供的方法
public abstract String findString(String expr);//利用默认的搜索规则,根据路径表达式获取key值 public abstract String findString(String expr, boolean throwExceptionOnFailure); /** * Find a value by evaluating the given expression against the stack in the default search order. * * @param expr the expression giving the path of properties to navigate to find the property value to return * @return the result of evaluating the expression */ public abstract Object findValue(String expr); //利用默认的搜索规则,根据路径表达式获取值 public abstract Object findValue(String expr, boolean throwExceptionOnFailure); // /** * Find a value by evaluating the given expression against the stack in the default search order. * * @param expr the expression giving the path of properties to navigate to find the property value to return * @param asType the type to convert the return value to * @return the result of evaluating the expression */ public abstract Object findValue(String expr, Class asType);//利用默认的搜索规则,根据路径表达式和类型获取值 public abstract Object findValue(String expr, Class asType, boolean throwExceptionOnFailure); /** * Get the object on the top of the stack <b>without</b> changing the stack. * * @return the object on the top. * @see CompoundRoot#peek() */ public abstract Object peek();//获取栈顶的元素(不改变原栈值对象) /** * Get the object on the top of the stack and <b>remove</b> it from the stack. * * @return the object on the top of the stack * @see CompoundRoot#pop() */ public abstract Object pop();//移除并返回栈顶的元素 /** * Put this object onto the top of the stack * * @param o the object to be pushed onto the stack * @see CompoundRoot#push(Object) */ public abstract void push(Object o);//将对象压入栈内 /** * Sets an object on the stack with the given key * so it is retrievable by {@link #findValue(String)}, {@link #findValue(String, Class)} * * @param key the key * @param o the object */ public abstract void set(String key, Object o);//给栈内的元素设置值 /** * Get the number of objects in the stack * * @return the number of objects in the stack */ public abstract int size();//返回元素数量
3,默认实现类OGNLValueStack
OGNLValueStack是ValueStack的默认实现类,Struts2根据OGNL表达式语言,利用栈值的形式在界面和后台之间传递数据,另外提供诸如集合的投影和过滤以及lambda表达式等。OGNLValueStack在OGNL基础上对对象属性的存取做的些许改动。
package com.opensymphony.xwork2.ognl; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.TextProvider; import com.opensymphony.xwork2.XWorkConstants; import com.opensymphony.xwork2.XWorkException; import com.opensymphony.xwork2.conversion.impl.XWorkConverter; import com.opensymphony.xwork2.inject.Container; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor; import com.opensymphony.xwork2.util.ClearableValueStack; import com.opensymphony.xwork2.util.CompoundRoot; import com.opensymphony.xwork2.util.MemberAccessValueStack; import com.opensymphony.xwork2.util.ValueStack; import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; import com.opensymphony.xwork2.util.logging.LoggerUtils; import com.opensymphony.xwork2.util.reflection.ReflectionContextState; import ognl.*; import java.io.Serializable; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessValueStack { public static final String THROW_EXCEPTION_ON_FAILURE = OgnlValueStack.class.getName() + ".throwExceptionOnFailure"; private static final long serialVersionUID = 370737852934925530L; private static final String MAP_IDENTIFIER_KEY = "com.opensymphony.xwork2.util.OgnlValueStack.MAP_IDENTIFIER_KEY"; private static final Logger LOG = LoggerFactory.getLogger(OgnlValueStack.class); //CompoundRoot继承了ArraryList,提供了额外的方法:push()和pop()方法,所以它相当于栈结构 <span style="color:#FF0000;">CompoundRoot root; transient Map<String, Object> context; Class defaultType; Map<Object, Object> overrides; transient OgnlUtil ognlUtil; transient SecurityMemberAccess securityMemberAccess;</span> private boolean devMode; private boolean logMissingProperties; protected OgnlValueStack(XWorkConverter xworkConverter, CompoundRootAccessor accessor, TextProvider prov, boolean allowStaticAccess) { setRoot(xworkConverter, accessor, new CompoundRoot(), allowStaticAccess); push(prov); } protected OgnlValueStack(ValueStack vs, XWorkConverter xworkConverter, CompoundRootAccessor accessor, boolean allowStaticAccess) { setRoot(xworkConverter, accessor, new CompoundRoot(vs.getRoot()), allowStaticAccess); } @Inject public void setOgnlUtil(OgnlUtil ognlUtil) { this.ognlUtil = ognlUtil; } protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot, boolean allowStaticMethodAccess) { this.root = compoundRoot; this.securityMemberAccess = new SecurityMemberAccess(allowStaticMethodAccess); this.context = Ognl.createDefaultContext(this.root, accessor, new OgnlTypeConverterWrapper(xworkConverter), securityMemberAccess); context.put(VALUE_STACK, this); Ognl.setClassResolver(context, accessor); ((OgnlContext) context).setTraceEvaluations(false); ((OgnlContext) context).setKeepLastEvaluation(false); } @Inject(XWorkConstants.DEV_MODE) public void setDevMode(String mode) { devMode = "true".equalsIgnoreCase(mode); } @Inject(value = "logMissingProperties", required = false) public void setLogMissingProperties(String logMissingProperties) { this.logMissingProperties = "true".equalsIgnoreCase(logMissingProperties); } /** * @see com.opensymphony.xwork2.util.ValueStack#getContext() */ public Map<String, Object> getContext() { return context; } /** * @see com.opensymphony.xwork2.util.ValueStack#setDefaultType(java.lang.Class) */ public void setDefaultType(Class defaultType) { this.defaultType = defaultType; } /** * @see com.opensymphony.xwork2.util.ValueStack#setExprOverrides(java.util.Map) */ public void setExprOverrides(Map<Object, Object> overrides) { if (this.overrides == null) { this.overrides = overrides; } else { this.overrides.putAll(overrides); } } /** * @see com.opensymphony.xwork2.util.ValueStack#getExprOverrides() */ public Map<Object, Object> getExprOverrides() { return this.overrides; } /** * @see com.opensymphony.xwork2.util.ValueStack#getRoot() */ public CompoundRoot getRoot() { return root; } /** * @see com.opensymphony.xwork2.util.ValueStack#setParameter(String, Object) */ public void setParameter(String expr, Object value) { setValue(expr, value, devMode, false); } /** /** * @see com.opensymphony.xwork2.util.ValueStack#setValue(java.lang.String, java.lang.Object) */ public void setValue(String expr, Object value) { setValue(expr, value, devMode); } /** * @see com.opensymphony.xwork2.util.ValueStack#setValue(java.lang.String, java.lang.Object, boolean) */ public void setValue(String expr, Object value, boolean throwExceptionOnFailure) { setValue(expr, value, throwExceptionOnFailure, true); } private void setValue(String expr, Object value, boolean throwExceptionOnFailure, boolean evalExpression) { Map<String, Object> context = getContext(); try { trySetValue(expr, value, throwExceptionOnFailure, context, evalExpression); } catch (OgnlException e) { handleOgnlException(expr, value, throwExceptionOnFailure, e); } catch (RuntimeException re) { //XW-281 handleRuntimeException(expr, value, throwExceptionOnFailure, re); } finally { cleanUpContext(context); } } private void trySetValue(String expr, Object value, boolean throwExceptionOnFailure, Map<String, Object> context, boolean evalExpression) throws OgnlException { context.put(XWorkConverter.CONVERSION_PROPERTY_FULLNAME, expr); context.put(REPORT_ERRORS_ON_NO_PROP, (throwExceptionOnFailure) ? Boolean.TRUE : Boolean.FALSE); ognlUtil.setValue(expr, context, root, value, evalExpression); } private void cleanUpContext(Map<String, Object> context) { ReflectionContextState.clear(context); context.remove(XWorkConverter.CONVERSION_PROPERTY_FULLNAME); context.remove(REPORT_ERRORS_ON_NO_PROP); } private void handleRuntimeException(String expr, Object value, boolean throwExceptionOnFailure, RuntimeException re) { if (throwExceptionOnFailure) { String message = ErrorMessageBuilder.create() .errorSettingExpressionWithValue(expr, value) .build(); throw new XWorkException(message, re); } else { if (LOG.isWarnEnabled()) { LOG.warn("Error setting value", re); } } } private void handleOgnlException(String expr, Object value, boolean throwExceptionOnFailure, OgnlException e) { String msg = "Error setting expression '" + expr + "' with value '" + value + "'"; if (LOG.isWarnEnabled()) { LOG.warn(msg, e); } if (throwExceptionOnFailure) { throw new XWorkException(msg, e); } } /** * @see com.opensymphony.xwork2.util.ValueStack#findString(java.lang.String) */ public String findString(String expr) { return (String) findValue(expr, String.class); } public String findString(String expr, boolean throwExceptionOnFailure) { return (String) findValue(expr, String.class, throwExceptionOnFailure); } /** * @see com.opensymphony.xwork2.util.ValueStack#findValue(java.lang.String) */ public Object findValue(String expr, boolean throwExceptionOnFailure) { try { setupExceptionOnFailure(throwExceptionOnFailure); return tryFindValueWhenExpressionIsNotNull(expr); } catch (OgnlException e) { return handleOgnlException(expr, throwExceptionOnFailure, e); } catch (Exception e) { return handleOtherException(expr, throwExceptionOnFailure, e); } finally { ReflectionContextState.clear(context); } } private void setupExceptionOnFailure(boolean throwExceptionOnFailure) { if (throwExceptionOnFailure) { context.put(THROW_EXCEPTION_ON_FAILURE, true); } } private Object tryFindValueWhenExpressionIsNotNull(String expr) throws OgnlException { if (expr == null) { return null; } return tryFindValue(expr); } private Object handleOtherException(String expr, boolean throwExceptionOnFailure, Exception e) { logLookupFailure(expr, e); if (throwExceptionOnFailure) throw new XWorkException(e); return findInContext(expr); } private Object tryFindValue(String expr) throws OgnlException { Object value; expr = lookupForOverrides(expr); if (defaultType != null) { value = findValue(expr, defaultType); } else { value = getValueUsingOgnl(expr); if (value == null) { value = findInContext(expr); } } return value; } private String lookupForOverrides(String expr) { if ((overrides != null) && overrides.containsKey(expr)) { expr = (String) overrides.get(expr); } return expr; } private Object getValueUsingOgnl(String expr) throws OgnlException { try { return ognlUtil.getValue(expr, context, root); } finally { context.remove(THROW_EXCEPTION_ON_FAILURE); } } public Object findValue(String expr) { return findValue(expr, false); } /** * @see com.opensymphony.xwork2.util.ValueStack#findValue(java.lang.String, java.lang.Class) */ public Object findValue(String expr, Class asType, boolean throwExceptionOnFailure) { try { setupExceptionOnFailure(throwExceptionOnFailure); return tryFindValueWhenExpressionIsNotNull(expr, asType); } catch (OgnlException e) { return handleOgnlException(expr, throwExceptionOnFailure, e); } catch (Exception e) { return handleOtherException(expr, throwExceptionOnFailure, e); } finally { ReflectionContextState.clear(context); } } private Object tryFindValueWhenExpressionIsNotNull(String expr, Class asType) throws OgnlException { if (expr == null) { return null; } return tryFindValue(expr, asType); } private Object handleOgnlException(String expr, boolean throwExceptionOnFailure, OgnlException e) { Object ret = findInContext(expr); if (ret == null) { if (shouldLogNoSuchPropertyWarning(e)) { LOG.warn("Could not find property [" + ((NoSuchPropertyException) e).getName() + "]"); } if (throwExceptionOnFailure) { throw new XWorkException(e); } } return ret; } private boolean shouldLogNoSuchPropertyWarning(OgnlException e) { return e instanceof NoSuchPropertyException && devMode && logMissingProperties; } private Object tryFindValue(String expr, Class asType) throws OgnlException { Object value = null; try { expr = lookupForOverrides(expr); value = getValue(expr, asType); if (value == null) { value = findInContext(expr); } } finally { context.remove(THROW_EXCEPTION_ON_FAILURE); } return value; } private Object getValue(String expr, Class asType) throws OgnlException { return ognlUtil.getValue(expr, context, root, asType); } private Object findInContext(String name) { return getContext().get(name); } public Object findValue(String expr, Class asType) { return findValue(expr, asType, false); } /** * Log a failed lookup, being more verbose when devMode=true. * * @param expr The failed expression * @param e The thrown exception. */ private void logLookupFailure(String expr, Exception e) { String msg = LoggerUtils.format("Caught an exception while evaluating expression '#0' against value stack", expr); if (devMode && LOG.isWarnEnabled()) { LOG.warn(msg, e); LOG.warn("NOTE: Previous warning message was issued due to devMode set to true."); } else if (LOG.isDebugEnabled()) { LOG.debug(msg, e); } } /** * @see com.opensymphony.xwork2.util.ValueStack#peek() */ public Object peek() { return root.peek(); } /** * @see com.opensymphony.xwork2.util.ValueStack#pop() */ public Object pop() { return root.pop(); } /** * @see com.opensymphony.xwork2.util.ValueStack#push(java.lang.Object) */ public void push(Object o) { root.push(o); } /** * @see com.opensymphony.xwork2.util.ValueStack#set(java.lang.String, java.lang.Object) */ 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; } /** * check if this is a Map put on the stack for setting if so just use the old map (reduces waste) */ private boolean shouldUseOldMap(Object topObj) { return topObj instanceof Map && ((Map) topObj).get(MAP_IDENTIFIER_KEY) != null; } /** * @see com.opensymphony.xwork2.util.ValueStack#size() */ public int size() { return root.size(); } private Object readResolve() { // TODO: this should be done better ActionContext ac = ActionContext.getContext(); Container cont = ac.getContainer(); XWorkConverter xworkConverter = cont.getInstance(XWorkConverter.class); CompoundRootAccessor accessor = (CompoundRootAccessor) cont.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()); TextProvider prov = cont.getInstance(TextProvider.class, "system"); boolean allow = "true".equals(cont.getInstance(String.class, "allowStaticMethodAccess")); OgnlValueStack aStack = new OgnlValueStack(xworkConverter, accessor, prov, allow); aStack.setOgnlUtil(cont.getInstance(OgnlUtil.class)); aStack.setRoot(xworkConverter, accessor, this.root, allow); return aStack; } public void clearContextValues() { //this is an OGNL ValueStack so the context will be an OgnlContext //it would be better to make context of type OgnlContext ((OgnlContext) context).getValues().clear(); } public void setAcceptProperties(Set<Pattern> acceptedProperties) { securityMemberAccess.setAcceptProperties(acceptedProperties); } public void setPropertiesJudge(PropertiesJudge judge) { securityMemberAccess.setPropertiesJudge(judge); } public void setExcludeProperties(Set<Pattern> excludeProperties) { securityMemberAccess.setExcludeProperties(excludeProperties); } }
OGNLValueStack分为两部分,分别是Map形式的OGNLContext和ArrayList形式的CompoundRoot

其中CompoundRoot为根元素(Struts2中为当前Action),直接访问路径
1 1 public UserAction extends ActionSupport{ 2 2 private String name; 3 3 private int age; 4 4 private Adress adress; 5 5 6 6 public String excute(){ 7 7 //.....其他代码 8 8 return SUCCESS; 9 9 } 10 10 public void setName(String name){ 11 11 this.name=name; 12 12 } 13 13 public void setAge(int age){ 14 14 this.age=age; 15 15 } 16 16 public void setAdress(Adress adress){ 17 17 this.adress=adress; 18 18 } 19 19 public String getName(){ 20 20 return name; 21 21 } 22 22 public String getAge(){ 23 23 return age; 24 24 }public String geAdress(){ 25 25 return adress; 26 26 } 27 class Adress{ 28 private String phone; 29 private String adressName; 30 public void setPhone(String phone){ 31 this.phone=phone; 32 } 33 public void setAdressName(String adressName){ 34 this.adressName=adressName; 35 } 36 public String getPhone(){ 37 38 return phone; 39 } 40 41 public String getAdressName(){ 42 43 return AdressName; 44 } 45 } 46 27 }
ValueStack valueStack=ActionContext.getContext().getValueStack();
存入值
valueStack.setValue("name","amy");
valueStack.setValue("age",24);
Adress adress=new Adress();
valueStack.setValue("adress","adress");
valueStack.setValue("adress.phone","123645789");
valueStack.setValue("adress.adressName,"**********");取值
valueStack.findValue("name");
valueStack.findValue("age");
valueStack.findValue("adress");
valueStack.findValue("adress.phone");
valueStack.findValue("adress.adressName");
OGNLContext部分,访问路径前加#
(Map)valueStack.findValue("#request");
(Map)valueStack.findValue("#session");
(Map)valueStack.findValue("#application");
(Map)valueStack.findValue("#parameters");
四 , ActionContext和OGNLValueStack的关系
浙公网安备 33010602011771号