mthoutai

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Filter 详解

前言

在 Java Web 开发中,你是否遇到过这样的需求:

  • 用户必须登录才能访问订单页面
  • 所有请求统一设置 UTF-8 编码避免乱码
  • 记录每个请求的访问日志用于审计
  • 防止跨站脚本攻击(XSS)
  • 响应数据压缩以提升性能

这些看似分散的功能,其实都可以通过一个强大的机制统一实现:Filter(过滤器)

Filter 就像网站的“保安”或“安检门”,它在请求到达业务逻辑之前、响应返回客户端之前,进行拦截、检查、处理,是构建安全、高效 Web 应用的基石。

一、Filter概述

Filter(过滤器)是 Java Servlet 规范中提供的一种组件,用于在请求到达目标资源(如 Servlet、JSP 等)之前或响应返回客户端之前,对请求和响应进行拦截和处理。

过滤器,顾名思义就是对事物进行过滤的,在Web中的过滤器,当然就是对请求进行过滤,我们使用过滤器,就可以对请求进行拦截,然后做相应的处理,实现许多特殊功能。如登录控制,权限管理,过滤敏感词汇等.

类比理解:就像“安检门”一样,所有进入 Web 应用的请求都必须先经过 Filter 的检查和处理。

  • 所属包:jakarta.servlet.Filter(Servlet 5.0+ 使用 jakarta,旧版本为 javax.servlet
  • 作用范围:可对指定 URL 路径、Servlet 或整个应用进行统一控制。
  • 特点:
    • 不生成响应内容
    • 可以决定是否放行请求
    • 支持链式调用(多个 Filter 组成过滤器链)

核心概念

过滤器的核心功能是拦截请求和响应,并在拦截过程中执行特定的逻辑。它通过 doFilter() 方法实现对请求和响应的处理,并通过 FilterChain 对象调用下一个过滤器或目标资源。

二、Filter 的核心作用

作用典型场景
权限控制登录校验、角色权限验证
编码处理统一设置请求/响应字符编码(UTF-8)
日志记录记录请求路径、IP、耗时等
安全防护XSS 过滤、CSRF 防护、IP 黑名单
性能优化响应压缩(GZIP)、缓存控制
请求改造修改请求头、包装 Request
响应改造修改响应头、包装 Response

三、过滤器原理

3.1 请求在Tomcat中的执行流程

在这里插入图片描述

看过Tomcat详解的都知道,

Container处理请求是使用Pipeline-Valve管道来处理的!

Pipeline-Valve是责任链模式

Pipeline管道分为First首节点和Basic基础节点,基础节点用于调用下一层容器,处于当前容器职责链的末尾,最后执行

也就是每层容器中职责链的调用顺序从First开始Basic结束

我们知道Container包含四个子容器,而这四个子容器对应的BaseValve分别在:StandardEngineValve、StandardHostValve、StandardContextValve、StandardWrapperValve。

也就是说:

1)Connector在接收到请求后会首先调用最顶层容器的Pipeline来处理,这里的最顶层容器的Pipeline就是EnginePipeline(Engine的管道);

(2)在Engine的管道中依次会执行EngineValve1、EngineValve2等等,最后会执行StandardEngineValve,在StandardEngineValve中会调用Host管道,然后再依次执行Host的HostValve1、HostValve2等,最后在执行StandardHostValve,然后再依次调用Context的管道和Wrapper的管道,最后执行到StandardWrapperValve。

(3)当执行到StandardWrapperValve的时候,会在StandardWrapperValve中调用ApplicationFilterFactory.createFilterChain(request, wrapper, servlet)方法创建FilterChain,并调用其doFilter方法来处理请求,这个FilterChain包含着我们配置的与请求相匹配的Filter和Servlet,其doFilter方法会依次调用所有的Filter的doFilter方法和Servlet的service方法,这样请求就得到了处理!

StandardWrapperValue源码中的invoke()方法佐证:

public void invoke(Request request, Response response) throws IOException, ServletException {
//省略...
// Create the filter chain for this request
ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
//省略...
}

(4)当所有的Pipeline-Value都执行完之后,并且处理完了具体的请求,这个时候就可以将返回的结果交给Connector了,Connector在通过Socket的方式将结果返回给客户端。

FilterChain 是一个责任链,它从第一个 Filter 开始执行,经过所有 Filter 的 doFilter(),最终“放行”到 Servlet.service() 方法,而 Servlet.service() 是这个链的最后一个节点。

