SpringBoot中使用过滤器(filter)/监听器(listener)/拦截器(interceptorHandler)

 

在实际开发过程中,经常会碰见一些比如系统启动初始化信息、统计在线人数、在线用户数、过滤敏/高词汇、访问权限控制(URL级别)等业务需求。实现以上的功能,都会或多或少的用到过滤器监听器拦截器

一.SpringBoot整合过滤器Filter

过滤器Filter,是Servlet的的一个实用技术了。可以通过过滤器,对请求进行拦截处理。

  • 编写普通Java类实现接口Filter。

  • 使用注解@WebFilter标注过滤器类,并配置过滤url。

  • 在启动类加入@ServletComponentScan注解使用@ServletComponentScan注解后,Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册。

  • 开启启动类,访问测试,查看控制台结果

Filter

 @WebFilter
 public class MyFilter implements Filter {
     @Override
     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
         System.out.println("执行了filter 过滤器");
         filterChain.doFilter(servletRequest,servletResponse);
         System.out.println("离开了filter 过滤器");
     }
 }

启动类

 @SpringBootApplication
 @ServletComponentScan  //扫描 filter/listener/servlet 的注解 
 public class DemoApplication {
     public static void main(String[] args) { 
       SpringApplication.run(DemoApplication.class, args); }
 }
 ​

运行结果

 执行了filter 过滤器
 filter1 执行了...
 离开了filter 过滤器

多个过滤器配置

目录结构如图:

过滤器执行顺序:过滤器会按照名称比较,比较小的先执行。例如: AFilter和BFilter 时 AFilter会先执行

 

 执行了filter 过滤器
 执行了filter2 过滤器
 filter1 执行了...
 离开了filter2 过滤器
 离开了filter 过滤器

如果想手动控制filter的执行顺序,可以通过配置类完成,如果使用配置类,此时filter上不需要@WebFilter注解 ,如下:

 @Configuration
 public class WebConfiguration {
     // 注册第一个Filter
     @Bean // 标注为Spring配置bean组件
     public FilterRegistrationBean registerFilter1() {
         //通过FilterRegistrationBean实例设置优先级可以生效
         FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
         // 注册自定义过滤器
         registrationBean.setFilter(new MyFilter());
         // 设置过滤器的名字
         registrationBean.setName("filter01");
         // 设置过滤器的名字过滤路径
         registrationBean.addUrlPatterns("/*");
         // 设置过滤器优先级:最顶级
         registrationBean.setOrder(6);
         return registrationBean;
     }
     @Bean
     public FilterRegistrationBean registerFilter2() {
         FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
         // 注册第二个自定义过滤器TestFilter2
         registrationBean.setFilter(new MyFilter2());
         registrationBean.setName("filter02");
         registrationBean.addUrlPatterns("/*");
         registrationBean.setOrder(5);
         return registrationBean;
     }
 }

结果如下:

 执行了filter2 过滤器
 执行了filter 过滤器
 filter1 执行了...
 离开了filter 过滤器
 离开了filter2 过滤器

二,SpringBoot整合拦截器

拦截器介绍

Java中的拦截器是动态拦截 action 调用的对象,然后提供了可以在 action 执行前后增加一些操作,也可以在 action 执行前停止操作,功能与过滤器类似,但是标准和实现方式不同。

  • 登录认证:在一些应用中,可能会通过拦截器来验证用户的登录状态,如果没有登录或者登录失败,就会给用户一个友好的提示或者返回登录页面,当然大型项目中都不采用这种方式,都是调单点登录系统接口来验证用户。

  • 记录系统日志:我们在常见应用中,通常要记录用户的请求信息,比如请求 ip,方法执行时间等,通过这些记录可以监控系统的状况,以便于对系统进行信息监控、信息统计、计算 PV、性能调优等。

  • 通用处理:在应用程序中可能存在所有方法都要返回的信息,这是可以利用拦截器来实现,省去每个方法冗余重复的代码实现。

使用拦截器

