Spring MVC中的拦截器Interceptor

谈谈spring中的拦截器

在web开发中,拦截器是经常用到的功能。它可以帮我们验证是否登陆、预先设置数据以及统计方法的执行效率等等。今天就来详细的谈一下spring中的拦截器。spring中拦截器主要分两种,一个是HandlerInterceptor,一个是MethodInterceptor。

一,HandlerInterceptor拦截器

HandlerInterceptor是springMVC项目中的拦截器,它拦截的目标是请求的地址,比MethodInterceptor先执行。实现一个HandlerInterceptor拦截器可以直接实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter类。这两种方法殊途同归,其实HandlerInterceptorAdapter也就是声明了HandlerInterceptor接口中所有方法的默认实现,而我们在继承他之后只需要重写必要的方法。下面就是HandlerInterceptorAdapter的代码,可以看到一个方法只是默认返回true,另外两个是空方法:

 1 public abstract class HandlerInterceptorAdapter implements HandlerInterceptor {
 2
 3     /**
 4      * This implementation always returns <code>true</code>.
 5      */
 6     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
 7         throws Exception {
 8         return true;
 9     }
10
11     /**
12      * This implementation is empty.
13      */
14     public void postHandle(
15             HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
16             throws Exception {
17     }
18
19     /**
20      * This implementation is empty.
21      */
22     public void afterCompletion(
23             HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
24             throws Exception {
25     }
26
27 }  

这三个方法都是干什么的,有什么作用,什么时候调用,不同的拦截器之间是怎样的调用顺序呢?这还得参考一下DispatcherServlet的doDispatch方法:

 1 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
 2         HttpServletRequest processedRequest = request;
 3         HandlerExecutionChain mappedHandler = null;
 4         boolean multipartRequestParsed = false;
 5
 6         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
 7
 8         try {
 9             ModelAndView mv = null;
10             Exception dispatchException = null;
11
12             try {
13                 processedRequest = checkMultipart(request);
14                 multipartRequestParsed = (processedRequest != request);
15
16                 // Determine handler for the current request.
17                 mappedHandler = getHandler(processedRequest);
18                 if (mappedHandler == null || mappedHandler.getHandler() == null) {
19                     noHandlerFound(processedRequest, response);
20                     return;
21                 }
22
23                 // Determine handler adapter for the current request.
24                 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
25
26                 // Process last-modified header, if supported by the handler.
27                 String method = request.getMethod();
28                 boolean isGet = "GET".equals(method);
29                 if (isGet || "HEAD".equals(method)) {
30                     long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
31                     if (logger.isDebugEnabled()) {
32                         logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
33                     }
34                     if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
35                         return;
36                     }
37                 }
38
39                 if (!mappedHandler.applyPreHandle(processedRequest, response)) {
40                     return;
41                 }
42
43                 // Actually invoke the handler.
44                 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
45
46                 if (asyncManager.isConcurrentHandlingStarted()) {
47                     return;
48                 }
49
50                 applyDefaultViewName(processedRequest, mv);
51                 mappedHandler.applyPostHandle(processedRequest, response, mv);
52             }
53             catch (Exception ex) {
54                 dispatchException = ex;
55             }
56             processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
57         }
58         catch (Exception ex) {
59             triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
60         }
61         catch (Error err) {
62             triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
63         }
64         finally {
65             if (asyncManager.isConcurrentHandlingStarted()) {
66                 // Instead of postHandle and afterCompletion
67                 if (mappedHandler != null) {
68                     mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
69                 }
70             }
71             else {
72                 // Clean up any resources used by a multipart request.
73                 if (multipartRequestParsed) {
74                     cleanupMultipart(processedRequest);
75                 }
76             }
77         }
78     }