在这里插入图片描述

  • 请求阶段:从前向后依次执行每个 Filter 的前置逻辑。
  • 调用 chain.doFilter() 后,继续向下传递。
  • 到达目标资源(如 Servlet)并处理完成后,响应沿原路返回,执行各 Filter 的后置逻辑。

3.2 过滤器(Filter)接口

public interface Filter {
default void init(FilterConfig filterConfig) throws ServletException {
}
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
default void destroy() {
}
}
  • init():获取配置信息,初始化资源。
  • doFilter():核心业务逻辑,决定是否放行。
  • destroy():释放资源,如关闭数据库连接等。

我们通过官方提供的过滤器可以看出过滤器(Filter)使用起来还是比较简单的,下面我们就来学习如何使用过滤器(Filter)

3.3 创建过滤器(Filter)

创建Filter,只需要继承Filter接口就行。

  1. 创建实现类实现 jakarta.servlet.Filter 接口;
  2. 重写 doFilter() 方法,编写拦截逻辑;
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//放行
filterChain.doFilter()
}
}

如果某个 Filter 中没有调用 filterChain.doFilter(),则请求被“拦截”,后续资源不会被执行。

Filter接口有3个方法,但是只有一个方法没有实现,我们只需要实现这个方法就行。我们可以发现,我们实现了一个doFilter方法,这个方法就是我们写过滤代码的地方,具体逻辑就是和上面介绍的过滤器原理一样的。

3.4 使用过滤器(Filter)

如何使用过滤器,使用它我们就要对它进行配置

配置过滤器主要有两种方式

方式一:注解方式

@WebFilter("/ServletA")          // 拦截指定路径
// @WebFilter("*.html")         // 拦截所有 .html 文件
// @WebFilter("/*")             // 拦截所有请求
public class MyFilter implements Filter { ... }

方式二:web.xml 配置