我们需要实现 HandlerInterceptor 类,并且重写三个方法

  • preHandle:在 Controoler 处理请求之前被调用,返回值是 boolean类型,如果是true就进行下一步操作;若返回false,则证明不符合拦截条件,在失败的时候不会包含任何响应,此时需要调用对应的response返回对应响应。

  • postHandler:在 Controoler 处理请求执行完成后、生成视图前执行,可以通过ModelAndView对视图进行处理,当然ModelAndView也可以设置为 null。

  • afterCompletion:在 DispatcherServlet 完全处理请求后被调用,通常用于记录消耗时间,也可以对一些资源进行处理。

 public class MyInterceptor implements HandlerInterceptor {
     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
             throws Exception {
         System.out.println("preHandle请求访问前,拦截执行……");
         // 返回 false 则请求中断
         return true;
     }
     @Override
     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                            ModelAndView modelAndView) throws Exception {
         System.out.println("postHandle请求访问后,执行……");
     }
     @Override
     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
             throws Exception {
         System.out.println("afterCompletion请求调用完成后回调方法,即在视图渲染完成后回调……");
     }
 }

注册到配置文件中

 @Configuration
 public class InterceptorConfig implements WebMvcConfigurer {
 ​
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
         // 添加一个实现HandlerInterceptor接口的拦截器实例
         registry.addInterceptor(new MyInterceptor())
                 // 用于设置拦截器的过滤路径规则
                 .addPathPatterns("/**")
                 // 用于设置不需要拦截的过滤规则
                 .excludePathPatterns("/emp/toLogin", "/emp/login", "/js/**", "/css/**", "/images/**");
     }
 }

三,SpringBoot整合监听器

监听器介绍

监听器通常用于监听 Web 应用程序中对象的创建、销毁等动作的发送,同时对监听的情况作出相应的处理,最常用于统计网站的在线人数、访问量等。

监听器大概分为以下几种:

  • ServletContextListener:用来监听 ServletContext 属性的操作,比如新增、修改、删除。

  • HttpSessionListener:用来监听 Web 应用种的 Session 对象,通常用于统计在线情况。

  • ServletRequestListener:用来监听 Request 对象的属性操作。

监听器的使用

我们通过 ServletRequestListener来统计当前在线人数、ip等信息,为了避免并发问题我们使用原子int来计数。

ServletContext,是一个全局的储存信息的空间,它的生命周期与Servlet容器也就是服务器保持一致,服务器关闭才销毁。request,一个用户可有多个;session,一个用户一个;而servletContext,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。因此我们这里用ServletContext来存储在线人数sessionCount最为合适。

我们下面来统计当前在线人数

@WebListener
public class MyHttpRequestListener implements ServletRequestListener {
    private static int onLineCount = 0;
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
        System.out.println("requestListener:  create--> " + request.getSession().getId());
        onLineCount ++;
    } 
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
        System.out.println("requestListener: destroy--> " + request.getSession().getId());
        onLineCount--;
    }
}

四,过滤器、拦截器、监听器注册

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    MyInterceptor myInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor);
    }
    /**
     * 注册过滤器
     * @return
     */
    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
        filterRegistration.setFilter(new MyFilter());
        filterRegistration.addUrlPatterns("/*");
        return filterRegistration;
    }

    /**
     * 注册监听器
     * @return
     */
    @Bean
    public ServletListenerRegistrationBean registrationBean(){
        ServletListenerRegistrationBean registrationBean = new ServletListenerRegistrationBean();
        registrationBean.setListener(new MyHttpRequestListener());
        registrationBean.setListener(new MyHttpSessionListener());
        return registrationBean;
    }
}

拦截器与过滤器的区别

1.参考标准

  • 过滤器是 JavaEE 的标准,依赖于 Servlet 容器,生命周期也与容器一致,利用这一特性可以在销毁时释放资源或者数据入库。

  • 拦截器是SpringMVC中的内容,依赖于web框架,通常用于验证用户权限或者记录日志,但是这些功能也可以利用 AOP 来代替。

2.实现方式

  • 过滤器是基于回调函数实现,无法注入 ioc 容器中的 bean。

  • 拦截器是基于反射来实现,因此拦截器中可以注入 ioc 容器中的 bean,例如注入 Redis 的业务层来验证用户是否已经登录。

你可能感兴趣的:(Java之旅,java)