JSP 过滤器(一文讲透)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

从安检通道到程序逻辑:理解过滤器的比喻

想象你进入一个大型演唱会场馆,入口处有安检人员检查票务信息和禁止携带物品。这个安检流程就像 JSP 过滤器(JSP Filter)在程序中的作用——它会在请求到达目标资源之前,对请求进行预处理或后处理。无论是验证用户身份、记录日志还是修改响应内容,过滤器都能像安检人员一样,对每一条请求进行“检查”和“处理”。

JSP 过滤器是 Java Web 开发中的一个重要组件,它基于 Servlet 规范(Servlet API 的一部分),能够拦截对资源的访问请求。这种拦截机制既可以在请求到达 Servlet 或 JSP 页面之前执行(预处理),也可以在响应返回客户端之前执行(后处理)。


JSP 过滤器的核心功能与典型场景

1. 功能特性

  • 请求预处理:在目标资源处理请求前,执行身份验证、参数校验、日志记录等操作。
  • 响应后处理:修改响应内容(如压缩、加密)、添加统一的 HTTP 头信息等。
  • 动态路由控制:根据特定条件重定向请求,例如未登录用户访问私密页面时跳转到登录页。

2. 典型应用场景

场景类型具体案例
安全性控制检查用户登录状态,拦截非法请求
性能优化压缩响应内容以减少传输数据量
日志与监控记录请求时间、URL、响应状态码等
内容适配根据客户端设备类型返回不同格式

JSP 过滤器的生命周期与执行流程

生命周期阶段

  1. 初始化(init):当 Web 应用启动时,Servlet 容器(如 Tomcat)加载过滤器类,并调用 init() 方法初始化资源。
  2. 拦截请求(doFilter):每当匹配的请求到达时,容器调用 doFilter() 方法执行过滤逻辑。
  3. 销毁(destroy):Web 应用关闭时,容器调用 destroy() 方法释放资源。

执行流程比喻

假设过滤器是一个“门卫”,其工作流程如下:

  1. 门卫上岗:Web 服务器启动时,门卫(过滤器)被雇佣并分配职责(初始化)。
  2. 检查每一位访客:每当有人(请求)试图进入场馆(目标资源),门卫先检查其门票(预处理),再决定是否放行。
  3. 记录离开信息:访客离开时,门卫可能记录其离开时间(后处理)。
  4. 门卫下班:服务器关闭时,门卫结束工作并归还装备(销毁)。

如何实现一个简单的 JSP 过滤器

步骤 1:编写过滤器类

需要继承 javax.servlet.Filter 接口,并实现其三个抽象方法:

import javax.servlet.*;  
import javax.servlet.http.HttpServletRequest;  
import java.io.IOException;  

public class AuthenticationFilter implements Filter {  
    @Override  
    public void init(FilterConfig filterConfig) throws ServletException {  
        // 初始化资源(如读取配置文件)  
        System.out.println("过滤器已初始化");  
    }  

    @Override  
    public void doFilter(ServletRequest request,  
                        ServletResponse response,  
                        FilterChain chain)  
                        throws IOException, ServletException {  
        // 1. 预处理:检查用户是否登录  
        HttpServletRequest httpRequest = (HttpServletRequest) request;  
        String username = (String) httpRequest.getSession().getAttribute("user");  

        if (username == null) {  
            // 未登录则重定向到登录页面  
            ((HttpServletResponse) response).sendRedirect("/login.jsp");  
            return;  
        }  

        // 2. 放行请求,继续后续处理  
        chain.doFilter(request, response);  

        // 3. 后处理:记录访问日志  
        System.out.println("用户 " + username + " 访问了 " + httpRequest.getRequestURI());  
    }  

    @Override  
    public void destroy() {  
        // 释放资源  
        System.out.println("过滤器已销毁");  
    }  
}  

步骤 2:配置过滤器

在项目的 web.xml 文件中声明过滤器,并指定其拦截的 URL 模式:

<filter>  
    <filter-name>AuthenticationFilter</filter-name>  
    <filter-class>com.example.AuthenticationFilter</filter-class>  
</filter>  

