过滤器概述

1. 是什么?

Filter 是 Servlet 规范 定义的接口(javax.servlet.Filter),本质是一个 “拦截器” 。它的作用域是 请求到达 Servlet 之前响应返回浏览器之前

2.原理是什么?

基于责任链模式实现:客户端请求 → 过滤器 1 → 过滤器 2 → … → Servlet → 过滤器 2 → 过滤器 1 → 客户端响应。过滤器可以选择:

  • 放行请求:chain.doFilter(request, response)
  • 拦截请求:不调用 doFilter,直接跳转 / 返回响应

过滤器的使用

开发步骤(传统 web.xml 方式)

  1. 创建过滤器类:实现 javax.servlet.Filter 接口
  2. 重写核心方法init()doFilter()destroy()
  3. 配置过滤器:在 web.xml 中配置拦截路径

完整代码示例

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

// 传统方式用web.xml配置
public class EncodingFilter implements Filter {
    // 初始化方法:过滤器创建时执行1次
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 可以获取web.xml中配置的初始化参数
        String encoding = filterConfig.getInitParameter("encoding");
        System.out.println("编码过滤器初始化,编码:" + encoding);
    }

    // 核心拦截方法:每次请求被拦截时执行
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 1. 请求预处理:设置编码
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        // 2. 放行请求(必须调用,否则请求无法到达Servlet)
        chain.doFilter(request, response);

        // 3. 响应后处理:可以在这里对响应做修改
        System.out.println("响应已返回客户端");
    }

    // 销毁方法:服务器关闭/过滤器销毁时执行1次
    @Override
    public void destroy() {
        System.out.println("编码过滤器销毁");
    }
}

配置方式(两种主流写法)

1. 注解方式(推荐)

核心注解:@WebFilter
// 拦截所有以 /demo8/ 开头的请求
@WebFilter(urlPatterns = "/demo8/*") 
public class LoggingFilter implements Filter {}
常用属性
属性说明
filterName过滤器名称(可选,默认类名)
urlPatterns/value拦截路径(数组,支持多个)
initParams初始化参数(@WebInitParam数组)
dispatcherTypes拦截的请求类型(默认REQUEST

2. web.xml 配置方式(可控顺序)

web.xml 配置示例
<!-- 注册过滤器 -->
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>com.example.filter.EncodingFilter</filter-class>
    <!-- 初始化参数 -->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>

<!-- 配置拦截路径 -->
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <!-- 拦截所有请求 -->
    <url-pattern>/*</url-pattern>
    <!-- 也可以拦截指定Servlet -->
    <!-- <servlet-name>MyServlet</servlet-name> -->
</filter-mapping>
拦截路径配置规则
配置方式示例说明
精确匹配/user/login仅拦截/user/login路径的请求
目录匹配/user/*拦截/user/下所有资源
后缀匹配*.do拦截所有以.do结尾的请求
全匹配/*拦截所有请求(最常用)

3. 注解 vs web.xml 对比

特性注解方式web.xml 方式
配置位置过滤器类上web.xml 文件
开发效率高,无需修改配置文件低,需手动配置
顺序控制按类名字母序,不灵活<filter-mapping>顺序,灵活
适用场景小型项目、快速开发大型项目、需要统一管理配置

完整代码示例

/**
 * 日志过滤器  记录请求的历史  将日志打印到控制台
 *
 * 1 实现Filter接口
 * 2 重写过滤方法
 * 3 配置过滤器
 *      在web.xml中配置
 *      注释
 */
public class LoggingFilter implements Filter {

    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    /**
     过滤请求的和响应的方法
     1 请求到达目标资源之前,先经过该方法
     2 该方法有能力控制请求是否继续向后到达目标资源 可以在该方法内直接向客户端做响应处理
     3 请求到达目标资源后,响应之前,还会经过该方法
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        /**
         * 1 请求到达目标资源之前的功能代码
         *          判断是否登录
         *          校验权限是否满足
         *          ...
         * 2 放行代码
         * 3 响应之前 HttpServletResponse 转换为响应报文之前 的功能代码
         *
         */
        // 请求到达目标资源之前的代码
        //System.out.println("LoggingFilter doFilter");
        //放行
        //filterChain.doFilter(servletRequest,servletResponse);
        //响应之前的功能代码
        //System.out.println("LoggingFilter doFilter end");
        //-----------------------------------------------------------


        //参数父转子
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        //请求到达目标资源之前  打印日志
        String requestURI = request.getRequestURI();
        String dateTime = dateFormat.format(new Date());
        String beforeLoggin = requestURI+"在"+dateTime+"访问了服务器";
        System.out.println(beforeLoggin);
        long t1 = System.currentTimeMillis();
        //放行
        filterChain.doFilter(servletRequest,servletResponse);
        //响应之前的功能代码 ***资源在**时间的请求耗时 毫秒
        long t2 = System.currentTimeMillis();
        String afterLoggin = requestURI+"资源在"+dateTime+"的请求耗时:"+(t2-t1)+"毫秒";
        System.out.println(afterLoggin);


    }
}
//------------------------------------------------------------------------------------------------------------------------------------------
 

