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();调用下一个拦截器......

原文地址:https://www.cnblogs.com/java-chen-hao/p/10870444.html

时间: 2024-08-01 22:42:57

Struts2 源码分析-----拦截器源码解析 --- ParametersInterceptor的相关文章

Struts2 源码分析——拦截器的机制

本章简言 上一章讲到关于action代理类的工作.即是如何去找对应的action配置信息,并执行action类的实例.而这一章笔者将讲到在执行action需要用到的拦截器.为什么要讲拦截器呢?可以这样子讲吧.拦截器的应用是sturts2核心的亮点之一.如果不明白拦截器是什么的话,那么你相当于没有学习过struts2.笔者本来想直接讲这一章的知识点.可是又怕读者可能对拦截器没有一个概念化的理解.为什么这么讲呢?struts2在设计拦截器这一个部分的内容.在笔者看来事实是以AOP为核心思想来设计的.

0002 - Spring MVC 拦截器源码简析:拦截器加载与执行

1.概述 Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理.例如通过拦截器可以进行权限验证.记录请求信息的日志.判断用户是否登录等. 2.简单示例 2.1.继承 HandlerInterceptorAdapter 抽象类实现一个拦截器.代码如下: public class DemoInterceptor extends HandlerInterceptorAdapter { @Override    pu

【E2LSH源码分析】E2LSH源码综述及主要数据结构

上一小节,我们对p稳定分布LSH的基本原理进行了介绍(http://blog.csdn.net/jasonding1354/article/details/38237353),在接下来的博文中,我将以E2LSH开源代码为基础,对E2LSH的源码进行注解学习,从而为掌握LSH的基本原理以及未来对相似性搜索的扩展学习打下基础. 1.代码概况 E2LSH的核心代码可以分为3部分: LocalitySensitiveHashing.cpp--主要包含基于LSH的RNN(R-near neighbor)数

cocos2d-x 源码分析 : control 源码分析 ( 控制类组件 controlButton)

源码版本来自3.1rc 转载请注明 cocos2d-x源码分析总目录 http://blog.csdn.net/u011225840/article/details/31743129 1.继承结构 control的设计整体感觉挺美的,在父类control定义了整个控制事件的基础以及管理,虽然其继承了Layer,但其本身和UI组件的实现并没有关联.在子类(controlButton,controlSwitch,controlStepper等中实现不同的UI组件).下面通过源码来分析control与

cocos2d-x 源码分析 之 CCTableView源码分析(附使用方法讨论)

cocos2d-x源码总目录 http://blog.csdn.net/u011225840/article/details/31743129 源码来自2.x,转载请注明 1.继承结构 首先来看下CCTableView的继承结构 从继承结构上看,CCTableView是一种CCScrollView,所以为了研究CCTableView的源码,清先去了解CCScrollView的源码http://blog.csdn.net/u011225840/article/details/30033501. 其

【JDK源码分析】通过源码分析CyclicBarrier

前言 CyclicBarrier它是什么?一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点.类似于朋友之间联系要在中午聚个会,几个朋友全部到齐后才开始喝酒吃菜. 源码 CyclicBarrier属性和构造器 public class CyclicBarrier { // 互斥锁 private final ReentrantLock lock = new ReentrantLock(); // 条件等待 private final Condition trip = lock.new

struts2学习笔记---自定义拦截器

什么是拦截器? struts2中拦截器分为Struts2定义好的拦截器和自定义的拦截器.其作用是在一个Action执行之前进行拦截,在Action执行之后又加入某些操作. 实现原理 当请求一个Action时,struts2会查找配置文件,并根据这个Action的配置实例化对应的拦截器对象,然后串成一个列表(list),最后一个一个地调用列表中的拦截器. 拦截器的执行流程 1.对Action进行预处理.(正序执行) 2.拦截器自身决定该不该执行后续的拦截器(由invoke()方法的返回值决定).

【struts2】预定义拦截器

1)预定义拦截器 Struts2有默认的拦截器配置,也就是说,虽然我们没有主动去配置任何关于拦截器的东西,但是Struts2会使用默认引用的拦截器.由于Struts2的默认拦截器声明和引用都在这个Struts-default.xml里面,因此我们需要到这个文件的struts-default包里去看一下.定义如下: 1 <interceptors> 2 <interceptor name="alias" class="com.opensymphony.xwor

走进Struts2(二) — Struts2的基石(拦截器)

拦截器(Interceptor)是Struts2的基石,拦截器的主要作用是在Action执行之前和Result执行之后进行一些特定功能的处理机制. 如图,拦截器是用来负责在Action执行之前和Result执行之后处理一些功能的类.每个不同的拦截器,它们分别执行不同的功能处理,而运行的时机就是在Action执行之前和Result执行之后,需要注意的是在执行Action之前和Result之后,拦截器的执行顺序是正好相反的. 一.拦截器的好处 1.简化Action的实现,可以把很多功能从Action