Filter_过滤器
·
文章目录
过滤器概述
1. 是什么?
Filter 是 Servlet 规范 定义的接口(javax.servlet.Filter),本质是一个 “拦截器” 。它的作用域是 请求到达 Servlet 之前 和 响应返回浏览器之前。
2.原理是什么?
基于责任链模式实现:客户端请求 → 过滤器 1 → 过滤器 2 → … → Servlet → 过滤器 2 → 过滤器 1 → 客户端响应。过滤器可以选择:
- 放行请求:
chain.doFilter(request, response) - 拦截请求:不调用
doFilter,直接跳转 / 返回响应
过滤器的使用
开发步骤(传统 web.xml 方式)
- 创建过滤器类:实现
javax.servlet.Filter接口 - 重写核心方法:
init()、doFilter()、destroy() - 配置过滤器:在
web.xml中配置拦截路径
完整代码示例
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
// 传统方式用web.xml配置
public class EncodingFilter implements Filter {
// 初始化方法:过滤器创建时执行1次
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 可以获取web.xml中配置的初始化参数
String encoding = filterConfig.getInitParameter("encoding");
System.out.println("编码过滤器初始化,编码:" + encoding);
}
// 核心拦截方法:每次请求被拦截时执行
@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. 响应后处理:可以在这里对响应做修改
System.out.println("响应已返回客户端");
}
// 销毁方法:服务器关闭/过滤器销毁时执行1次
@Override
public void destroy() {
System.out.println("编码过滤器销毁");
}
}
配置方式(两种主流写法)
1. 注解方式(推荐)
核心注解:@WebFilter
// 拦截所有以 /demo8/ 开头的请求
@WebFilter(urlPatterns = "/demo8/*")
public class LoggingFilter implements Filter {}
常用属性
| 属性 | 说明 |
|---|---|
filterName | 过滤器名称(可选,默认类名) |
urlPatterns/value | 拦截路径(数组,支持多个) |
initParams | 初始化参数(@WebInitParam数组) |
dispatcherTypes | 拦截的请求类型(默认REQUEST) |
2. web.xml 配置方式(可控顺序)
web.xml 配置示例
<!-- 注册过滤器 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>com.example.filter.EncodingFilter</filter-class>
<!-- 初始化参数 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<!-- 配置拦截路径 -->
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<!-- 拦截所有请求 -->
<url-pattern>/*</url-pattern>
<!-- 也可以拦截指定Servlet -->
<!-- <servlet-name>MyServlet</servlet-name> -->
</filter-mapping>
拦截路径配置规则
| 配置方式 | 示例 | 说明 |
|---|---|---|
| 精确匹配 | /user/login | 仅拦截/user/login路径的请求 |
| 目录匹配 | /user/* | 拦截/user/下所有资源 |
| 后缀匹配 | *.do | 拦截所有以.do结尾的请求 |
| 全匹配 | /* | 拦截所有请求(最常用) |
3. 注解 vs web.xml 对比
| 特性 | 注解方式 | web.xml 方式 |
|---|---|---|
| 配置位置 | 过滤器类上 | web.xml 文件 |
| 开发效率 | 高,无需修改配置文件 | 低,需手动配置 |
| 顺序控制 | 按类名字母序,不灵活 | 按<filter-mapping>顺序,灵活 |
| 适用场景 | 小型项目、快速开发 | 大型项目、需要统一管理配置 |
完整代码示例
/**
* 日志过滤器 记录请求的历史 将日志打印到控制台
*
* 1 实现Filter接口
* 2 重写过滤方法
* 3 配置过滤器
* 在web.xml中配置
* 注释
*/
public class LoggingFilter implements Filter {
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
过滤请求的和响应的方法
1 请求到达目标资源之前,先经过该方法
2 该方法有能力控制请求是否继续向后到达目标资源 可以在该方法内直接向客户端做响应处理
3 请求到达目标资源后,响应之前,还会经过该方法
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
/**
* 1 请求到达目标资源之前的功能代码
* 判断是否登录
* 校验权限是否满足
* ...
* 2 放行代码
* 3 响应之前 HttpServletResponse 转换为响应报文之前 的功能代码
*
*/
// 请求到达目标资源之前的代码
//System.out.println("LoggingFilter doFilter");
//放行
//filterChain.doFilter(servletRequest,servletResponse);
//响应之前的功能代码
//System.out.println("LoggingFilter doFilter end");
//-----------------------------------------------------------
//参数父转子
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//请求到达目标资源之前 打印日志
String requestURI = request.getRequestURI();
String dateTime = dateFormat.format(new Date());
String beforeLoggin = requestURI+"在"+dateTime+"访问了服务器";
System.out.println(beforeLoggin);
long t1 = System.currentTimeMillis();
//放行
filterChain.doFilter(servletRequest,servletResponse);
//响应之前的功能代码 ***资源在**时间的请求耗时 毫秒
long t2 = System.currentTimeMillis();
String afterLoggin = requestURI+"资源在"+dateTime+"的请求耗时:"+(t2-t1)+"毫秒";
System.out.println(afterLoggin);
}
}
//------------------------------------------------------------------------------------------------------------------------------------------
@WebServlet(urlPatterns = "/servlet1")
public class Servlet1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("servlet1");
resp.getWriter().write("servlet1 message");
}
}
过滤器的生命周期
过滤器的生命周期由服务器管理,分为 3 个阶段:
-
创建与初始化
- 时机:服务器启动时(或第一次请求时,取决于服务器配置)
- 执行方法:
init(FilterConfig filterConfig) - 执行次数:仅执行 1 次
- 作用:完成初始化操作,比如读取配置参数、创建资源
-
拦截处理
- 时机:每次请求匹配拦截路径时
- 执行方法:
doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - 执行次数:每次请求都执行
- 核心:通过
chain.doFilter()控制是否放行
-
销毁
- 时机:服务器正常关闭 / 项目卸载时
- 执行方法:
destroy() - 执行次数:仅执行 1 次
- 作用:释放资源,比如关闭数据库连接
过滤");
public class LifeCycleFilter implements Filter {
/**
1 构造 构造器 项目启动 1次
2 初始化 init 构造完毕 1次
3 过滤 doFilter 每次请求 多次
4 销毁 destroy 服务器关闭 1次
*/
public LifeCycleFilter(){
System.out.println("构造器");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("初始化");
System.out.println(filterConfig.getInitParameter("dateTimePattern"));
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("过滤");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("销毁");
}
}
过滤器链
核心定义
过滤器链(FilterChain) :当多个过滤器同时拦截同一个请求时,这些过滤器会形成一个链式结构,按照配置顺序依次执行。
执行顺序
- 请求方向:按照过滤器配置的顺序依次执行(web.xml 中
<filter-mapping>的顺序,注解方式按类名字母序) - 响应方向:按照过滤器配置的逆序依次执行
- 示例:过滤器 A → 过滤器 B → Servlet → 过滤器 B → 过滤器 A
代码示例(两个过滤器)
过滤器 1:登录校验过滤器
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("登录过滤器:请求预处理");
// 校验登录状态
HttpServletRequest req = (HttpServletRequest) request;
Object user = req.getSession().getAttribute("loginUser");
if (user == null) {
// 未登录,拦截跳转
response.getWriter().write("请先登录!");
return;
}
// 放行
chain.doFilter(request, response);
System.out.println("登录过滤器:响应后处理");
}
// 其他方法省略
}
过滤器 2:编码过滤器
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("编码过滤器:请求预处理");
request.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
System.out.println("编码过滤器:响应后处理");
}
// 其他方法省略
}
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>
<filter-name>loginFilter</filter-name>
<filter-class>com.example.filter.LoginFilter</filter-class>
</filter-mapping>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
执行结果
编码过滤器:请求预处理
登录过滤器:请求预处理
Servlet处理请求
登录过滤器:响应后处理
编码过滤器:响应后处理
关键注意事项
- 顺序优先级:web.xml 中
<filter-mapping>的顺序 > 注解方式的类名字母序 - 拦截中断:如果某个过滤器不调用
chain.doFilter(),后续过滤器和 Servlet 都不会执行 - 请求 / 响应对象传递:过滤器链中传递的是同一个
HttpServletRequest和HttpServletResponse对象,前序过滤器的修改会影响后续过滤器
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)