<!-- 注册过滤器 -->
  <filter>
  <filter-name>MyFilter</filter-name>
  <filter-class>com.zzz.filter.MyFilter</filter-class>
  </filter>
  <!-- 映射过滤规则 -->
    <filter-mapping>
    <filter-name>LoggingFilter</filter-name>
      <!-- 拦截方式任选其一或组合 -->
      <!-- <url-pattern>/*</url-pattern> -->
      <servlet-name>ServletA</servlet-name>
      </filter-mapping>

当我们的Servlet注册和映射时

比如

@WebServlet(value = "/ServletA",name = "ServletA")

或者

<servlet>
<servlet-name>ServletA</servlet-name>
<servlet-class>com.zzz.servlet.ServletA</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletA</servlet-name>
<url-pattern>/ServletA</url-pattern>
</servlet-mapping>

我们在配置过滤器的映射过滤规则时,可以使用servlet-name标签

<!-- 映射过滤规则 -->
  <filter-mapping>
  <filter-name>LoggingFilter</filter-name>
  <servlet-name>ServletA</servlet-name>
  </filter-mapping>

或者

@WebFilter(servletNames = "ServletA")

测试

//通过注解的方式进行配置
@WebFilter("/ServletA")
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + "   MyFilter开始执行");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + "   MyFilter执行完毕");
}
}
@WebServlet(value = "/ServletA",name = "ServletA")
public class ServletA extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + "   ServletA开始执行");
try {
Thread thread = new Thread();
thread.sleep(5000);
}catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + "   ServletA执行完毕");
}
}

我们访问http://localhost:8080/JavaWeb_05/ServletA

在这里插入图片描述

可以看到,我们的请求经过过滤器时执行了 MyFilter开始执行,随后执行filterChain.doFilter(servletRequest, servletResponse),进行放行,执行ServletA.service()方法,执行完毕后进行响应,响应的时候会再次经过过滤器的过滤,执行了 MyFilter执行完毕。

此过程验证了我们上面讲述的请求在Tomcat中是如何经过Filter的。

3.5 Filter 的生命周期(由 Servlet 容器管理)

Filter 的生命周期由 Web 容器(如 Tomcat)控制,分为四个阶段:

阶段方法调用时机调用次数
实例化构造函数Tomcat 容器在 Context 初始化阶段1 次
初始化init(FilterConfig config)Tomcat 容器在 Context 初始化阶段1 次
过滤处理doFilter(ServletRequest, ServletResponse, FilterChain)每次请求匹配时N 次
销毁destroy()Tomcat 容器关闭时1 次

类比:就像保安的上班流程:打卡(构造)→ 接收任务(init)→ 检查人员(doFilter)→ 下班(destroy)

测试

public class LifecycleFilter implements Filter {
public LifecycleFilter() {
System.out.println("LifecycleFilter 构造方法");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LifecycleFilter init方法");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("LifecycleFilter doFilter方法");
}
@Override
public void destroy() {
System.out.println("LifecycleFilter destroy方法");
}
@WebServlet(value = "/ServletA",name = "ServletA")
public class ServletA extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("ServletA开始执行");
try{
Thread thread = new Thread();
thread.sleep(5000);
} catch (Exception e) {
throw new RuntimeException(e);
}
System.out.println("ServletA执行完毕");
}
}
<filter>
<filter-name>LifecycleFilter</filter-name>
<filter-class>com.zzz.filter.LifecycleFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LifecycleFilter</filter-name>
<url-pattern>/ServletA</url-pattern>
</filter-mapping>

Tomcat启动时,在 Context 初始化阶段,先执行构造函数,在执行init方法

在这里插入图片描述

每次请求匹配时

在这里插入图片描述

Tomcat 容器关闭时
在这里插入图片描述

经过测试,我们基本可以理解Filter的生命周期。

3.6 FilterConfig和FilterChain

FilterConfigFilterChain这2个对象是由服务器(Tomcat)在创建和调用Filter对象时所传入的,这2个对象十分有用,FilterConfig对象可以读取我们配置的初始参数,FilterChain可以实现多个Filter之间的连接。

在 Servlet 规范中,FilterConfigFilterChain 是过滤器(Filter)机制中两个核心的接口对象,均由服务器(如 Tomcat)在运行时自动创建并传入,开发者无需手动实例化。它们分别承担配置管理执行流程控制的职责。

3.6.1 FilterConfig

FilterConfig 是容器在初始化 Filter 时传入的配置对象,用于:

  • 获取 web.xml@WebFilter 注解中配置的初始化参数(init-param
  • 获取 ServletContext 对象,进而访问全局上下文信息

生命周期

  • Filter.init(FilterConfig config) 方法中传入
  • 整个 Filter 生命周期中只传入一次
  • Filter 实例可通过该对象持久持有配置信息
public interface FilterConfig {
String getFilterName();
ServletContext getServletContext();
String getInitParameter(String name);
Enumeration<String> getInitParameterNames();
  }
方法说明
String getInitParameter(String name)获取指定名称的初始化参数
Enumeration<String> getInitParameterNames()获取所有初始化参数的名称
String getFilterName()获取 <filter-name> 的值
ServletContext getServletContext()获取全局上下文对象

测试

public class MyFilterConfig implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String filterName = filterConfig.getFilterName();
System.out.println("MyFilterConfig初始化方法,过滤器名称:" + filterName);
ServletContext servletContext = filterConfig.getServletContext();
System.out.println("MyFilterConfig初始化方法,ServletContext对象:" + servletContext);
String username = filterConfig.getInitParameter("username");
System.out.println("MyFilterConfig初始化方法,username参数:" + username);
Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();
  while(initParameterNames.hasMoreElements()){
  String name = initParameterNames.nextElement();
  System.out.println(name+" = "+filterConfig.getInitParameter(name));
  }
  }
  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  }
  }
<filter>
<filter-name>MyFilterConfig</filter-name>
<filter-class>com.zzz.filter.MyFilterConfig</filter-class>
  <init-param>
  <param-name>username</param-name>
  <param-value>zhangsan</param-value>
  </init-param>
  <init-param>
  <param-name>password</param-name>
  <param-value>123456</param-value>
  </init-param>
  <init-param>
  <param-name>DriverClass</param-name>
  <param-value>com.mysql.cj.jdbc.Driver</param-value>
  </init-param>
</filter>
<filter-mapping>
<filter-name>MyFilterConfig</filter-name>
<url-pattern>/ServletA</url-pattern>
</filter-mapping>

或者通过注解配置

@WebFilter(initParams = {@WebInitParam(name = "username",value = "张三"),
@WebInitParam(name = "password",value = "123456")
},value = "/ServletA")

我们重启项目:因为FilterConfig是在 Filter.init(FilterConfig config) 方法中传入,整个 Filter 生命周期中只传入一次

在这里插入图片描述

3.6.2 FilterChain

过滤器链,实现责任链模式

作用

FilterChain 是 Servlet 容器动态构建的责任链(Chain of Responsibility),用于:

  • 按照配置顺序依次调用多个 FilterdoFilter() 方法
  • 在所有 Filter 执行完毕后,最终调用目标 Servletservice() 方法

核心机制

  • 动态构建:每次请求到达时,Tomcat 根据请求 URL 匹配所有有效的 Filter,并按 <filter-mapping> 顺序组装成 FilterChain
  • 顺序执行:每个 Filter 调用 chain.doFilter(request, response) 表示“放行”到下一个处理者
  • 终点是 Servlet:链的最后一个节点是目标 Servlet,调用 servlet.service()
    在这里插入图片描述
  • 如果某个 Filter没有调用chain.doFilter(),请求将被拦截,后续 FilterServlet 都不会执行
  • 多个 Filter 可以形成“环绕”效果:前处理 → 下一个 → 后处理
public interface FilterChain {
void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException;
}

我们查看源码,可以发现FilterChain就只有一个方法,其实这个方法就是用来对过滤器的拦截进行放行的,如果有多个过滤器,那么就会继续调用下一个Filter进行拦截。doFilter方法需要传入个参数,一个是ServletRequest,一个是ServletResponse,这个直接传入进行。

​ Tomcat在调用过滤器时,默认就会传入Request和Response,这个参数封装了请求和响应,我们直接使用就行。ServletResquest和ServletResponse可以直接强转成HttpServletRequest和HttpServletResponse,然后使用相应的方法。

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
}
接口特点
ServletRequest / ServletResponse通用接口,适用于任何协议(如 FTP、自定义协议等)
HttpServletRequest / HttpServletResponseHTTP 专用,提供了所有 HTTP 相关的操作方法

在 Web 应用中,我们处理的几乎都是 HTTP 请求,所以必须转成 HTTP 子类型才能进行实际操作。

测试

我们多写几个过滤器,通过FilterChain来进行多个过滤。

直接通过注解进行注册和映射。

@WebFilter("/ServletB")
public class MyFilter01 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + "   MyFilter01开始执行");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + "   MyFilter01执行完毕");
}
}
@WebFilter("/ServletB")
public class MyFilter02 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + "   MyFilter02开始执行");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + "   MyFilter02执行完毕");
}
}
@WebFilter("/ServletB")
public class MyFilter03 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + "   MyFilter03开始执行");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + "   MyFilter03执行完毕");
}
}
@WebServlet(value = "/ServletB",name = "ServletB")
public class ServletB extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + "   ServletB开始执行");
try {
Thread thread = new Thread();
thread.sleep(5000);
}catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + "   ServletB执行完毕");
}
}

我们访问http://localhost:8080/JavaWeb_05/ServletB
在这里插入图片描述

可以看到我们配置的多个过滤器生效,请求时过滤,响应时也会过滤。

那么我们怎么指定多个Filter的执行顺序呢?

3.7 多个Filter的执行顺序

FilterChain 中多个过滤器的执行顺序,是由它们在 web.xml 中的 <filter-mapping> 配置顺序决定的 —— 谁先声明,谁先执行。

不是按 <filter> 声明顺序,而是按 <filter-mapping> 的声明顺序!

方式一:使用 web.xml 配置

<filter>
<filter-name>MyFilter01</filter-name>
<filter-class>com.zzz.filter.MyFilter01</filter-class>
</filter>
<filter>
<filter-name>MyFilter02</filter-name>
<filter-class>com.zzz.filter.MyFilter02</filter-class>
</filter>
<filter>
<filter-name>MyFilter03</filter-name>
<filter-class>com.zzz.filter.MyFilter03</filter-class>
</filter>
<!-- 关键来了:mapping 的顺序决定执行顺序 -->
  <filter-mapping>
  <filter-name>MyFilter03</filter-name>
  <url-pattern>/ServletB</url-pattern>
  </filter-mapping>
  <filter-mapping>
  <filter-name>MyFilter02</filter-name>
  <url-pattern>/ServletB</url-pattern>
  </filter-mapping>
  <filter-mapping>
  <filter-name>MyFilter01</filter-name>
  <url-pattern>/ServletB</url-pattern>
  </filter-mapping>

测试

我们访问http://localhost:8080/JavaWeb_05/ServletB

在这里插入图片描述

此时可以发现顺序是按我们在web.xml中filter-mapping映射的顺序进行执行的。

方式二:使用注解

默认情况(无顺序控制):

@WebFilter("/*")
public class MyFilter01 implements Filter { ... }
@WebFilter("/*")
public class MyFilter02 implements Filter { ... }
@WebFilter("/*")
public class MyFilter03 implements Filter { ... }

使用 @Order@Priority(需配合 Spring)

如果你在 Spring Boot 环境下:

@Order(1)
@WebFilter("/*")
public class MyFilter01 implements Filter { ... }
@Order(2)
@WebFilter("/*")
public class MyFilter02 implements Filter { ... }
@Order(3)
@WebFilter("/*")
public class MyFilter03 implements Filter { ... }

@Order(n) 数值越小,优先级越高,越早执行。

⚠️ 注意:原生 Servlet 容器(如纯 Tomcat)不识别 @Order,它来自 Spring 框架。

四、Filter应用实例(实现敏感词汇过滤)

写一个评论页面,可以进行评论,如果评论中含有我们定义的敏感词汇,那么我们就进行过滤,使用***来进行代替。

@WebFilter(value = "/comment",initParams = {@WebInitParam(name = "words1",value = "zz"),
@WebInitParam(name = "words2",value = "sb")})
public class SensitiveWordFilter implements Filter {
private List<String> sensitiveWords = new ArrayList<>();
  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
  Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();
    while(initParameterNames.hasMoreElements()){
    String name = initParameterNames.nextElement();
    System.out.println(name+" = "+filterConfig.getInitParameter(name));
    sensitiveWords.add(filterConfig.getInitParameter(name));
    }
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) servletRequest;
    HttpServletResponse response = (HttpServletResponse) servletResponse;
    //设置编码
    request.setCharacterEncoding("utf-8");
    response.setContentType("text/html;charset=utf-8");
    //获得评论
    String comment = request.getParameter("comment");
    for (String sensitiveWord : sensitiveWords) {
    if (comment.contains(sensitiveWord)) {
    String newComment = comment.replace(sensitiveWord, "***");
    comment = newComment;
    } else {
    System.out.println("未匹配");
    }
    }
    //存入request域
    request.setAttribute("comment",comment);
    //放行
    filterChain.doFilter(servletRequest,servletResponse);
    }
    }
@WebServlet("/comment")
public class CommentServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置编码
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//获得评论
String comment = req.getAttribute("comment").toString();
if(comment.contains("***")){
resp.getWriter().write("<p> bad boy :"+comment + "</p>");
}else{
resp.getWriter().write("<p> good boy :"+comment + "</p>");
}
}
}
<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
      <title>敏感词汇过滤</title>
      </head>
      <body>
      <h1>敏感词汇过滤</h1>
      <h2>请输入评论:</h2>
          <form action="comment" method="post">
        <textarea id="comment" name="comment" rows="5" cols="40"></textarea>
            <input type="submit" value="提交">
          </form>
        </body>
      </html>

我们通过设置注解配置过滤器的初始化值,设置了两个zz和sb

在初始化阶段,通过FilterConfig获得两个初始化参数将他们存入我们的List集合中

在doFilter()方法中,我们通过request对象获得我们前端输入的comment,此时我们进行过滤,当包含我们的敏感词时,对他进行一个替换,并将它重新设置回request对象中,此时过滤完毕放行。

放行后到达我们的CommentServlet,我们从request对象中获得过滤过的comment,判断comment是否含有***,也就是我们过滤的替换标志,然后通过不同的情况,设置response对象。

我们输入你是一个好人
在这里插入图片描述

在这里插入图片描述

我们输入你是一个zz

在这里插入图片描述
在这里插入图片描述

此时我们的敏感词过滤就成功了。


总结

Filter 是 Java Web 中用于拦截请求和响应的组件,可在到达 Servlet 前进行权限校验、编码设置、日志记录、敏感词过滤等处理。它通过 doFilter() 方法实现逻辑,并由 FilterChain 控制多个过滤器的执行顺序。配置方式有注解和 web.xml 两种,生命周期由容器管理,是实现通用功能解耦的核心技术。

posted on 2025-11-08 20:35  mthoutai  阅读(2)  评论(0)    收藏  举报