一、什么是过滤器和监听器?—— 生活中的类比

想象你经营着一家在线书店(没错,还是我们的老例子!),为了保证书店正常运营,你需要两种关键角色:

  • 过滤器(Filter):像书店门口的 保安,所有顾客(请求)进入前必须经过检查 —— 没带口罩?禁止入内!带了危险品?拦下!只有符合条件的人才能进店。
  • 监听器(Listener):像书店里的 监控系统,默默记录顾客进出(会话创建 / 销毁)、货架商品变动(属性变更)等事件,一旦发生异常就会触发警报。

在 Java Web 中,过滤器负责拦截请求 / 响应,监听器负责监听 Web 应用事件,两者配合让 Web 应用更安全、可控。

二、过滤器(Filter)—— 请求的 “安检员”

1. 核心概念:过滤器能做什么?

过滤器就像 “请求安检员”,在请求到达 Servlet 之前、响应返回客户端之前 “拦截” 并处理:

  • 登录验证:未登录用户禁止访问订单页面
  • 统一编码:把所有请求的编码设为 UTF-8,避免乱码
  • 敏感词过滤:把评论中的 “垃圾话” 替换成 ***
  • 日志记录:记录谁访问了哪个页面、什么时间访问

2. 过滤器的 “一生”:生命周期

过滤器的工作流程就像保安的一天:

阶段 方法 类比场景 特点
初始化 init(FilterConfig) 保安上班,领取装备(配置) 服务器启动时执行,仅 1 次
工作中 doFilter(...) 检查每个进出的人(请求) 每次请求都执行
下班 destroy() 保安下班,归还装备 服务器关闭时执行,仅 1 次

3. 动手写一个登录验证过滤器

假设我们的在线书店需要验证用户是否登录才能访问 /order 页面,过滤器代码如下:

// 登录验证过滤器
@WebFilter("/order/*") // 拦截所有以/order开头的请求
public class LoginFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) 
            throws IOException, ServletException {
        // 1. 转换为HTTP请求/响应(获取会话)
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        
        // 2. 检查Session中是否有登录用户
        HttpSession session = request.getSession();
        if (session.getAttribute("loginUser") == null) {
            // 未登录,重定向到登录页
            response.sendRedirect("/login.jsp");
            return;
        }
        
        // 3. 已登录,放行请求(让请求继续走向Servlet)
        chain.doFilter(request, response); 
    }

    // init和destroy方法默认空实现,可省略
}

关键点

  • @WebFilter("/order/*"):指定拦截的 URL(/* 拦截所有请求)
  • chain.doFilter(...):必须调用,否则请求会被 “拦死”(就像保安不让进也不让出)

三、监听器(Listener)—— 应用的 “监控摄像头”

1. 核心概念:监听器监听什么?

监听器就像 “监控摄像头”,默默盯着 Web 应用中的三大域对象(请求、会话、应用)的一举一动:

  • ServletContextListener:监控应用启动 / 销毁(如加载全局配置)
  • HttpSessionListener:监控用户会话创建 / 销毁(如统计在线人数)
  • ServletRequestListener:监控请求创建 / 销毁(如记录访问日志)

2. 最常用的监听器:统计在线人数

以在线书店为例,用 HttpSessionListener 统计当前在线用户数:

// 在线人数监听器
@WebListener
public class OnlineCountListener implements HttpSessionListener {
    private int onlineCount = 0; // 在线人数

    // 会话创建时(用户登录/首次访问)
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        onlineCount++;
        // 把在线人数存到应用域(所有用户共享)
        se.getSession().getServletContext().setAttribute("onlineCount", onlineCount);
    }

    // 会话销毁时(用户退出/超时)
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        onlineCount--;
        se.getSession().getServletContext().setAttribute("onlineCount", onlineCount);
    }
}

在 JSP 中显示在线人数

<!-- 在线书店首页 -->
当前在线人数:${applicationScope.onlineCount}人

为什么能统计?

  • 用户打开浏览器访问网站 → 创建 Session → sessionCreated 触发 → 人数 + 1
  • 用户关闭浏览器 / 超时 → Session 销毁 → sessionDestroyed 触发 → 人数 - 1

四、过滤器 vs 监听器:怎么选?

功能 过滤器(Filter) 监听器(Listener)
核心作用 拦截请求 / 响应,修改内容 监听事件,被动触发操作
使用场景 登录验证、编码处理、敏感词过滤 统计在线人数、加载全局配置
触发方式 主动拦截请求 被动监听事件(如 Session 创建)

一句话总结:需要 “拦请求” 用过滤器,需要 “盯事件” 用监听器。

五、小白避坑指南

  1. 过滤器别忘了放行!
    如果在 doFilter 中忘记调用 chain.doFilter(request, response),请求会被永久拦截(用户永远看不到页面)。

  2. 监听器注册要正确

    • 注解方式:用 @WebListener 标注类
    • XML 方式:在 web.xml 中配置 <listener> 标签
      两种方式选一种,不要重复注册。
  3. 过滤器链的执行顺序
    多个过滤器时,注解配置按类名字母顺序执行(如 AFilter 比 BFilter 先执行),XML 配置按 <filter-mapping> 顺序执行

六、总结:过滤器和监听器的价值

  • 过滤器:Web 应用的 “守门人”,帮你挡掉非法请求、统一处理通用逻辑(如编码)。
  • 监听器:Web 应用的 “千里眼”,帮你监控应用状态、统计关键数据(如在线人数)。

下一篇我们将学习 “会话管理”,敬请期待

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