学静思语
Published on 2025-02-15 / 2 Visits
0
0

Listener监听器和Filter过滤器

Listener监听器和Filter过滤器

一、Listener监听器

1. Listener监听器介绍

  • Listener监听器它是JavaWeb的三大组件之一,JavaWeb的三大组件分别是:Servlet程序、Listener监听器、Filter过滤器

  • Listener是一个接口,是JavaWeb的规范的一种、

  • 监听器的作用是:监听某种变化(如:对象的创建和销毁,属性的添加和删除等),然后再触发对应的方法完成相应的任务

  • JavaWeb中常用的监听器有八个,目前最常用的是ServletContextListener

  • 流程图

    image-20231109163840467

2.ServletContextListener监听器

  • 作用:监听ServletContext创建或销毁(当web应用启动时,就会创建ServletContext),可以理解为生命周期的监听

  • 应用场景:

  • 加载初始化的配置文件:比如spring的配置文件

  • 任务调度(配合定时器Timer/TimerTask)

  • 相关方法

     package com.leon.listener;
    
     import javax.servlet.ServletContext;
     import javax.servlet.ServletContextEvent;
     import javax.servlet.ServletContextListener;
    
     /**
      * ClassName:ContextListener
      * Package:com.leon.listener
      * Description:
      *
      * @Author: leon-->ZGJ
      * @Create: 2023/11/9 16:57
      * @Version: 1.0
      */
    
     /**
      * 1. 当一个类实现了ServletContextListener接口,该类就是一个监听器了
      * 2. 该类可以监听的事件由该类所实现的接口所决定的。
      *  比如:实现ServletContextListener,则该类就可以监听ServletContext对象的创建和销毁,其     他的以此类推
      * 3.ContextListener就是一个监听者
      * 4.当web应用启动时,就会产生ServletContextEvent事件,因为Tomcat在启动web应用程序时就会创     建一个ServletContext对象
      *  会调用监听器的对应事件处理方法contextInitialized()同时会传递事件对象                  ServletContextEvent
      * 5. 程序员可以通过ServletContextEvent事件对象,来获取需要的信息,然后再进行业务处理
      * 6. Tomcat通过web.xml文件在使用反射创建相应的监听器对象
      */
     public class ContextListener implements ServletContextListener {
    
         //被创建时调用
         @Override
         public void contextInitialized(ServletContextEvent sce) {
             ServletContext servletContext = sce.getServletContext();
             System.out.println("ServletContext 被创建了" + servletContext);
         }
      //被销毁时调用
         @Override
         public void contextDestroyed(ServletContextEvent sce) {
             ServletContext servletContext = sce.getServletContext();
             System.out.println("ServletContext 被销毁了" + servletContext);
         }
     }
    

3.ServletContextAttributeListener监听器

  • 作用:监听ServletContext属性变化

  • 相关方法

    import javax.servlet.ServletContextAttributeListener;
    
    /**
    
  • ClassName:ContextAttributeListener

  • Package:com.leon.listener

  • Description:
    *

  • @Author: leon–>ZGJ

  • @Create: 2023/11/9 19:08

  • @Version: 1.0
    */
    public class ContextAttributeListener implements ServletContextAttributeListener {
    //属性添加的时候调用
    @Override
    public void attributeAdded(ServletContextAttributeEvent scae) {

      System.out.println("ContextAttributeListener attributeAdded 被调用了~~~~");
      System.out.println("添加属性了");
      System.out.println("添加的属性:" + scae.getName());
    

    }

    //属性删除的时候调用
    @Override
    public void attributeRemoved(ServletContextAttributeEvent scae) {

      System.out.println("ContextAttributeListener attributeRemoved 被调用了~~~~");
      System.out.println("替换属性了");
      System.out.println("删除的属性:" + scae.getName());
    

    }

    //属性替换的时候调用
    @Override
    public void attributeReplaced(ServletContextAttributeEvent scae) {

      System.out.println("ContextAttributeListener attributeReplaced 被调用了~~~~");
      System.out.println("修改属性了");
      System.out.println("修改的属性:" + scae.getName());
    

    }
    }

4. HttpSessionListener监听

  • 作用:监听Session创建或销毁,即生命周期监听

  • 相关方法

    package com.leon.listener;
    
    import javax.servlet.http.HttpSession;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    
    /**
    
  • ClassName:SessionListener

  • Package:com.leon.listener

  • Description:
    *

  • @Author: leon–>ZGJ

  • @Create: 2023/11/9 19:44

  • @Version: 1.0
    */
    public class SessionListener implements HttpSessionListener {
    //创建Session的时候调用
    @Override
    public void sessionCreated(HttpSessionEvent se) {

    System.out.println("SessionListener sessionCreated被调用了~~~~");
    HttpSession session = se.getSession();
    System.out.println("被创建的Session的id是:" + session.getId());
    

    }
    //删除Session的时候调用
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {

    System.out.println("SessionListener sessionDestroyed被调用了······");
    HttpSession session = se.getSession();
    System.out.println("被删除的Session的id是:" + session.getId());
    

    }
    }

  • 使用场景:监控用户上线,离线