@WebServlet(urlPatterns = "/servlet1")
public class Servlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("servlet1");
        resp.getWriter().write("servlet1 message");
    }
}

过滤器的生命周期

过滤器的生命周期由服务器管理,分为 3 个阶段:

  1. 创建与初始化

    • 时机:服务器启动时(或第一次请求时,取决于服务器配置)
    • 执行方法:init(FilterConfig filterConfig)
    • 执行次数:仅执行 1 次
    • 作用:完成初始化操作,比如读取配置参数、创建资源
  2. 拦截处理

    • 时机:每次请求匹配拦截路径时
    • 执行方法:doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    • 执行次数:每次请求都执行
    • 核心:通过 chain.doFilter() 控制是否放行
  3. 销毁

    • 时机:服务器正常关闭 / 项目卸载时
    • 执行方法:destroy()
    • 执行次数:仅执行 1 次
    • 作用:释放资源,比如关闭数据库连接
      过滤");
public class LifeCycleFilter implements Filter {
    /**
     1 构造  构造器  项目启动       1次
     2 初始化 init 构造完毕        1次
     3 过滤 doFilter 每次请求     多次
     4 销毁   destroy 服务器关闭   1次
     */
    public LifeCycleFilter(){
        System.out.println("构造器");
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化");
        System.out.println(filterConfig.getInitParameter("dateTimePattern"));
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("过滤");
        filterChain.doFilter(servletRequest,servletResponse);
    }
    @Override
    public void destroy() {
        System.out.println("销毁");
    }
}

过滤器链

核心定义

过滤器链(FilterChain) :当多个过滤器同时拦截同一个请求时,这些过滤器会形成一个链式结构,按照配置顺序依次执行。

执行顺序

  • 请求方向:按照过滤器配置的顺序依次执行(web.xml 中 <filter-mapping> 的顺序,注解方式按类名字母序)
  • 响应方向:按照过滤器配置的逆序依次执行
  • 示例:过滤器 A → 过滤器 B → Servlet → 过滤器 B → 过滤器 A

代码示例(两个过滤器)

过滤器 1:登录校验过滤器
public class LoginFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("登录过滤器:请求预处理");
        // 校验登录状态
        HttpServletRequest req = (HttpServletRequest) request;
        Object user = req.getSession().getAttribute("loginUser");
        if (user == null) {
            // 未登录,拦截跳转
            response.getWriter().write("请先登录!");
            return;
        }
        // 放行
        chain.doFilter(request, response);
        System.out.println("登录过滤器:响应后处理");
    }
    // 其他方法省略
}
过滤器 2:编码过滤器
public class EncodingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("编码过滤器:请求预处理");
        request.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response);
        System.out.println("编码过滤器:响应后处理");
    }
    // 其他方法省略
}
web.xml 配置(顺序决定执行顺序)
<!-- 先配置编码过滤器,再配置登录过滤器 -->
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>com.example.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
    <filter-name>loginFilter</filter-name>
    <filter-class>com.example.filter.LoginFilter</filter-class>
</filter-mapping>
<filter-mapping>
    <filter-name>loginFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
执行结果
编码过滤器:请求预处理
登录过滤器:请求预处理
Servlet处理请求
登录过滤器:响应后处理
编码过滤器:响应后处理

关键注意事项

  1. 顺序优先级:web.xml 中 <filter-mapping> 的顺序 > 注解方式的类名字母序
  2. 拦截中断:如果某个过滤器不调用 chain.doFilter(),后续过滤器和 Servlet 都不会执行
  3. 请求 / 响应对象传递:过滤器链中传递的是同一个 HttpServletRequestHttpServletResponse 对象,前序过滤器的修改会影响后续过滤器
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