ParametersInterceptor拦截器其主要功能是把ActionContext中的请求参数设置到ValueStack中,如果栈顶是当前Action则把请求参数设置到了Action中,如果栈顶是一个model(Action实现了ModelDriven接口)则把参数设置到了model中。

下面是该拦截器的doIntercept方法源码:

  1. @Override
  2. public String doIntercept(ActionInvocation invocation) throws Exception {
  3. Object action = invocation.getAction();//获取当前执行的Action对象
  4. if (!(action instanceof NoParameters)) {//判断Action是否实现了NoParameters接口,实现该接口表示该Action没有任何请求参数
  5. ActionContext ac = invocation.getInvocationContext();//获取ActionContext对象
  6. final Map<String, Object> parameters = retrieveParameters(ac);//获取请求参数Map
  7. //省略...
  8. if (parameters != null) {//如果请求参数不为null
  9. Map<String, Object> contextMap = ac.getContextMap();//获取ActionContext内部的context Map,即OgnlContext对象
  10. try {
  11. //省略...
  12. ValueStack stack = ac.getValueStack();//获取值栈
  13. setParameters(action, stack, parameters);//为值栈设置参数
  14. } finally {
  15. //省略...
  16. }
  17. }
  18. }
  19. return invocation.invoke();//调用下一个拦截器
  20. }

setParameters方法才是该拦截器的主要逻辑,现在进入该方法:

  1. protected void setParameters(Object action, ValueStack stack, final Map<String, Object> parameters) {
  2. ParameterNameAware parameterNameAware = (action instanceof ParameterNameAware)
  3. ? (ParameterNameAware) action : null;//判断Action有无实现ParameterNameAware接口
  4.  
  5. Map<String, Object> params;
  6. Map<String, Object> acceptableParameters;//合法参数集合
  7. //判断参数设置是否有序,ordered默认为false,即无序
  8. if (ordered) {
  9. params = new TreeMap<String, Object>(getOrderedComparator());//如果有序则要获取比较器
  10. acceptableParameters = new TreeMap<String, Object>(getOrderedComparator());
  11. params.putAll(parameters);
  12. } else {
  13. params = new TreeMap<String, Object>(parameters);
  14. acceptableParameters = new TreeMap<String, Object>();
  15. }
  16. //迭代请求参数
  17. for (Map.Entry<String, Object> entry : params.entrySet()) {
  18. String name = entry.getKey();
  19. //判断参数是否合法,如果Action实现了ParameterNameAware则acceptableName(name)返回true且parameterNameAware.acceptableParameterName(name)
  20. //也返回true该参数才是合法的;如果Action没有实现ParameterNameAware则参数是否合法由acceptableName(name)方法决定
  21. boolean acceptableName = acceptableName(name) && (parameterNameAware == null || parameterNameAware.acceptableParameterName(name));
  22. //如果参数合法
  23. if (acceptableName) {
  24. acceptableParameters.put(name, entry.getValue());//把合法参数添加到合法参数集合中
  25. }
  26. }
  27.  
  28. ValueStack newStack = valueStackFactory.createValueStack(stack);
  29. //省略...
  30. for (Map.Entry<String, Object> entry : acceptableParameters.entrySet()) {//迭代合法参数
  31. String name = entry.getKey();//参数名
  32. Object value = entry.getValue();//参数值
  33. try {
  34. newStack.setValue(name, value);//将该参数设置到ValueStack中
  35. } catch (RuntimeException e) {
  36. //省略...
  37. }
  38. }
  39. //省略...
  40. //看该方法的名称是将合法参数添加到ActionContext中,但在该拦截器中,该方法为空实现,无任何代码
  41. //该方法被声明为protected,即子类可以覆盖该方法以改变行为
  42. addParametersToContext(ActionContext.getContext(), acceptableParameters);
  43. }

根据上面的注释大家应该可以发现该setParameters方法逻辑还是很明确的,就是先判断提交过来的参数是否合法,因为提交过来的参数会影响到值栈所以struts2要对提交过来的参数进行合法性检查,以防止恶意用户的攻击,凡是请求参数中表达式中含有等号(=),逗号(,),#号(#)的都是非法表达式,现在就去看一下具体是如何判断一个参数是否合法的。上面注释也讲到了,如果Action实现了ParameterNameAware,即要判断ParameterNameAware接口中声明的acceptableParameterName(name)方法(逻辑由自己实现)也要判断该拦截器的acceptableName(name)方法,我们这里假设Action没有实现ParameterNameAware接口,参数是否合法由acceptableName(name)方法决定,下面是该方法源码:

  1. protected boolean acceptableName(String name) {
  2. //调用isAccepted与isExcluded方法判断
  3. if (isAccepted(name) && !isExcluded(name)) {
  4. return true;
  5. }
  6. return false;
  7. }

