在SpringBoot项目中添加SpringMVC拦截器

1、认识拦截器

  SpringMVC的拦截器(Interceptor)不是Filer,同样可以实现请求的预处理、后处理。使用拦截器仅需要两个步骤

  实现拦截器

  注册拦截器

1.1实现拦截器

  实现拦截器可以自定义实现HandleInterceptor接口,也可以继承HandleInterceptorAdatper类,后者是前者的实现类。

  下面是拦截器实现的一个例子,目的是判断用户是否登录。如果preHandle方法return true ,则后续方法继续执行。

  

 1 package Interceptor;
 2 
 3 import javax.servlet.http.HttpServletRequest;
 4 import javax.servlet.http.HttpServletResponse;
 5 
 6 import org.springframework.web.servlet.ModelAndView;
 7 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 8 
 9 /**
10  * 实现拦截器 
11  *
12  */
13 public class LoginInterceptor extends HandlerInterceptorAdapter{
14 
15     /**
16      * 预处理回调方法,实现处理器的预处理(如登录检查)
17      * 第三个参数为相应的处理器,即controller
18      * 返回true表示流程继续调用下一个拦截器或处理器
19      * 返回false表示流程中断,通过response产生响应
20      */
21     @Override
22     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
23             throws Exception {
24         System.out.println("------------------------------------preHandle");
25          // 验证用户是否登陆
26         Object obj = request.getSession().getAttribute("username");
27         if (obj == null || !(obj instanceof String)) {
28             response.sendRedirect(request.getContextPath() + "/index.html");
29             return false;
30         }
31         return true;
32     }
33     
34      /**
35      *当前请求进行处理之后,也就是Controller 方法调用之后执行,
36      *但是它会在DispatcherServlet 进行视图返回渲染之前被调用。
37      *此时我们可以通过modelAndView对模型数据进行处理或对视图进行处理。
38      */
39     @Override
40     public void postHandle(HttpServletRequest request, HttpServletResponse response, 
41             Object handler, ModelAndView modelAndView) throws Exception {
42         System.out.println("-------------------postHandle");
43     }
44 
45     /**
46      *方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。
47      *这个方法的主要作用是用于进行资源清理工作的。
48      */
49     @Override
50     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, 
51             Object handler, Exception ex) throws Exception {
52         System.out.println("-------------------afterCompletion");
53     }
54 
55 }

1.2注册拦截器

扫描二维码关注公众号,回复: 8449516 查看本文章

  为了使自定义的拦截器生效,需要把拦截器注册到spring容器中。具体做法是继承WebMvcConfigurerAdapter类,重写其addInterceptors(InterceptorRegistry registry)方法,然后使用@Component 或者 @Configuration将Bean注册到Spring容器中。

  可以单独建一个类继承WebMvcConfigurerAdaoter类

 1 package Interceptor;
 2 
 3 import org.springframework.context.annotation.Configuration;
 4 import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
 5 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 6 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
 7 
 8 /**
 9  * 注册拦截器
10  *
11  */
12 @Configuration
13 public class InterceptorConfiguration extends WebMvcConfigurerAdapter{
14 
15     @Override
16     public void addInterceptors(InterceptorRegistry registry) {
17         //注册拦截器
18         InterceptorRegistration addInterceptor = registry.addInterceptor(new LoginInterceptor());
19         // 配置拦截的路径
20         addInterceptor.addPathPatterns("/**");
21         // 配置不拦截的路径
22         addInterceptor.excludePathPatterns("/**.html");
23 
24         // 还可以在这里注册其它的拦截器
25         //registry.addInterceptor(new OtherInterceptor()).addPathPatterns("/**");
26     }
27 }

  也可以直接在SpringBoot的启动类中继承WebMvcConfigurerAdaoter类

  1 package cn.wowkai.mall;
  2 
  3 import java.nio.charset.Charset;
  4 import java.util.Arrays;
  5 
  6 import javax.annotation.PostConstruct;
  7 import javax.annotation.Resource;
  8 import javax.sql.DataSource;
  9 
 10 import org.springframework.boot.SpringApplication;
 11 import org.springframework.boot.autoconfigure.SpringBootApplication;
 12 import org.springframework.context.annotation.Bean;
 13 import org.springframework.data.redis.core.RedisTemplate;
 14 import org.springframework.data.redis.serializer.StringRedisSerializer;
 15 import org.springframework.http.HttpHeaders;
 16 import org.springframework.scheduling.annotation.EnableScheduling;
 17 import org.springframework.web.cors.CorsConfiguration;
 18 import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
 19 import org.springframework.web.filter.CorsFilter;
 20 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 21 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 22 
 23 import com.fd.myshardingfordata.helper.ConnectionManager;
 24 import com.fd.myshardingfordata.helper.TransManager;
 25 
 26 import cn.wowkai.mall.web.interceptor.AuthInterceptor;
 27 
 28 @EnableScheduling
 29 @SpringBootApplication
 30 public class ShopSaasMallApplication implements WebMvcConfigurer {
 31 
 32     public static void main(String[] args) {
 33         SpringApplication.run(ShopSaasMallApplication.class, args);
 34     }
 35 
 36     @Resource
 37     protected RedisTemplate<String, Object> redisTemplate;
 38 
 39     @PostConstruct
 40     private void init() {
 41         redisTemplate.setKeySerializer(new StringRedisSerializer(Charset.forName("UTF8")));
 42         redisTemplate.setValueSerializer(new StringRedisSerializer(Charset.forName("UTF8")));
 43     }
 44 
 45     @Override
 46     public void addInterceptors(InterceptorRegistry registry) {
 47         registry.addInterceptor(new AuthInterceptor(redisTemplate)).excludePathPatterns("/mall/mp/*",
 48                 "/mall/notify/panganNotify", "/mall/notify/panganRechargeNotify", "/mall/notify/panganbillNotify",
 49                 "/mall/notify/wxpayrechargenotify", "/mall/notify/wxpaybillnotify", "/mall/notify/wxpaynotify",
 50                 "/mall/api/getToken", "/mall/store/getStoreListWithLongitudeLatitude",
 51                 "/mall/sett/getIndexTemplateListWithXcx", "/mall/product/productListForXcxSelect",
 52                 "/mall/product/custFindProduct", "/mall/product/custFindProductSpeceInventoryAndPrice",
 53                 "/mall/sett/xcx/getIndexTemplateMastList");
 54     }
 55 
 56     @Resource
 57     private DataSource dataSource;
 58 
 59     @Bean
 60     public TransManager transManager() {
 61         TransManager trans = new TransManager();
 62         trans.setConnectionManager(connectionManager());
 63         return trans;
 64     }
 65 
 66     @Bean
 67     public ConnectionManager connectionManager() {
 68         ConnectionManager conm = new ConnectionManager();
 69         conm.setGenerateDdl(true);
 70         conm.setShowSql(false);
 71         conm.setInitConnect("set  names  utf8mb4");
 72         conm.setDataSource(dataSource);
 73         conm.setReadDataSources(Arrays.asList(dataSource));
 74 
 75         return conm;
 76     }
 77 
 78     @Bean
 79     public CorsFilter corsFilter() {
 80         // 1.添加CORS配置信息
 81         CorsConfiguration config = new CorsConfiguration();
 82         // 放行哪些原始域
 83         config.addAllowedOrigin("*");
 84         // 是否发送Cookie信息
 85         config.setAllowCredentials(true);
 86         // 放行哪些原始域(请求方式)
 87         config.addAllowedMethod("*");
 88         // 放行哪些原始域(头部信息)
 89         config.addAllowedHeader("*");
 90         // 暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
 91         config.addExposedHeader(HttpHeaders.LOCATION);
 92         config.setExposedHeaders(Arrays.asList("JSESSIONID", "SESSION", "token", HttpHeaders.LOCATION,
 93                 HttpHeaders.ACCEPT, HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS,
 94                 HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, HttpHeaders.COOKIE, HttpHeaders.SET_COOKIE,
 95                 HttpHeaders.SET_COOKIE2));
 96         // 2.添加映射路径
 97         UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
 98         configSource.registerCorsConfiguration("/**", config);
 99 
100         // 3.返回新的CorsFilter.
101         return new CorsFilter(configSource);
102     }
103 
104 }

