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 过滤器的生命周期与执行流程
生命周期阶段
- 初始化(init):当 Web 应用启动时,Servlet 容器(如 Tomcat)加载过滤器类,并调用
init()
方法初始化资源。 - 拦截请求(doFilter):每当匹配的请求到达时,容器调用
doFilter()
方法执行过滤逻辑。 - 销毁(destroy):Web 应用关闭时,容器调用
destroy()
方法释放资源。
执行流程比喻
假设过滤器是一个“门卫”,其工作流程如下:
- 门卫上岗:Web 服务器启动时,门卫(过滤器)被雇佣并分配职责(初始化)。
- 检查每一位访客:每当有人(请求)试图进入场馆(目标资源),门卫先检查其门票(预处理),再决定是否放行。
- 记录离开信息:访客离开时,门卫可能记录其离开时间(后处理)。
- 门卫下班:服务器关闭时,门卫结束工作并归还装备(销毁)。
如何实现一个简单的 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()
中捕获异常,防止过滤器崩溃导致请求中断。
实战案例:构建登录拦截过滤器
需求背景
假设我们有一个用户管理系统,要求:
- 访问
/admin/*
的 URL 必须已登录。 - 未登录用户自动跳转到
/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 开发者进阶的必经之路。通过本文的案例与代码示例,希望读者能够快速上手并灵活运用这一核心技术。