它封装了springMVC处理请求的整个过程。首先根据请求找到对应的HandlerExecutionChain,它包含了处理请求的handler和所有的HandlerInterceptor拦截器;然后在调用hander之前分别调用每个HandlerInterceptor拦截器的preHandle方法,若有一个拦截器返回false,则会调用triggerAfterCompletion方法,并且立即返回不再往下执行;若所有的拦截器全部返回true并且没有出现异常,则调用handler返回ModelAndView对象;再然后分别调用每个拦截器的postHandle方法;最后,即使是之前的步骤抛出了异常,也会执行triggerAfterCompletion方法。关于拦截器的处理到此为止,接下来看看triggerAfterCompletion做了什么

 1 void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
 2             throws Exception {
 3
 4         HandlerInterceptor[] interceptors = getInterceptors();
 5         if (!ObjectUtils.isEmpty(interceptors)) {
 6             for (int i = this.interceptorIndex; i >= 0; i--) {
 7                 HandlerInterceptor interceptor = interceptors[i];
 8                 try {
 9                     interceptor.afterCompletion(request, response, this.handler, ex);
10                 }
11                 catch (Throwable ex2) {
12                     logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
13                 }
14             }
15         }
16     }

triggerAfterCompletion做的事情就是从当前的拦截器开始逆向调用每个拦截器的afterCompletion方法,并且捕获它的异常,也就是说每个拦截器的afterCompletion方法都会调用。

根据以上的代码,分析一下不同拦截器及其方法的执行顺序。假设有5个拦截器编号分别为12345,若一切正常则方法的执行顺序是12345的preHandle,54321的postHandle,54321的afterCompletion。若编号3的拦截器的preHandle方法返回false或者抛出了异常,接下来会执行的是21的afterCompletion方法。这里要注意的地方是,我们在写一个拦截器的时候要谨慎的处理preHandle中的异常,因为这里一旦有异常抛出就不会再受到这个拦截器的控制。12345的preHandle的方法执行过之后,若handler出现了异常或者某个拦截器的postHandle方法出现了异常,则接下来都会执行54321的afterCompletion方法,因为只要12345的preHandle方法执行完,当前拦截器的拦截器就会记录成编号5的拦截器,而afterCompletion总是从当前的拦截器逆向的向前执行。

另外,实现HandlerInterceptor拦截器还有一个方法,就是实现WebRequestInterceptor接口。其实它和刚才的两种方法也是殊途同归,最终还是被spring适配成HandlerInterceptor。有一点不同,它的preHandle方法最终只会返回true。

拦截器的配置

<mvc:interceptors>
    <!-- 使用 bean 定义一个 Interceptor,直接定义在 mvc:interceptors 下面的 Interceptor 将拦截所有的请求 -->
    <bean class="com.psm.interceptor.WrongCodeInterceptor"/>
    <mvc:interceptor>
        <mvc:mapping path="/login.do"/>
        <!-- 定义在 mvc:interceptor 下面的 Interceptor,表示对特定的请求进行拦截 -->
        <bean class="com.psm.interceptor.LoginInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors> 

在 Spring 的XML 配置文件中,咱们可以通过mvc:interceptors标签声明一系列的拦截器,例如:

1 <mvc:interceptors>
2         <bean class="com.hit.interceptor.ContextInterceptor"/>
3         <bean class="com.hit.interceptor.LoginInterceptor"/>
4         <bean class="com.hit.interceptor.WrongCodeInterceptor"/>
5 </mvc:interceptors>

如上所示,这些拦截器就够成了一个拦截器链,或者称之为拦截器栈。而这些拦截器的执行顺序是按声明的先后顺序执行的,即:先声明的拦截器先执行,后声明的拦截器后执行。在mvc:interceptors标签下声明interceptor标签主要有两种方式:

  • 直接定义一个 Interceptor 实现类的 bean 对象,使用这种方式声明的 Interceptor 拦截器将会对所有的请求进行拦截;
  • 使用mvc:interceptor标签进行声明,使用这种方式进行声明的 Interceptor 可以通过mvc:mapping子标签来定义需要进行拦截的请求路径。

此外,由于拦截器是 AOP 编程思想的典型应用,也就意味着咱们可以“切”到具体的“面”进行某些操作。例如,

<bean id="WrongCodeInterceptor" class="com.hit.interceptor.WrongCodeInterceptor">
        <property name="userName" value="user-module"></property>
</bean>

<bean id="loginInterceptor" class="com.hit.interceptor.LoginInterceptor">
    <property name="excludePackages">
       <list>
          <value>com.hit.user.exception</value>
          <value>com.hit.order.exception</value>
       </list>
    </property>
