`
okhaoba
  • 浏览: 5818 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

SpringMVC拦截器详解[附带源码分析]

阅读更多

目录

前言

SpringMVC是目前主流的Web MVC框架之一。 

如果有同学对它不熟悉,那么请参考它的入门blog:http://www.cnblogs.com/fangjian0423/p/springMVC-introduction.html

拦截器是每个Web框架必备的功能,也是个老生常谈的主题了。

本文将分析SpringMVC的拦截器功能是如何设计的,让读者了解该功能设计的原理。

重要接口及类介绍

1. HandlerExecutionChain类

  由HandlerMethod和Interceptor集合组成的类,会被HandlerMapping接口的getHandler方法获取。

2. HandlerInterceptor接口

  

  SpringMVC拦截器基础接口。 

3. AbstractHandlerMapping

  HandlerMapping的基础抽象类。

4. AsyncHandlerInterceptor

  继承HandlerInterceptor的接口,额外提供了afterConcurrentHandlingStarted方法,该方法是用来处理异步请求。当Controller中有异步请求方法的时候会触发该方法。 楼主做过测试,异步请求先支持preHandle、然后执行afterConcurrentHandlingStarted。异步线程完成之后执行preHandle、postHandle、afterCompletion。 有兴趣的读者可自行研究。

5. HandlerInterceptorAdapter

   实现AsyncHandlerInterceptor接口的抽象类,一般我们使用拦截器的话都会继承这个类。然后复写相应的方法。

6. WebRequestInterceptor

  与HandlerInterceptor接口类似,区别是WebRequestInterceptor的preHandle没有返回值。还有WebRequestInterceptor是针对请求的,接口方法参数中没有response。

  

  AbstractHandlerMapping内部的interceptors是个Object类型集合。处理的时候判断为MappedInterceptor[加入到mappedInterceptors集合中];HandlerInterceptor、WebRequestInterceptor(适配成WebRequestHandlerInterceptorAdapter)[加入到adaptedInterceptors中]

7. MappedInterceptor

  一个包括includePatterns和excludePatterns字符串集合并带有HandlerInterceptor的类。 很明显,就是对于某些地址做特殊包括和排除的拦截器。

   

8. ConversionServiceExposingInterceptor

  默认的<annotation-driven/>标签初始化的时候会初始化ConversionServiceExposingInterceptor这个拦截器,并被当做构造方法的参数来构造MappedInterceptor。之后会被加入到AbstractHandlerMapping的mappedInterceptors集合中。该拦截器会在每个请求之前往request中丢入ConversionService。主要用于spring:eval标签的使用。

源码分析

首先我们看下拦截器的如何被调用的。

Web请求被DispatcherServlet截获后,会调用DispatcherServlet的doDispatcher方法。

很明显地看到,在HandlerAdapter处理之后,以及处理完成之后会调用HandlerExecutionChain的方法。

HandlerExecutionChain的applyPreHandle、applyPostHandle、triggerAfterCompletion方法如下:

很明显,就是调用内部实现HandlerInterceptor该接口集合的各个对应方法。

 

下面我们看下HandlerExecutionChain的构造过程。

 HandlerExecutionChain是从HandlerMapping接口的getHandler方法获取的。

 HandlerMapping的基础抽象类AbstractHandlerMapping中:

我们看到,HandlerExecutionChain的拦截器是从AbstractHandlerMapping中的adaptedInterceptors和mappedInterceptors属性中获取的。

拦截器的配置

清楚了HandlerExecutionChain的拦截器属性如何构造之后,下面来看下SpringMVC是如何配置拦截器的。

1. *-dispatcher.xml配置文件中添加 <mvc:interceptors>配置

<mvc:interceptors>
  <mvc:interceptor>
    <mvc:mapping path="/**"/>
    <mvc:exclude-mapping path="/login"/>   
    <mvc:exclude-mapping path="/index"/>
    <bean class="package.interceptor.XXInterceptor"/>
  </mvc:interceptor>
</mvc:interceptors>

这里配置的每个<mvc:interceptor>都会被解析成MappedInterceptor。

其中子标签<mvc:mapping path="/**"/>会被解析成MappedInterceptor的includePatterns属性;<mvc:exclude-mapping path="/**"/>会被解析成MappedInterceptor的excludePatterns属性;<bean/>会被解析成MappedInterceptor的interceptor属性。

<mvc:interceptors>这个标签是被InterceptorsBeanDefinitionParser类解析。

2. 配置RequestMappingHandlerMapping,并配置该bean对应的interceptors集合属性。 这里的interceptors集合是个Object类型的泛型集合。

  AbstractHandlerMapping抽象类只暴露了1个拦截器的set方法 -> interceptors。

  adaptedInterceptors和mappedInterceptors均没有暴露set方法,因此我们只能为RequestMappingHandlerMapping配置interceptors属性。

  其实AbstractHandlerMapping内部的initInterceptors方法中,会遍历interceptors集合,然后判断各个项是否是MappedInterceptor、HandlerInterceptor、WebRequestInterceptor。

  其中MappedInterceptor类型的拦截器会被加到mappedInterceptors集合中,HandlerInterceptor类型的会被加到adaptedInterceptors集合中,WebRequestInterceptor类型的会被适配成WebRequestHandlerInterceptorAdapter加到adaptedInterceptors集合中。

  

  

  如果读者配置了:

<mvc:annotation-driven/>

  那么配置如下:

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
  <property name="interceptors">
    <bean class="package.interceptor.XXInterceptor"/>
  </property>  
  <property name="order" value="-1"/>
</bean>

  否则,可以去掉order这个属性的设置。

  为什么呢? 请参考楼主的另外一篇博客:http://www.cnblogs.com/fangjian0423/p/spring-Ordered-interface.html

  一般建议使用第一种方法。 

编写自定义的拦截器

public class LoginInterceptor extends HandlerInterceptorAdapter {
  
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception { 
        // 获得请求路径的uri
        String uri = request.getRequestURI();

        // 判断路径是登出还是登录验证,是这两者之一的话执行Controller中定义的方法
        if(uri.endsWith("/login/auth") || uri.endsWith("/login/out")) {
            return true;
        }

        // 进入登录页面,判断session中是否有key,有的话重定向到首页,否则进入登录界面
        if(uri.endsWith("/login/") || uri.endsWith("/login")) {
            if(request.getSession() != null && request.getSession().getAttribute("loginUser") != null) {
                response.sendRedirect(request.getContextPath() + "/index");
            } else {
                return true;
            }
        }

        // 其他情况判断session中是否有key,有的话继续用户的操作
        if(request.getSession() != null && request.getSession().getAttribute("loginUser") != null) {
            return true;
        }

        // 最后的情况就是进入登录页面
        response.sendRedirect(request.getContextPath() + "/login");
        return false;
  }
  
}

登录Controller:

@Controller
@RequestMapping(value = "/login")
public class LoginController {
  
    @RequestMapping(value = {"/", ""})
    public String index() {
        return "login";
    }

    @RequestMapping("/auth")
    public String auth(@RequestParam String username, HttpServletRequest req) {
        req.getSession().setAttribute("loginUser", username);
        return "redirect:/index";
    }

    @RequestMapping("/out")
    public String out(HttpServletRequest req) {
        req.getSession().removeAttribute("loginUser");
        return "redirect:/login";
    }
  
}

 *-diapatcher.xml配置:

<mvc:interceptors>
  <mvc:interceptor>
    <mvc:mapping path="/**"/>
    <bean class="org.format.demo.interceptor.LoginInterceptor"/>
  </mvc:interceptor>
</mvc:interceptors>

 

PS:我们看到LoginInterceptor里的preHandle方法对于地址“/login/auth”和"/login/out"不处理。

因此,可以写点配置,少写带java代码。在拦截器配置中添加2个exclude-mapping,并且去掉LoginInterceptor里的

if(uri.endsWith("/login/auth") || uri.endsWith("/login/out")) {
  return true;
}

配置新增:

<mvc:exclude-mapping path="/login/out"/>
<mvc:exclude-mapping path="/login/auth"/>

总结

总结了SpringMVC拦截器的原理以及各种配置,像网上很多人会问为什么拦截器执行preHandle方法返回false之后还是会执行afterCompletion方法,其实我们看下源码就知道了。

关于异步请求方面的拦截器以及第二种配置方法(interceptors集合属性可加入继承自HandlerInterceptorAdapter抽象类的类以及实现WebRequestInterceptor接口的类),读者可自行研究。

 

文中难免有错误,希望读者能够指出来。

参考资料

http://jinnianshilongnian.iteye.com/blog/1670856

 
分类: javaSpringMVC
 
 
原文出处:http://www.cnblogs.com/fangjian0423/p/springmvc-interceptor.html
 
分享到:
评论

相关推荐

    防止SpringMVC拦截器拦截js等静态资源文件的解决方法

    在本文中,我们讨论了三种解决SpringMVC拦截器拦截静态资源文件的方法,并对这些方法的优劣进行了分析。 方案一是在拦截器中排除静态资源路径。在SpringMVC的配置文件中(通常是spring-mvc.xml),可以通过配置元素...

    springMVC拦截器项目

    SpringMVC 拦截器项目是一个典型的 Web 应用开发示例,它利用 SpringMVC 框架中的拦截器(Interceptor)机制来实现特定的功能,如权限控制、日志记录、性能统计等。SpringMVC 是 Spring 框架的一部分,专为构建基于 ...

    SpringMVC拦截器例子详解

    在Spring MVC框架中,拦截器(Interceptor)是一个强大的工具,用于在请求被控制器处理之前或之后执行特定的逻辑。它们可以用来实现通用的功能,如权限验证、日志记录、性能统计等,避免在每个控制器方法中重复代码...

    SpringMVC拦截器源代码.zip

    这个名为“SpringMVC拦截器源代码.zip”的压缩包可能包含了Spring MVC拦截器的实现源码,这对于理解和学习如何自定义拦截器以增强应用功能非常有帮助。 1. **拦截器的基本概念** - 拦截器是AOP(面向切面编程)的...

    springMvc源码分析

    springMvc源码分析springMvc源码分析springMvc源码分析springMvc源码分析springMvc源码分析springMvc源码分析

    SpringMVC拦截器源码.rar

    在SpringMVC中,拦截器(Interceptor)是一个重要的概念,用于在实际处理请求之前和之后执行一些预处理或后处理逻辑。这些逻辑可以包括权限检查、日志记录、性能统计等。 ### 一、SpringMVC 拦截器的定义 ...

    SpringMVC拦截器

    ### SpringMVC拦截器 #### 一、拦截器概述 拦截器(Interceptor)是一种轻量级、低侵入式的AOP实现方式,在SpringMVC框架中有着广泛的应用。它主要用于处理那些与业务逻辑无关但又频繁出现的功能需求,如日志记录...

    企业级开发-SpringMVC使用拦截器实现用户登录权限验证实验报告.docx

    本实验报告将探讨如何利用 SpringMVC 的拦截器(Interceptor)来实现用户登录权限验证,确保只有已登录的用户才能访问特定的受保护资源。 首先,我们来看一下实验的基本步骤: 1. 创建 `User` 类:这是表示用户...

    springMVC 详细版本 拦截器源码

    springMVC 拦截器源代码 内有详细文档介绍操作 @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { //可以通过...

    SpringMVC 拦截器 实现 登录退出功能

    **SpringMVC 拦截器实现登录退出功能** 在SpringMVC框架中,拦截器(Interceptor)是一种非常重要的机制,它允许我们在请求被控制器处理之前或之后执行自定义逻辑。在本例中,我们将讨论如何使用拦截器来实现用户...

    SpringMVC中的拦截器-拦截器方法的作用和执行顺序.avi

    SpringMVC中的拦截器-拦截器方法的作用和执行顺序.avi

    1、手写springmvc框架及分析springmvc源码.zip

    1、手写springmvc框架及分析springmvc源码.zip1、手写springmvc框架及分析springmvc源码.zip1、手写springmvc框架及分析springmvc源码.zip1、手写springmvc框架及分析springmvc源码.zip1、手写springmvc框架及分析...

    SpringMVC-12 拦截器

    在本教程“SpringMVC-12 拦截器”中,我们将深入探讨如何实现和配置自定义拦截器,以及多个拦截器的执行顺序。 首先,我们来了解如何创建一个自定义的拦截器。在Spring MVC中,我们需要创建一个实现了`...

    11SpringMVC拦截器.md

    11SpringMVC拦截器.md

    SpringMVC拦截器实现登录认证

    SpringMVC拦截器是实现登录认证的一种常见方法,它允许开发者在请求被实际处理之前或之后执行特定的逻辑。本文将深入探讨如何利用SpringMVC拦截器来实现这一功能。 首先,了解SpringMVC的核心组件是必要的。...

    SpringMVC拦截器实现单点登录

    SpringMVC 拦截器实现单点登录是一种常见的安全控制机制,主要用于确保在同一时间只有一个用户能够使用同一账号进行操作。这种功能在多用户、多设备登录的环境中尤为重要,可以防止用户账号被盗用或者误操作。 单点...

    SpringMVC拦截器运行原理及配置详解

    SpringMVC拦截器运行原理及配置详解 SpringMVC拦截器是SpringMVC框架中的一种机制,用于在 Controller 方法执行前、后或抛出异常时执行某些操作的拦截器,拦截器可以对Controller中的方法进行拦截和过滤,从而实现...

    Spring Cloud OpenFeign - - - >拦截器

    初学者很容易将 Spring MVC 拦截器 和 Spring Cloud OpenFeign 拦截器搞混,误以为OpenFeign拦截器就是SpringMVC拦截器:Spring MVC拦截器发生在客户端 和 服务端之间,在客户端向服务端发送请求时进行拦截处理。...

    使用SessionListener+持久化Session+Springmvc拦截器实现单点登录

    在这个过程中,`SessionListener`、持久化`Session`和`Springmvc拦截器`是关键组件,让我们逐一深入探讨。 ### SessionListener `SessionListener`是Java Servlet API中的一个接口,用于监听`HttpSession`事件。...

    jetbrick-springmvc jar包(包含源码)

    8. **拦截器**:扩展了SpringMVC的拦截器机制,允许开发者自定义拦截逻辑,用于权限控制、日志记录等功能。 9. **工具类**:提供了一系列实用的工具类,如字符串操作、日期时间处理、JSON转换等,方便开发者进行...

Global site tag (gtag.js) - Google Analytics