<filter-mapping>  
    <filter-name>AuthenticationFilter</filter-name>  
    <url-pattern>/secure/*</url-pattern>  <!-- 拦截所有 /secure/ 开头的请求 -->  
</filter-mapping>  

过滤器的高级用法与最佳实践

1. 过滤器链:组合多个过滤器

可以为同一请求配置多个过滤器,形成“过滤器链”。例如:

<filter-mapping>  
    <filter-name>LoggingFilter</filter-name>  
    <url-pattern>/*</url-pattern>  
</filter-mapping>  

<filter-mapping>  
    <filter-name>CompressionFilter</filter-name>  
    <url-pattern>/*</url-pattern>  
</filter-mapping>  

每个过滤器的 doFilter() 方法都会依次执行,形成类似“安检流程”的串联处理。

2. 使用注解简化配置(Servlet 3.0+)

通过 @WebFilter 注解可直接在代码中声明过滤器,无需 web.xml 配置:

import javax.servlet.annotation.WebFilter;  

@WebFilter("/secure/*")  
public class AnnotationBasedFilter implements Filter {  
    // 实现与之前相同  
}  

3. 性能优化与注意事项

  • 避免过度拦截:过滤器会增加请求处理时间,需合理选择 URL 模式。
  • 线程安全:过滤器实例是单例的,应避免在成员变量中存储请求相关数据。
  • 错误处理:在 doFilter() 中捕获异常,防止过滤器崩溃导致请求中断。

实战案例:构建登录拦截过滤器

需求背景

假设我们有一个用户管理系统,要求:

  1. 访问 /admin/* 的 URL 必须已登录。
  2. 未登录用户自动跳转到 /login.jsp

实现步骤

1. 创建过滤器类 LoginCheckFilter

public class LoginCheckFilter implements Filter {  
    @Override  
    public void doFilter(ServletRequest request,  
                        ServletResponse response,  
                        FilterChain chain)  
                        throws IOException, ServletException {  
        HttpServletRequest httpRequest = (HttpServletRequest) request;  
        HttpSession session = httpRequest.getSession(false);  

        if (session == null || session.getAttribute("loggedInUser") == null) {  
            // 未登录,重定向到登录页  
            HttpServletResponse httpResponse = (HttpServletResponse) response;  
            httpResponse.sendRedirect("/login.jsp");  
            return;  
        }  

        // 放行请求  
        chain.doFilter(request, response);  
    }  
    // 省略 init 和 destroy 方法(可留空)  
}  

2. 配置过滤器

web.xml 中添加:

<filter-mapping>  
    <filter-name>LoginCheckFilter</filter-name>  
    <url-pattern>/admin/*</url-pattern>  
</filter-mapping>  

验证效果

  • 当用户访问 /admin/dashboard.jsp 且未登录时,会自动跳转到登录页面。
  • 登录成功后(设置 session.setAttribute("loggedInUser", username)),可正常访问受保护的页面。

常见问题与解决方案

Q1:过滤器如何区分 GET 和 POST 请求?

可以通过 HttpServletRequest 的方法判断:

if (httpRequest.getMethod().equals("POST")) {  
    // 执行特定逻辑  
}  

Q2:如何让过滤器忽略某些静态资源(如图片、CSS)?

web.xml 中排除特定路径:

<url-pattern>/*</url-pattern>  
<dispatcher>INCLUDE</dispatcher>  
<dispatcher>FORWARD</dispatcher>  
<!-- 排除静态资源 -->  
<init-param>  
    <param-name>excluded-urls</param-name>  
    <param-value>\.(css|js|jpg|png)$</param-value>  
</init-param>  

Q3:过滤器能否修改请求参数?

可以通过包装 ServletRequest 对象实现:

ServletRequestWrapper wrappedRequest = new CustomRequestWrapper(request);  
chain.doFilter(wrappedRequest, response);  

结论:JSP 过滤器的实践价值与未来展望

JSP 过滤器是 Java Web 开发中不可或缺的工具,它通过统一的拦截机制,帮助开发者高效实现安全控制、性能优化等需求。无论是保护敏感接口、记录系统日志,还是动态修改响应内容,过滤器都能以简洁的代码实现复杂功能。

随着 Web 应用的复杂度增加,过滤器的链式组合、注解配置等特性将进一步简化开发流程。未来,结合现代框架(如 Spring Security)的高级功能,开发者可以更灵活地扩展过滤器的能力,应对更复杂的业务场景。

掌握 JSP 过滤器的设计与实现,是每一位 Java Web 开发者进阶的必经之路。通过本文的案例与代码示例,希望读者能够快速上手并灵活运用这一核心技术。

最新发布