</bean>

<aop:config>
    <aop:advisor advice-ref="WrongCodeInterceptor" pointcut="execution(* com.hit.*.demo..*.*(..)) || execution(* com.hit.*.demo..*.*(..)) " />
    <aop:advisor advice-ref="loginInterceptor" pointcut="execution(* com.hit.*.demo..*.*(..))" />
</aop:config>

引用博客

http://blog.csdn.net/qq_35246620/article/details/68487904

http://blog.csdn.net/hongxingxiaonan/article/details/48090075

原文地址:https://www.cnblogs.com/oldzhang1222/p/8252805.html

时间: 2024-12-10 02:09:36

Spring MVC中的拦截器Interceptor的相关文章

spring mvc中的拦截器小结 .

在spring mvc中,拦截器其实比较简单了,下面简单小结并demo下. preHandle:预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器(如我们上一章的Controller实现):      返回值:true表示继续流程(如调用下一个拦截器或处理器):              false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应: postHandle:后处理回调方法,实现处理器的后处理(但在渲

Spring MVC中的拦截器/过滤器HandlerInterceptorAdapter的使用

一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的 而在Spring中,基于Filter这种方式可以实现Bean预处理.后处理. 比如注入FilterRegistrationBean,然后在这个Bean上传递自己继承Filter实现的自定义Filter进入即可. 而Spring MVC也有拦截器,不仅可实现Filter的所有功能,还可以更精确的控制拦截精度. Spring MVC提供的org.springframework.web.servlet.handler.HandlerInt

Spring mvc中自定义拦截器

一.要实现的一个功能: 1.打开特定的一些页面时必需强制用户进行登录. 2.登录后再返回到之前的页面. 二.先写一个service,实现从cookie中判断用户是否登录. 1.TT_TOKEN为登录成功时,响应给浏览器的Cookie的键. @Service public class UserServiceImpl implements UserService{ @Value("${SSO_BASE_URL}") private String SSO_BASE_URL; @Value(&

spring mvc 方法注解拦截器

应用场景,在方法级别对本次调用进行鉴权,如api接口中有个用户唯一标示accessToken,对于有accessToken的每次请求可以在方法加一个拦截器,获得本次请求的用户,存放到request或者session域. python中,之前在python flask中可以使用装饰器来对方法进行预处理,进行权限处理 先看一个实例,使用@access_required拦截: @api.route('/post_apply') @access_required def apply():     "&q

spring mvc 能过拦截器记录请求数据和响应数据

spring mvc 能过拦截器记录请求数据记录有很多种方式,主要有以下三种: 1:过滤器 2:HandlerInterceptor拦截器 3:Aspect接口控制器 但是就我个人所知要记录返回的数据,只能通过Aspect处理,以下是实现此需要的代码 package com.qmtt.config; import java.util.Arrays; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annot

spring boot中注册拦截器

拦截器是动态拦截Action调用的对象.它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式.在AOP(Aspect-Oriented Programming)中拦截器用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作. 如何在spring boot中添加拦截器? 1.首先自己实现一个拦截器 import org.springframework.web.ser

mybatis Spring MVC添加分页拦截器

网上有很多封装的mybatis 分页拦截器,但是看起来都比较乱,不能直接套用,在这里贴出项目中的分页源码出来供大家参考. Controller 层: @RequestMapping("/channelList") public String channelList(HttpServletRequest request,AppMarket appMarket,Model model){ String pageNo = request.getParameter("pageNo&q

Spring MVC 学习 之 - 拦截器

public class GlobalInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("GlobalInterceptor 开始调用"); return true; } pub

asp.net mvc中的拦截器

在ASP.NET MVC中,有三种拦截器:Action拦截器.Result拦截器和Exception拦截器,所谓的拦截器也没有什么的,只是写一个类,继承另一个类和一个接口,顺便实现接口里面的方法而以拉!下面我们一一实现! public class ExceptionFillters : FilterAttribute,IExceptionFilter    {        //发生异常时会执行这段代码        public void OnException(ExceptionContex