【JavaWeb学习 | 第19篇】Filter过滤器

【JavaWeb学习 | 第19篇】Filter过滤器(过滤器)

在上一篇文章中,我们学习了 Servlet + JSP + JavaBeanMVC开发模式,代码结构已经清晰了很多。
但实际开发中还会遇到一些通用的、重复的处理逻辑,例如:

  • 统一字符编码(解决中文乱码)
  • 登录权限检查(未登录用户不能访问后台页面)
  • 敏感词过滤
  • 访问日志记录
  • 防止SQL注入、XSS攻击等

如果把这些逻辑写在每一个Servlet里,就会造成大量代码重复,违背“DRY”(Don’t Repeat Yourself)原则。

Filter(过滤器) 正是为了解决这类问题而生的!


一、什么是Filter?

Filter 是 Servlet规范中提供的一个接口,位于 javax.servlet 包下。
它可以在 请求到达Servlet之前响应返回浏览器之前 对请求和响应进行拦截和处理。

Filter的执行位置(非常重要):

浏览器 → Filter1 → Filter2 → ... → FilterN → Servlet(Controller) → JSP(View) → FilterN → ... → Filter1 → 浏览器

Filter可以有多个,它们按照配置顺序依次执行,形成过滤器链(Filter Chain)


二、Filter的核心作用

  • 预处理:请求到达Servlet之前做统一处理(编码、权限校验、日志等)
  • 后处理:响应返回浏览器之前做统一处理(压缩、添加水印等)
  • 拦截:不符合条件时直接阻止请求继续向下传递

三、Filter的开发步骤(超详细)

1. 编写Filter类(实现Filter接口)

// com.example.filter.EncodingFilter.java
package com.example.filter;

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

@WebFilter("/*")   // 使用注解配置,拦截所有请求
public class EncodingFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // Filter初始化时执行一次(类似Servlet的init)
        System.out.println("EncodingFilter 初始化...");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {

        // ===== 前置处理(请求进来时)=====
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        System.out.println("EncodingFilter 前置处理完成");

        // ===== 关键:放行请求,让其继续往下走(到达下一个Filter或Servlet)=====
        chain.doFilter(request, response);

        // ===== 后置处理(响应返回时)=====
        System.out.println("EncodingFilter 后置处理完成");
    }

    @Override
    public void destroy() {
        // Filter被销毁时执行一次(服务器关闭时)
        System.out.println("EncodingFilter 销毁...");
    }
}

2. 配置Filter(两种方式)

方式一:注解配置(推荐,Servlet 3.0+)

@WebFilter(
    urlPatterns = {"/*"},           // 拦截路径
    dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD}
)
public class EncodingFilter implements Filter { ... }

方式二: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示例

示例1:登录权限过滤器(最实用!)

@WebFilter("/*")
public class LoginFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        // 1. 获取当前请求路径
        String uri = request.getRequestURI();

        // 2. 放行登录相关页面和资源
        if (uri.contains("/login") || uri.contains("/register") 
            || uri.endsWith(".css") || uri.endsWith(".js") 
            || uri.endsWith(".png") || uri.endsWith(".jpg")) {

            chain.doFilter(request, response);
            return;
        }

        // 3. 检查session中是否有用户
        Object user = request.getSession().getAttribute("user");
        if (user != null) {
            // 已登录,放行
            chain.doFilter(request, response);
        } else {
            // 未登录,跳转到登录页
            request.setAttribute("errorMsg", "请先登录!");
            request.getRequestDispatcher("/login.jsp").forward(request, response);
        }
    }
}

示例2:XSS攻击简单过滤(字符替换)

public class XssFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        // 包装request,增强getParameter方法进行XSS过滤
        XssHttpServletRequestWrapper wrapper = new XssHttpServletRequestWrapper((HttpServletRequest) request);
        chain.doFilter(wrapper, response);
    }
}

(实际生产中推荐使用成熟的XSS过滤框架,如OWASP Java Encoder)


五、Filter的重要知识点

  • 多个Filter执行顺序
  • 注解方式:按照类名首字母顺序执行(不推荐依赖此顺序)
  • web.xml方式:按照<filter-mapping>在web.xml中出现的顺序执行(推荐)
  • FilterChain.doFilter():必须调用!否则请求会被拦截,无法到达Servlet。
  • Filter的生命周期
  1. 服务器启动时 → init()
  2. 每次请求 → doFilter()
  3. 服务器关闭时 → destroy()
  • Filter可以拦截:Request、Forward、Include、Error 等多种分发器类型。

六、实际开发建议

  1. 通用功能(编码、日志、权限)优先考虑用Filter实现。
  2. 权限控制通常结合Session + Filter + MVC一起使用。
  3. 不要在Filter中写复杂业务逻辑,Filter只做“通用预处理/后处理”。
  4. Filter执行顺序很重要,敏感操作的过滤器要放在前面。
  5. 现代项目中,Spring Boot常用 Interceptor(拦截器)和 HandlerExceptionResolver 替代部分Filter功能,但Filter仍是JavaWeb基础必须掌握的内容。

七、练习建议(动手实践很重要!)

  1. 实现全局字符编码过滤器(解决所有中文乱码问题)。
  2. 编写登录权限过滤器,保护后台管理页面(/admin/*)。
  3. 实现一个简单的访问日志过滤器,记录每次请求的IP、URI、时间。
  4. 尝试配置多个Filter,观察执行顺序(一个编码过滤器 + 一个登录过滤器)。

完成这些练习后,你会明显感觉到项目代码变得更加优雅和专业!


系列文章导航(持续更新中):

  • 第17篇:JSP内置对象
  • 第18篇:Servlet与MVC
  • 第19篇:Filter过滤器(本文)
  • 第20篇:Listener监听器(在线人数统计、Session监听等)

下一篇文章预告:我们将学习 Listener(监听器),它能监听ServletContext、HttpSession、ServletRequest的创建、销毁和属性变化,是实现“在线人数统计”、“实时聊天”等功能的核心技术。

有任何疑问(比如多个Filter的顺序如何精确控制、或XssFilter如何实现),欢迎在评论区留言,我会及时补充详细代码!

继续加油!你正在从“会用Servlet+JSP”逐步走向“能搭建完整JavaWeb项目”的阶段!🔥

下一篇文章见~ 🚀

文章已创建 5295

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部