isAccepted与isExcluded方法源码:

  1. protected boolean isAccepted(String paramName) {
  2. if (!this.acceptParams.isEmpty()) {
  3. for (Pattern pattern : acceptParams) {
  4. Matcher matcher = pattern.matcher(paramName);
  5. if (matcher.matches()) {
  6. return true;
  7. }
  8. }
  9. return false;
  10. } else
  11. return acceptedPattern.matcher(paramName).matches();
  12. }
  13.  
  14. protected boolean isExcluded(String paramName) {
  15. if (!this.excludeParams.isEmpty()) {
  16. for (Pattern pattern : excludeParams) {
  17. Matcher matcher = pattern.matcher(paramName);
  18. if (matcher.matches()) {
  19. return true;
  20. }
  21. }
  22. }
  23. return false;
  24. }

上面说到了该拦截器配置了参数过滤,配置了一个名为excludeParams的参数,用于指定哪些参数要排除,即不合法,我们传递的时候是字符串在设置该字符串的时候该拦截器会对该字符串进行解析转化成相应的Pattern对象以用于正则表达式校验,而isAccepted与isExcluded方法中就是在用这些正则表达式进行检验,逻辑很简单,就说这么多。

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

到此该拦截器就讲解完毕了,最后调用invocation.invoke();调用下一个拦截器......

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

  1. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

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

    本章简言 上一章讲到关于action代理类的工作.即是如何去找对应的action配置信息,并执行action类的实例.而这一章笔者将讲到在执行action需要用到的拦截器.为什么要讲拦截器呢?可以这样 ...

  3. springMVC源码分析--拦截器HandlerExecutionChain(三)

    上一篇博客springMVC源码分析--HandlerInterceptor拦截器调用过程(二)中我们介绍了HandlerInterceptor的执行调用地方,最终HandlerInterceptor ...

  4. Nacos 2.0源码分析-拦截器机制

    温馨提示: 本文内容基于个人学习Nacos 2.0.1版本代码总结而来,因个人理解差异,不保证完全正确.如有理解错误之处欢迎各位拍砖指正,相互学习:转载请注明出处. Nacos服务端在处理健康检查和心 ...

  5. struts2拦截器源码分析

    前面博客我们介绍了开发struts2应用程序的基本流程(开发一个struts2的实例),通过前面我们知道了struts2实现请求转发和配置文件加载都是拦截器进行的操作,这也就是为什么我们要在web.x ...

  6. Jfinal拦截器源码解读

    本文对Jfinal拦截器源码做以下分析说明

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

    1.概述 Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理.例如通过拦截器可以进行权限验证.记录请求信息的日 ...

  8. 5.2 spring5源码--spring AOP源码分析三---切面源码分析

    一. AOP切面源码分析 源码分析分为三部分 1. 解析切面 2. 创建动态代理 3. 调用 源码的入口 源码分析的入口, 从注解开始: 组件的入口是一个注解, 比如启用AOP的注解@EnableAs ...

  9. drf的基本使用、APIView源码分析和CBV源码拓展

    cbv源码拓展 扩展,如果我在Book视图类中重写dispatch方法 -可以实现,在get,post方法执行之前或者之后执行代码,完成类似装饰器的效果 def dispatch(self, requ ...

随机推荐

  1. Qt版权介绍:GPL, LGPL 以及 Commercial 授权

    http://blog.csdn.net/changsheng230/article/details/6167933 Qt版权介绍:GPL, LGPL 以及 Commercial 授权 分类: Qt ...

  2. js混合计算字符串字节长度

    js混合计算字符串字节长度 function getBt(str) { ) { var char = str.match(/[^\x00-\xff]/ig); : char.length); } el ...

  3. Android Studio Mac版快捷键

    mac上按键符号 ⌥ : option / alt ⇧ : shift ⌃ : control ⌘ : command ⎋ : esc (一)查找/查看相关 搜索任意内容 双击 sft 当前文件查找/ ...

  4. 【Selenium】Option加载用户配置,Chrom命令行参数

    about:version - 显示当前版本 about:memory - 显示本机浏览器内存使用状况 about:plugins - 显示已安装插件 about:histograms - 显示历史记 ...

  5. Selenium-使用firepath获取元素的xpath

  6. html中Meta属性

    <!DOCTYPE html> <!-- 使用 HTML5 doctype,不区分大小写 --> <html lang="zh-cmn-Hans"&g ...

  7. 【遍历二叉树】10判断二叉树是否平衡【Balanced Binary Tree】

    平衡的二叉树的定义都是递归的定义,所以,用递归来解决问题,还是挺容易的额. 本质上是递归的遍历二叉树. ++++++++++++++++++++++++++++++++++++++++++++++++ ...

  8. do-while-zero 结构在宏定义中的应用

    do while 语句在使用宏定义时是一个有用的技巧,说明如下: 假设有这样一个宏定义 #define macro(condition) / if(condition) dosomething() 现 ...

  9. Eclipse 反编译插件安装jad【转】

    原文地址:http://tangmingjie2009.iteye.com/blog/1916992 Eclipse的反编译插件一直在用jad,感觉很不错. 刚下了个新版的eclipse,配置jad的 ...

  10. BZOJ2563阿狸和桃子的游戏

    2563: 阿狸和桃子的游戏 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 952  Solved: 682[Submit][Status][Discu ...