• springboot下使用拦截器、过滤器和监听器


    文章目录

    1. 拦截器Interceptor

    2. 过滤器Filter

    3. 监听器                                                                                                                                                                                                                    1. 拦截器Interceptor

      • Spring MVC的拦截器(Interceptor)和Filter不同,但是也可以实现对请求进行预处理,后处理。先介绍它的使用,只需要两步:
        1.1 实现拦截器
        实现拦截器可以通过继承HandlerInterceptorAdapter类。如果preHandle方法return true,则继续后续处理。

        public class InterceptorDemo extends HandlerInterceptorAdapter {
        
        
            @Override
            public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
                StringBuffer requestURL = httpServletRequest.getRequestURL();
                System.out.println("前置拦截器1 preHandle: 请求的uri为:"+requestURL.toString());
                return true;
            }
        
            @Override
            public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
                System.out.println("拦截器1 postHandle: ");
            }
        
            @Override
            public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
                System.out.println("拦截器1 afterCompletion: ");
            }
        }

        1.2 注册拦截器
        实现拦截器后还需要将拦截器注册到spring容器中,可以通过implements WebMvcConfigurer,覆盖其addInterceptors(InterceptorRegistry registry)方法。记得把Bean注册到Spring容器中,可以选择@Component 或者 @Configuration。

        @Configuration
        public class InterceptorConfig implements WebMvcConfigurer{
        
             /**
             * 注册自定义拦截器
             */
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                
                   registry.addInterceptor(new InterceptorDemo2()).addPathPatterns("/**");
                registry.addInterceptor(new InterceptorDemo()).addPathPatterns("/**");
            }
         }

        注意这里注册了两个拦截器。这两个拦截器的执行顺序和配置顺序有关系,即先配置顺序就在前(感觉这样不太方便,但没有找到设置类似order的API)。

        发起一个请求,在控制台可以看到拦截器生效:

        前置拦截器2 preHandle: 用户名:null
        前置拦截器1 preHandle: 请求的uri为:http://localhost:8010/user/353434
        拦截器1 postHandle: 
        拦截器2 postHandle: 
        拦截器1 afterCompletion: 
        拦截器2 afterCompletion:

        1.3 拦截器的总结
        1.3.1 工作原理
        一个拦截器,只有preHandle方法返回true,postHandle、afterCompletion才有可能被执行;如果preHandle方法返回false,则该拦截器的postHandle、afterCompletion必然不会被执行。拦截器不是Filter,却实现了Filter的功能,其原理在于:

        所有的拦截器(Interceptor)和处理器(Handler)都注册在HandlerMapping中。
        Spring MVC中所有的请求都是由DispatcherServlet分发的。
        当请求进入DispatcherServlet.doDispatch()时候,首先会得到处理该请求的Handler(即Controller中对应的方法)以及所有拦截该请求的拦截器。拦截器就是在这里被调用开始工作的。
        1.3.2 拦截器工作流程

        正常流程:

            1.Interceptor2.preHandle
              2.Interceptor1.preHandle
              3.Controller处理请求
              4.Interceptor1.postHandle
              5.Interceptor2.postHandle
              6.渲染视图view
              2.Interceptor1.afterCompletion
              2.Interceptor2.afterCompletion

        中断流程
        如果在Interceptor1.preHandle中报错或返回false ,那么接下来的流程就会被中断,但注意被执行过的拦截器的afterCompletion仍然会执行。下图为Interceptor1.preHandle返回false的情况:                                                                                                                                                                                    

        前置拦截器2 preHandle: 用户名:null
        前置拦截器1 preHandle: 请求的uri为:http://localhost:8010/user/353434
        拦截器2 afterCompletion:

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

        Filter->Interceptor.preHandle->Handler->Interceptor.postHandle->Interceptor.afterCompletion->Filter

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

        登录验证,判断用户是否登录。
        权限验证,判断用户是否有权限访问资源,如校验token
        日志记录,记录请求操作日志(用户ip,访问时间等),以便统计请求访问量。
        处理cookie、本地化、国际化、主题等。
        性能监控,监控请求处理时长等。
        2. 过滤器Filter
        springboot下过滤器的使用有两种形式:
        2.1 注解形式
        创建一个Filter,并使用WebFilter注解进行修饰,表示该类是一个Filter,以便于启动类进行扫描的时候确认

        @WebFilter(urlPatterns = "/*",filterName = "filter2")
        public class FilterAnnotationTest implements Filter {
        
            @Override
            public void init(FilterConfig filterConfig) throws ServletException {
                System.out.println("过滤器2开始初始化");
            }
        
            @Override
            public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
                System.out.println("过滤器2开始工作");
                filterChain.doFilter(servletRequest,servletResponse);
            }
        
            @Override
            public void destroy() {
                System.out.println("过滤器2销毁");
            }
        }

        然后在启动类上添加注解@ServletComponentScan,该注解用于自动扫描指定包下(默认是与启动类同包下)的WebFilter/WebServlet/WebListener等特殊类。
        2.2 代码注册方式
        同样编写Filter,但是不添加WebFilter注解,通过@Bean注入spring

        public class FilterDemo implements Filter {
        
            @Override
            public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
                HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
                System.out.println("过滤器开始工作。。"+httpServletRequest.getRequestURL());
                filterChain.doFilter(servletRequest,servletResponse);
            }
        
            @Override
            public void destroy() {
                System.out.println("过滤器开始销毁");
            }
        }

        然后利用filterRegistrationBean来进行注册。也可以在代码里设置Order                                                                                                                                       

        @Configuration
        public class FilterDemo {
            @Bean
            @Order(2)
            //spring boot会按照order值的大小,从小到大的顺序来依次过滤
            public FilterRegistrationBean configFilter(){
                FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
                filterRegistrationBean.setFilter(new FilterDemo());
                filterRegistrationBean.addUrlPatterns("/*");
                filterRegistrationBean.setName("sessionFilter");
                //filterRegistrationBean.setOrder(2);
                return filterRegistrationBean;
            }
            
        }

        2.3 过滤器filter和拦截器Interceptor的区别
        spring的拦截器和servlet的过滤器有相似之处,都是AOP思想的体现,都可以实现权限检查,日志记录,不同的是

        1.适用范围不同:Filter是Servlet容器规定的,只能使用在servlet容器中,而拦截器的使用范围就大得多
        2.使用的资源不同:拦截器是属于spring的一个组件,因此可以使用spring的所有资源,对象,如service对象,数据源,事务控制等,而过滤器就不行
        3.深度不同:Filter还在servlet前后起作用。而拦截器能够深入到方法前后,异常抛出前后,因此拦截器具有更大的弹性,所有在spring框架中应该优先使用拦截器。
        通过调试可以发现,拦截器的执行过程是在过滤器的doFilter中执行的,过滤器的初始化会在项目启动时执行。

        过滤器开始工作。。http://localhost:8010/user/353434
        前置拦截器2 preHandle: 用户名:null
        前置拦截器1 preHandle: 请求的uri为:http://localhost:8010/user/353434
        拦截器1 postHandle: 
        拦截器2 postHandle: 
        拦截器1 afterCompletion: 
        拦截器2 afterCompletion: 
        过滤器开始工作。。http://localhost:8010/favicon.ico

        可以通过这个博客里的一张图来说明:                                                                                                                                                                                                                              

        3. 监听器

        监听器的简单使用如下:先编写监听器的实现:

        @WebListener
        public class WebListenerDemo implements ServletContextListener {
        
        
            @Override
            public void contextInitialized(ServletContextEvent sce) {
                System.out.println("监听器初始化。。。。。。。。。。。。");
            }
        
            @Override
            public void contextDestroyed(ServletContextEvent sce) {
                System.out.println("监听器销毁。。。。。。。。。。。");
            }
        }

        监听session创建的监听器(可以用来统计在线人数)

      • @WebListener
        public class SessionListener implements HttpSessionListener {
        
            @Override
            public void sessionCreated(HttpSessionEvent se) {
                System.out.println("。。。创建session成功");
            }
        
            @Override
            public void sessionDestroyed(HttpSessionEvent se) {
                System.out.println("。。。销毁session");
            }
        }

        然后在启动类上添加注解@ServletComponentScan即可,当然也可以注册到spring容器中省却@ServletComponentScan注解。                                               

        @Configuration
        public class ListenerConfig {
            @Bean
            public ServletListenerRegistrationBean servletListenerRegistrationBean() {
                ServletListenerRegistrationBean slrBean = new ServletListenerRegistrationBean();
                slrBean.setListener(new WebListenerDemo());
                return slrBean;
            }
        
            @Bean
            public ServletListenerRegistrationBean sessionListenerRegistrationBean() {
                ServletListenerRegistrationBean slrBean = new ServletListenerRegistrationBean();
                slrBean.setListener(new SessionListener());
                return slrBean;
            }
        }
  • 相关阅读:
    黑马day16 jquery案例演示
    duilib各种布局的作用,相对布局与绝对布局的的意义与使用方法
    Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: “object”未包括“get_Range”的定义
    Android App 内存泄露之调试工具(1)
    手动安装huson插件的做法
    Linux管理日记(二)
    小强的HTML5移动开发之路(9)——坦克大战游戏3
    TextView中实现跑马灯的最简单方法
    Android中使用achartengine生成图表
    Android菜鸟的成长笔记(6)——剖析源码学自定义主题Theme
  • 原文地址:https://www.cnblogs.com/BruceV/p/12066812.html
Copyright © 2020-2023  润新知