码迷,mamicode.com
首页 > 编程语言 > 详细

Spring MVC中的拦截器Interceptor

时间:2018-01-09 20:26:03      阅读:222      评论:0      收藏:0      [点我收藏+]

标签:它的   try   null   text   gen   servlet   false   value   finally   

谈谈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

 

Spring MVC中的拦截器Interceptor

标签:它的   try   null   text   gen   servlet   false   value   finally   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!