5.HttpSessionAttributeListener监听器

  • 作用:监听Session属性的变化

  • 相关方法

    package com.leon.listener;
    
    import javax.servlet.http.HttpSessionAttributeListener;
    import javax.servlet.http.HttpSessionBindingEvent;
    
    /**
    
  • ClassName:SessionAttributeListener

  • Package:com.leon.listener

  • Description:
    *

  • @Author: leon–>ZGJ

  • @Create: 2023/11/9 20:01

  • @Version: 1.0
    */
    public class SessionAttributeListener implements HttpSessionAttributeListener {

    @Override
    public void attributeAdded(HttpSessionBindingEvent se) {

      System.out.println("SessionAttributeListener attributeAdded 属性添加了:--->" + se.getValue());
    

    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent se) {

      System.out.println("SessionAttributeListener attributeRemoved 属性删除了:--->" + se.getValue());
    

    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent se) {

      System.out.println("SessionAttributeListener attributeReplaced 属性替换了:--->" + se.getValue());
    

    }
    }

6.ServletRequestListener监听器

  • 作用:监听Request创建或销毁,即Request生命周期监听

  • 相关方法

    package com.leon.listener;
    
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletRequestEvent;
    import javax.servlet.ServletRequestListener;
    import javax.servlet.http.HttpServletRequest;
    
    /**
    
  • ClassName:RequestListener

  • Package:com.leon.listener

  • Description:
    *

  • @Author: leon–>ZGJ

  • @Create: 2023/11/9 20:16

  • @Version: 1.0
    */
    public class RequestListener implements ServletRequestListener{

    @Override
    public void requestInitialized(ServletRequestEvent sre) {

      System.out.println("Request被创建了");
      ServletRequest servletRequest = sre.getServletRequest();
      System.out.println(((HttpServletRequest)servletRequest).getRequestURL());
    

    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {

      System.out.println("Request被销毁了");
    

    }
    }

  • 使用场景:某个IP访问我们网站的频率,日志,访问资源

7.ServletRequestAttributeListener监听器

  • 作用:Request属性的变化

  • 相关方法

    package com.leon.listener;
    
    import javax.servlet.ServletRequestAttributeEvent;
    import javax.servlet.ServletRequestAttributeListener;
    
    /**
    
  • ClassName:RequestAttributeListener

  • Package:com.leon.listener

  • Description:
    *

  • @Author: leon–>ZGJ

  • @Create: 2023/11/9 20:20

  • @Version: 1.0
    */
    public class RequestAttributeListener implements ServletRequestAttributeListener {

    @Override
    public void attributeAdded(ServletRequestAttributeEvent srae) {

      System.out.println("Request 的属性添加了");
    

    }

    @Override
    public void attributeRemoved(ServletRequestAttributeEvent srae) {

      System.out.println("Request 的属性删除了");
    

    }

    @Override
    public void attributeReplaced(ServletRequestAttributeEvent srae) {

      System.out.println("Request 的属性修改了");
    

    }
    }

8.其他监听器

  • HttpSessionBindingListener监听器
  • HttpSessionActivationListener监听器

二、Filter过滤器

1. 使用过滤器的原因

  • 使用传统的每个页面进行验证,会造成代码的冗余,因而功能是重复的,这样不便于维护
  • 过滤器可以:统计进行验证,比如权限,身份,日志,事务

2.Filter过滤器的工作原理

image-20231109213724778

3.Filter过滤器的注意事项

  • Servlet中的请求转发是不会激发过滤器的

  • 在web.xml文件中的注意事项

    1.Filter一般是写在其他Servlet的前面
    2.通过观察发现Filter与Servlet非常相似,由此可得Filter也是被tomcat管理和维护
    3.Filter中的url-pattern标签,就是当你在请求的时候的URL和url-pattern标签中的URL匹配时
    就会调用该Filter
    4./manage/* 因为是在服务器解析所以第一个"/"会被解析成 http://ip:port/工程路径
    5.完整的路径就是http://ip:port/工程路径/manage/* 当请求的URL满足该条件时都会调用该Filter
    标签中的解读
      <!--ManageFilter-->
      <filter>
          <filter-name>ManageFilter</filter-name>
          <filter-class>com.leon.filter.ManageFilter</filter-class>
      </filter>
      <filter-mapping>
          <filter-name>ManageFilter</filter-name>
          <!--目录匹配
           1.这个"*"表示Mange目录下的任意资源被请求的时候都会被匹配上
           2."*"可以表示多成目录,只要是Manage下的子目录即可
          -->
          <url-pattern>/manage/*</url-pattern>
      </filter-mapping>
    
  • Filter过滤器中的doFilter(ServletRequest request,ServletResponse response,FilterChain filterChain)注意事项

    filterChain.doFilter(servletRequest, servletResponse);
    /*
      该方法的解析
      1.表示可以继续访问目标资源,也可以理解为放行
      2.servletRequest和ServletResponse 对象会传递给目标资源或文件
      3.目标资源所获取的request和response对象是和Filter所传过来的对象是相同的(指的是同一个      http请求)
    */
    

4. Filter过滤器在web.xml文件中的url-pattern

  • url-pattern :表示Filter的拦截路径,即浏览器在请求的URL匹配上拦截路径时,过滤器会进行拦截过滤
  • 精确匹配< url-pattern >/a.jsp< /url-pattern >对应的匹配请求地址为:http://ip:port/工程路径/a.jsp会被拦截
  • 目录匹配 < url-pattern >/manage/*< /url-pattern >对应的匹配请求地址为:http://ip:port/工程路径/manage/xxx,即web工程下的Manage目录下的所有资源都会被拦截
  • 后缀名匹配 < url-pattern >.jsp< /url-pattern >后缀名可变,比如 .action *.do对应的匹配请求地址为:http://ip:port/工程路径/xxx.jsp,后缀名为.jsp会被拦截
  • 任意匹配 < url-pattern >/< /url-pattern >后缀名可变,比如 .action *.do对应的匹配请求地址为:http://ip:port/工程路径,即web工程下的任意资源都会被拦截
  • Filter过滤器它只关心请求的地址是否匹配,不关心请求的资源是否存在

5. Filter生命周期的注意事项

  • filter在web项目启动时,由tomcat来创建Filter实例,每个Filter只会创建一次Filter实例,如果重启和从新发布则会再次创建,因为之前的Filter实例被清除了
  • tomcat会调用Filter默认的无参构造器,同时会调用init方法,每个Filter实例的init方法也只会调用一次
  • 在创建Filter实例时,同时会创建一个FilterConfig对象,并通过init方法传入
  • 通过FilterConfig对象,程序员可以获取该Filter的相关配置信息
  • 当一个http请求和该Filter的url-pattern匹配时,就会调用doFiilter()方法
  • 在调用doFilter()方法时,tomcat会同时创建ServletRequest和ServletResponse和FilterChain对象,并通过doFiter()方法传入
  • 如果后面的请求目标资源(jsp,servlet….),使用的request和response与前面Filter传递的ServletRequest和ServletResponse的对象是同一个

6.FilterConfig接口

  • 类图

    image-20231110100820714

  • 说明

  • FilterConfig是Filter过滤器的配置类

  • Tomcat每次创建Filter的时候,也会创建一个FilterConfig对象,这里包含了Filter配置文件的配置信息

  • FilterConfig对象作用是获取Filter过滤器的配置内容

7. FilterChain注意事项和细节

  • 多个Filter和目标资源在一次http请求,在同一个线程中

  • 当一个请求URL和Filter的url-pattern匹配时,才会被执行,如果有多个匹配上,就会顺序执行,形成一个Filter调用链【这个顺序是你定义在web.xml中Filter的顺序】

  • 多个Filter共同执行时,因为是一次http请求,使用同一request对象

  • 多个Filter执行顺序,和web.xml配置顺序保持一致

  • filterChain.doFilter(ServletRequest request ,ServletResponse response)方法,将执行下一个过滤器的doFilter()方法,如果后面没有过滤器,则执行目标资源(或文件)

  • 顺序分析(案例)

  • 类1

    package com.leon.filter;
    
    import javax.servlet.*;
    import java.io.IOException;
    
    /**
    
  • ClassName:ChainFilter1

  • Package:com.leon.filter

  • Description:
    *

  • @Author: leon–>ZGJ

  • @Create: 2023/11/10 10:52

  • @Version: 1.0
    */
    public class ChainFilter1 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

      System.out.println("ChainFilter1 前置代码");
      filterChain.doFilter(servletRequest,servletResponse);
      System.out.println("ChainFilter1 后置代码");
    

    }

    @Override
    public void destroy() {

    }
    }

  • 类2

    package com.leon.filter;
    
    import javax.servlet.*;
    import java.io.IOException;
    
    /**
     * ClassName:ChainFilter2
     * Package:com.leon.filter
     * Description:
     *
     * @Author: leon-->ZGJ
     * @Create: 2023/11/10 10:53
     * @Version: 1.0
     */
    public class ChainFilter2 implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("ChainFilter2 前置代码");
            filterChain.doFilter(servletRequest,servletResponse);
            System.out.println("ChainFilter2 后置代码");
        }
    
        @Override
        public void destroy() {
    
        }
    }
    
  • 执行顺序(在web.xml文件中ChainFilter1定义在ChainFilter2的前面)

    数


Comment