Java Web 过滤器与监听器
过滤器是运行在服务器端的拦截器,它可以在请求到达 Servlet 之前 “拦截” 请求,也可以在响应返回给客户端之前 “拦截” 响应,从而实现统一的请求处理、权限控制、编码过滤等功能。统一设置请求 / 响应的编码格式。拦截非法请求(如未登录用户访问受保护页面)。记录请求日志、统计接口访问次数。监听器是监听 Web 应用中 “事件”的组件,它可以感知这三个域对象的创建、销毁或属性变化,从而实现全局事
一、过滤器(Filter)
1. 过滤器概述
过滤器是运行在服务器端的拦截器,它可以在请求到达 Servlet 之前 “拦截” 请求,也可以在响应返回给客户端之前 “拦截” 响应,从而实现统一的请求处理、权限控制、编码过滤等功能。
典型应用场景:
- 统一设置请求 / 响应的编码格式。
- 拦截非法请求(如未登录用户访问受保护页面)。
- 记录请求日志、统计接口访问次数。
2. 过滤器入门代码
编写一个简单的编码过滤器,统一处理请求和响应的编码:
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
// @WebFilter 注解配置过滤器的拦截路径
@WebFilter("/*") // 拦截所有请求
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 过滤器初始化逻辑(仅执行一次)
System.out.println("EncodingFilter 初始化完成");
}
@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. 后处理:可对响应做额外操作(如添加响应头)
response.setHeader("X-Powered-By", "Java Web Filter");
}
@Override
public void destroy() {
// 过滤器销毁逻辑(仅执行一次)
System.out.println("EncodingFilter 销毁");
}
}
说明:
init:过滤器初始化时执行,用于加载配置、创建资源等。doFilter:每次请求被拦截时执行,是过滤器的核心方法。FilterChain.doFilter用于 “放行” 请求,若不调用则请求会被拦截。destroy:过滤器销毁时执行,用于释放资源。
3. 过滤器执行流程
过滤器的执行流程可概括为:
- 客户端发送请求到服务器。
- 过滤器拦截请求,执行
doFilter中的 “预处理” 逻辑。 - 调用
chain.doFilter放行请求,请求到达目标 Servlet(或下一个过滤器)。 - Servlet 处理请求并生成响应。
- 响应回到过滤器,执行
doFilter中的 “后处理” 逻辑。 - 响应最终返回给客户端。
4. 过滤器的拦截路径配置
过滤器通过@WebFilter的urlPatterns属性配置拦截路径,支持多种匹配方式:
| 配置方式 | 示例 | 说明 |
|---|---|---|
| 精确匹配 | @WebFilter("/user/login") |
仅拦截/user/login请求 |
| 目录匹配 | @WebFilter("/user/*") |
拦截/user下的所有子路径 |
| 后缀匹配 | @WebFilter("*.do") |
拦截所有以.do结尾的请求 |
| 拦截所有请求 | @WebFilter("/*") |
拦截所有请求 |
5. 多个过滤器的执行顺序
当多个过滤器拦截同一请求时,执行顺序由过滤器类名的字母顺序决定(若需自定义顺序,可在web.xml中配置<filter-mapping>的顺序)。
示例:若有FilterA和FilterB,类名FilterA字母序在前,则FilterA先执行,FilterB后执行;响应时则FilterB先处理,FilterA后处理(即 “先进后出”)。
二、监听器(Listener)
1. 监听器概述
监听器是监听 Web 应用中 “事件”的组件,它可以感知ServletContext、HttpSession、ServletRequest这三个域对象的创建、销毁或属性变化,从而实现全局事件处理、数据统计、资源初始化等功能。
根据监听的对象不同,监听器分为三类:
- ServletContext 监听器:监听应用上下文的创建、销毁和属性变化。
- HttpSession 监听器:监听会话(Session)的创建、销毁和属性变化。
- ServletRequest 监听器:监听请求的创建、销毁和属性变化。
2. ServletContext 监听器
ServletContext是 Web 应用的全局上下文,对应的监听器接口是ServletContextListener和ServletContextAttributeListener。
(1)ServletContextListener(监听上下文的创建和销毁)
示例:在应用启动时初始化数据库连接池,关闭时销毁连接池。
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class AppContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
// 应用启动时执行(服务器启动或应用部署时)
System.out.println("应用启动,初始化数据库连接池...");
// 此处编写初始化连接池的逻辑
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// 应用销毁时执行(服务器关闭或应用卸载时)
System.out.println("应用销毁,销毁数据库连接池...");
// 此处编写销毁连接池的逻辑
}
}
(2)ServletContextAttributeListener(监听上下文属性变化)
示例:监听ServletContext的属性新增、修改、删除。
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class AppContextAttrListener implements ServletContextAttributeListener {
@Override
public void attributeAdded(ServletContextAttributeEvent scae) {
System.out.println("ServletContext 添加属性:" + scae.getName() + " = " + scae.getValue());
}
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
System.out.println("ServletContext 删除属性:" + scae.getName());
}
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
System.out.println("ServletContext 修改属性:" + scae.getName() + " 旧值=" + scae.getValue());
}
}
3. HttpSession 监听器
HttpSession是用户会话的载体,对应的监听器接口是HttpSessionListener、HttpSessionAttributeListener等。
(1)HttpSessionListener(监听会话的创建和销毁)
示例:统计在线用户数量。
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class SessionCountListener implements HttpSessionListener {
private int onlineCount = 0;
@Override
public void sessionCreated(HttpSessionEvent se) {
onlineCount++;
se.getSession().getServletContext().setAttribute("onlineCount", onlineCount);
System.out.println("用户上线,在线人数:" + onlineCount);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
onlineCount--;
se.getSession().getServletContext().setAttribute("onlineCount", onlineCount);
System.out.println("用户下线,在线人数:" + onlineCount);
}
}
(2)HttpSessionAttributeListener(监听会话属性变化)
示例:监听HttpSession的属性新增、修改、删除。
import javax.servlet.http.HttpSessionAttributeEvent;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class SessionAttrListener implements HttpSessionAttributeListener {
@Override
public void attributeAdded(HttpSessionAttributeEvent se) {
System.out.println("Session 添加属性:" + se.getName() + " = " + se.getValue());
}
@Override
public void attributeRemoved(HttpSessionAttributeEvent se) {
System.out.println("Session 删除属性:" + se.getName());
}
@Override
public void attributeReplaced(HttpSessionAttributeEvent se) {
System.out.println("Session 修改属性:" + se.getName() + " 旧值=" + se.getValue());
}
}
4. ServletRequest 监听器
ServletRequest是单次请求的载体,对应的监听器接口是ServletRequestListener、ServletRequestAttributeListener等。
(1)ServletRequestListener(监听请求的创建和销毁)
示例:记录请求的创建和销毁时间。
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class RequestListener implements ServletRequestListener {
@Override
public void requestInitialized(ServletRequestEvent sre) {
sre.getServletRequest().setAttribute("requestStartTime", System.currentTimeMillis());
System.out.println("请求创建");
}
@Override
public void requestDestroyed(ServletRequestEvent sre) {
long startTime = (long) sre.getServletRequest().getAttribute("requestStartTime");
long cost = System.currentTimeMillis() - startTime;
System.out.println("请求销毁,处理耗时:" + cost + "ms");
}
}
三、过滤器与监听器的实战结合
案例:用户登录拦截与在线统计
需求:
- 未登录用户无法访问
/user/*下的受保护页面(过滤器实现)。 - 统计当前在线用户数量(监听器实现)。
1. 登录过滤器(LoginFilter)
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter("/user/*")
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
HttpSession session = req.getSession();
// 判断用户是否登录(假设登录后Session中存在"user"属性)
if (session.getAttribute("user") != null) {
chain.doFilter(request, response); // 已登录,放行
} else {
resp.sendRedirect(req.getContextPath() + "/login.jsp"); // 未登录,跳转到登录页
}
}
}
2. 在线用户统计监听器(OnlineUserListener)
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class OnlineUserListener 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);
}
}
3. 页面展示在线人数
在index.jsp中展示在线人数:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>在线统计</title>
</head>
<body>
当前在线人数:${applicationScope.onlineCount}
</body>
</html>
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)