1.3拦截器的应用场景

  拦截器的本质是面向切面编程(AOP),符合橫切关注点的功能都可以放在拦截器中来实现,主要的应用场景包括:

  1、登录验证,判断用户是否登录。

  2、权限验证,判断用户是否具有访问权限。

  3、日志记录,记录请求日志,以便统计请求访问量。

  4、处理cookie、本地化、国际化、主题等。

  5、性能监控,监控请求处理时长等。

2、原理

2.1、工作原理

  拦截器不是Filter,却实现了filter的功能,其原理在于:

  所有的拦截器(Interceptor)和处理器(Handler)都注册在HandlerMapping中。

  Spring MVC中所有的请求都是由DispatcherServlet分发的。

  当请求进入 DispatcherServlet.doDispatch()时候,首先会得到处理该请求的Handler(即Controller中对应的方法)以及所有拦截该请求的拦截器。拦截器就是在这里被调用开始工作的。
 
2.2、拦截器工作流程

  一个拦截器,只有preHandle方法返回true,postHandleafterCompletion才有可能被执行;如果preHandle方法返回false,则该拦截器的postHandleafterCompletion必然不会被执行。

假设我们有两个拦截器,例如叫Interceptor1和Interceptor2,当一个请求过来,正常的流程和中断的流程分别如下。

2.2.1正常流程

  注意两个拦截器在执行preHandle方法和执行postHandleafterCompletion方法时,顺序是颠倒的。

 1 Interceptor1.preHandle
 2 
 3 Interceptor2.preHandle
 4 
 5 //Controller处理请求
 6 
 7 Interceptor2.postHandle
 8 
 9 Interceptor1.postHandle
10 
11 //渲染视图
12 
13  Interceptor2.afterCompletion
14 
15  Interceptor1.afterCompletion

2.2.2中断流程

  假设执行 Interceptor2.preHandle中报错,那么流程被中断,之前被执行过的拦截器的afterCompletion仍然会执行。在本例中,即执行了 Interceptor1.afterCompletion
1 Interceptor1.preHandle
2 
3 Interceptor2.preHandle
4 
5 //中间流程被中断,不再执行
6 
7 Interceptor1.afterCompletion

2.3和Filter共存时的执行顺序

  拦截器是在DispatcherServlet这个servlet中执行的,因此所有的请求最先进入Filter,最后离开Filter。其顺序如下。

 1 Filter
 2 
 3 Interceptor.preHandle
 4 
 5 Handler
 6 
 7 Interceptor.postHandle
 8 
 9 Interceptor.afterCompletion
10 
11 Filter

猜你喜欢

转载自www.cnblogs.com/bulushengse/p/12157212.html