Struts2源码分析之ParametersInterceptor拦截器

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Struts2源码分析之ParametersInterceptor拦截器
前⾔
ParametersInterceptor拦截器其主要功能是把ActionContext中的请求参数设置到ValueStack中,如果栈顶是当前Action则把请求参数设置到了Action中,如果栈顶是⼀个model(Action实现了ModelDriven接⼝)则把参数设置到了model中。

下⾯是该拦截器的doIntercept⽅法源码:
@Override
public String doIntercept(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();//获取当前执⾏的Action对象
if (!(action instanceof NoParameters)) {//判断Action是否实现了NoParameters接⼝,实现该接⼝表⽰该Action没有任何请求参数
ActionContext ac = invocation.getInvocationContext();//获取ActionContext对象
final Map<String, Object> parameters = retrieveParameters(ac);//获取请求参数Map
//省略...
if (parameters != null) {//如果请求参数不为null
Map<String, Object> contextMap = ac.getContextMap();//获取ActionContext内部的context Map,即OgnlContext对象
try {
//省略...
ValueStack stack = ac.getValueStack();//获取值栈
setParameters(action, stack, parameters);//为值栈设置参数
} finally {
//省略...
}
}
}
return invocation.invoke();//调⽤下⼀个拦截器
}
setParameters⽅法才是该拦截器的主要逻辑,现在进⼊该⽅法:
protected void setParameters(Object action, ValueStack stack, final Map<String, Object> parameters) {
ParameterNameAware parameterNameAware = (action instanceof ParameterNameAware)
(ParameterNameAware) action : null;//判断Action有⽆实现ParameterNameAware接⼝
Map<String, Object> params;
Map<String, Object> acceptableParameters;//合法参数集合
//判断参数设置是否有序,ordered默认为false,即⽆序
if (ordered) {
params = new TreeMap<String, Object>(getOrderedComparator());//如果有序则要获取⽐较器
acceptableParameters = new TreeMap<String, Object>(getOrderedComparator());
params.putAll(parameters);
} else {
params = new TreeMap<String, Object>(parameters);
acceptableParameters = new TreeMap<String, Object>();
}
//迭代请求参数
for (Map.Entry<String, Object> entry : params.entrySet()) {
String name = entry.getKey();
//判断参数是否合法,如果Action实现了ParameterNameAware则acceptableName(name)返回true且parameterNameAware.acceptableParameterName(name) //也返回true该参数才是合法的;如果Action没有实现ParameterNameAware则参数是否合法由acceptableName(name)⽅法决定
boolean acceptableName = acceptableName(name) && (parameterNameAware == null || parameterNameAware.acceptableParameterName(name));
//如果参数合法
if (acceptableName) {
acceptableParameters.put(name, entry.getValue());//把合法参数添加到合法参数集合中
}
}
ValueStack newStack = valueStackFactory.createValueStack(stack);
//省略...
for (Map.Entry<String, Object> entry : acceptableParameters.entrySet()) {//迭代合法参数
String name = entry.getKey();//参数名
Object value = entry.getValue();//参数值
try {
newStack.setValue(name, value);//将该参数设置到ValueStack中
} catch (RuntimeException e) {
//省略...
}
}
//省略...
//看该⽅法的名称是将合法参数添加到ActionContext中,但在该拦截器中,该⽅法为空实现,⽆任何代码
//该⽅法被声明为protected,即⼦类可以覆盖该⽅法以改变⾏为
addParametersToContext(ActionContext.getContext(), acceptableParameters);
}
根据上⾯的注释⼤家应该可以发现该setParameters⽅法逻辑还是很明确的,就是先判断提交过来的参数是否合法,因为提交过来的参数会影响到值栈所以struts2要对提交过来的参数进⾏合法性检查,以防⽌恶意⽤户的攻击,凡是请求参数中表达式中含有等号(=),逗号(,),#号(#)的都是⾮法表达式,现在就去看⼀下具体是如何判断⼀个参数是否合法的。

上⾯注释也讲到了,如果Action实现了ParameterNameAware,即要判断ParameterNameAware接⼝中声明的acceptableParameterName(name)⽅法(逻辑由⾃⼰实现)也要判断该拦截器的acceptableName(name)⽅法,我们这⾥假设Action没有实现ParameterNameAware接⼝,参数是否合法由acceptableName(name)⽅法决定,下⾯是该⽅法源码:protected boolean acceptableName(String name) {
//调⽤isAccepted与isExcluded⽅法判断
if (isAccepted(name) && !isExcluded(name)) {
return true;
}
return false;
}
isAccepted与isExcluded⽅法源码:
protected boolean isAccepted(String paramName) {
if (!this.acceptParams.isEmpty()) {
for (Pattern pattern : acceptParams) {
Matcher matcher = pattern.matcher(paramName);
if (matcher.matches()) {
return true;
}
}
return false;
} else
return acceptedPattern.matcher(paramName).matches();
}
protected boolean isExcluded(String paramName) {
if (!this.excludeParams.isEmpty()) {
for (Pattern pattern : excludeParams) {
Matcher matcher = pattern.matcher(paramName);
if (matcher.matches()) {
return true;
}
}
}
return false;
}
上⾯说到了该拦截器配置了参数过滤,配置了⼀个名为excludeParams的参数,⽤于指定哪些参数要排除,即不合法,我们传递的时候是字符串在设置该字符串的时候该拦截器会对该字符串进⾏解析转化成相应的Pattern对象以⽤于正则表达式校验,⽽isAccepted与isExcluded⽅法中就是在⽤这些正则表达式进⾏检验,逻辑很简单,就说这么多。

最终进⾏参数赋值是调⽤的ValueStack的setValue⽅法,该⽅法内部使⽤是OGNL表达式引擎进⾏赋值的,虽然内部⾮常复杂,但我们只需要知道OGNL表达式引擎在把请求参数设置到ValueStack中时,是从栈顶往栈底寻找有相应setter⽅法的对象,如果正在赋值的参数在ValueStack找到了⼀个对象有setter⽅法则把该参数的值赋给该对象,如果没有找到则继承往栈底寻找,直到找到为⽌,如果找到栈底还是没有找到也就没有赋值成功。

到此该拦截器就讲解完毕了,最后调⽤invocation.invoke();调⽤下⼀个拦截器......
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

相关文档
最新文档