想要知道struts2取值原理 就从源码中看struts2的拦截器顺序知道原理
从struts2-core\2.3.24\struts2-core-2.3.24.jar核心包里面找到的核心配置文件 struts-default.xml
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="datetime"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<!--这个是参数拦截器params -->
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
找到params实现类
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
这是实现类
public class ParametersInterceptor extends MethodFilterInterceptor
从实现类里面找到doIntercept(拦截器核心方法)
public String doIntercept(ActionInvocation invocation) throws Exception {
//获取当前action
Object action = invocation.getAction();
//如果action没有实现NoParameters就不会进去,
/*
假设我if条件为true进去了
*/
if (!(action instanceof NoParameters)) {
//获取action上下文
ActionContext ac = invocation.getInvocationContext();
final Map<String, Object> parameters = retrieveParameters(ac);
if (LOG.isDebugEnabled()) {
LOG.debug("Setting params " + getParameterLogMap(parameters));
}
if (parameters != null) {
Map<String, Object> contextMap = ac.getContextMap();
try {
ReflectionContextState.setCreatingNullObjects(contextMap, true);
ReflectionContextState.setDenyMethodExecution(contextMap, true);
ReflectionContextState.setReportingConversionErrors(contextMap, true);
//通过action上下问去值,下面看getValueStack()
//是怎么实现的
ValueStack stack = ac.getValueStack();
setParameters(action, stack, parameters);
} finally {
ReflectionContextState.setCreatingNullObjects(contextMap, false);
ReflectionContextState.setDenyMethodExecution(contextMap, false);
ReflectionContextState.setReportingConversionErrors(contextMap, false);
}
}
}
return invocation.invoke();
}
//这是ActionContext类下的方法
public ValueStack getValueStack() {
return (ValueStack) get(VALUE_STACK);
}
//找到这个常亮在跟这找
public static final String VALUE_STACK = ValueStack.VALUE_STACK;
public interface ValueStack {
//就找到这里了ValueStack 是个接口看实现类
public static final String VALUE_STACK = "com.opensymphony.xwork2.util.ValueStack.ValueStack";
//看类名知道了取值是用的OGNL表达式取的值
public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessValueStack {
//...这里不是关键代码就删掉了
//这是struts2的值栈 现在看struts2是怎么实现栈结构的
//栈结构肯定有压栈,和弹栈两个方法
CompoundRoot root;
//这是struts2 context
transient Map<String, Object> context;
//值栈用的是ArrayList 集合,在看看压栈和弹栈两个方法
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);
}
//弹栈
/**
每次都是从第0号元素删除,遵守了栈规则
*/
public Object pop() {
return remove(0);
}
//压栈
/**
栈规则是:前进后出
每一次添加都要ArrayList集合中的第0个元素开始,
是栈结构
*/
public void push(Object o) {
add(0, o);
}
}
- 上面写了,知道了struts2的赋值的原理所以我们想让struts自动赋值一定要在 params 拦截器之前赋值。下面我们在回到struts2拦截器上
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<!--是在params拦截器之上可用这个拦截器
进行赋值
<interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
-->
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="scopedModelDriven"/>
<!--这个是模型驱动 这就是模型驱动可以赋值的原因modelDriven拦截器是在params拦截器上面-->
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="datetime"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="debugging"/>
<interceptor-ref name="deprecation"/>
</interceptor-stack>
- prepare拦截器赋值使用
(模板驱动就不写了,我相信大家都会写)
//实现Preparable接口添加未实现方法prepare()
public class Dome1 extends ActionSupport implements Preparable {
private User user = new User();
//实现原理把要赋值的对象压入栈顶
@Override
public void prepare() throws Exception {
//1获得值栈
ValueStack vs = ActionContext.getContext().getValueStack();
//2将u压入栈顶
vs.push(user);
}
}