过滤器和监听器

过滤器和监听器

过滤器 Filter

当客户端访问服务器的某些资源时,过滤器可以将请求拦截,一般用于完成通用的操作,例如登录验证、统一编码处理、敏感字符过滤等。与 Servlet 地位相同,Filter 是 JavaWeb 的三大组件之一。

使用 Filter

要使用过滤器 Filter,首先定义一个类实现 Filter 接口,实现其中的抽象方法,然后通过 web.xml 文件或者注解配置该类,例如使用注解配置

package cool.yzt.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

// 配置 Filter 要拦截的资源路径,这里拦截所有资源
@WebFilter(urlPatterns = {"/*"})
public class FilterDemo1 implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 放行请求前的操作
        System.out.println("第一次执行过滤器");
        // 放行
        filterChain.doFilter(servletRequest,servletResponse);
        // 访问到资源后响应时的操作
        System.out.println("第二次执行过滤器");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }
}

注意到,一次资源访问会经过过滤器两次,所以一般在放行请求前,会对 request 作增强操作,而访问资源后再次经过过滤器时,一般是对 response 做出增强操作。

关于 Filter 的配置

如果使用注解配置,其中的 urlPatterns 属性配置的是要拦截的资源,注意这点和 Servlet 不同,具体来说可以有以下几种情况

  • 拦截某个具体资源,例如 urlPatterns = {"/index.html"}
  • 拦截某个目录。例如 urlPatterns = {"/user/"} 即拦截 user 目录下的所有资源
  • 拦截某个后缀名的资源,例如 urlPatterns = {"*.jsp"} 即拦截所有 jsp 文件
  • 拦截所有资源,urlPatterns = {"/*"}

除了可以配置 urlPatterns 属性,有时还需要配置 dispatcherTypes 属性,即拦截使用该方式的访问,而不拦截其他方式,主要有以下取值

  • REQUEST,默认值,指浏览器直接请求资源
  • FORWARD,转发方式访问资源
  • INCLUDE,包含方式访问资源
  • ERROR,错误跳转资源
  • ASYNC,异步访问资源

如果使用 web.xml 文件配置

<filter>
    <!-- 过滤器的别名 -->
    <filter-name>demo1</filter-name>
    <!-- 过滤器的全类名 -->
    <filter-class>cn.itcast.web.filter.FilterDemo1</filter-class>
</filter>
<!-- 关系映射 -->
<filter-mapping>
    <filter-name>demo1</filter-name>
    <!-- 拦截路径 -->
    <url-pattern>/*</url-pattern>
    <!-- 拦截访问方式 -->
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

Filter 链

有时一个过滤器无法满足需求,可能会用到一系列的过滤器组成过滤器链

通过注解配置的 Filter 链,拦截请求时,按照其类名的字典顺序从小到大依次执行,访问资源后对客户端做出响应时,拦截请求时先执行的过滤器反而后执行执行(可以看做是栈,先进后出)

通过 web.xml 配置的 Filter 链,先于注解配置的 Filter 执行,且按照配置文件从上到下的顺序依次执行,与类名无关

Filter 的生命周期

注意到 Filter 接口三个必须实现的方法:init()doFilter()destroy

  1. init():在服务器启动后,会创建 Filter 对象,然后调用 init() 方法,所以该方法只执行一次,一般用于加载资源
  2. doFilter():对于被拦截资源的每一次请求,该方法都会执行,所以会执行多次
  3. destroy():在服务器关闭后,Filter 对象被销毁,如果服务器是正常关闭,则会执行 destroy() 方法,所以该方法只执行一次,一般用于释放资源

监听器 Listener

监听器同样是 JavaWeb 的三大组件之一,监听器的本质就是一个对象,事件监听机制最关键的就是注册监听,就是指将事件、事件源、监听器绑定在一起,当事件源上某个事件发生时,监听器的代码就会被执行。

ServletContextListener

ServletContextListener 是一个常用的监听器,用于监听 ServletContext 对象的创建和销毁

创建一个 Listener 类,实现 ServletContextListener 接口,发现有两个需要实现的接口,并且监听器需要加上 @WebListener 注解,服务器启动后,ServletContext 对象会自动创建,所以 ServletContextListenercontextInitialized() 方法会被自动调用,一般用于加载整个项目都需要的资源,而当服务器关闭时,ServletContext 对象会被销毁,如果服务器正常关闭,ServletContextListenercontextDestroyed() 方法会被自动调用。

// 监听 ServletContext 对象的创建和销毁
// 
@WebListener
public class ListenerDemo implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("ServletContext对象被创建了");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("ServletContext对象被销毁了");
    }
}

Listener 配置

  1. web.xml 配置
<listener>
    <listener-class>cool.yzt.listener.ListenerDemo</listener-class>
</listener>
  1. 注解配置
@WebListener

参考