当前位置: 首页 > news >正文

过滤器 Filter 详解

想象一下,你正在搭建一个网站,用户需要登录才能访问某些页面。你肯定不希望未经授权的用户能够随意浏览或修改重要信息,这时,你就需要一个“安全门”来保护你的网站,而 Java Filter 就是扮演这个角色的最佳人选!

一、Filter 基本概念

1.1 什么是 Filter ?

Filter 就像一个尽职尽责的“保安”,专门负责检查进出网站的人员和货物。它拦截每一个来自客户端(例如浏览器)的请求,并在请求到达最终目的地(例如 Servlet 或 JSP 页面)之前进行一系列的检查和处理。同样地,当服务器准备将响应发送回客户端时,Filter 也会再次进行拦截,对响应内容进行修改或添加额外的信息。

1.2 Filter 的作用
  • 拦截请求和响应: 就像保安检查来往人员一样,Filter 可以拦截所有进出网站的 HTTP 请求和响应,掌握网站动态。

  • 预处理请求: 在请求到达目的地之前,Filter 可以进行一些预处理操作,例如:

    • 检查用户是否登录

    • 设置字符编码,避免乱码

    • 记录请求日志,方便追踪问题

  • 修改请求和响应: Filter 可以根据需要修改请求头、请求体、响应头和响应体的内容,例如:

    • 添加或删除 Cookie

    • 设置响应状态码

    • 压缩响应数据,提高传输效率

  • 拦截请求: 对于一些不符合条件的请求,Filter 可以直接拒绝,阻止其访问敏感资源,例如:

    • 阻止未登录用户访问需要权限的页面

    • 限制来自特定 IP 地址的访问

1.3 Filter 的生命周期

Filter 的生命周期由 Servlet 容器(例如 Tomcat)全权负责,就像保安在岗时间一样,有着严格的管理:

  1. 实例化: 当 Servlet 容器启动时,会根据配置文件创建 Filter 实例,就像保安上班打卡一样。

  2. 初始化: Filter 实例创建后,容器会调用 init() 方法,让 Filter 做好上岗前的准备工作,例如加载配置文件或初始化资源。

  3. 过滤请求: 每当有请求到达时,容器都会调用 doFilter() 方法,让 Filter 执行过滤逻辑,就像保安检查来往人员一样。

  4. 销毁: 当 Servlet 容器关闭时,会调用 destroy() 方法,让 Filter 释放资源,结束工作,就像保安下班打卡一样。

1.4 Filter 的使用

为了让 Filter 能够完成各种任务,Java Servlet API 提供了一套强大的武器库,让 Filter 能够应对各种挑战:

  • javax.servlet.Filter 接口: 这是所有 Filter 的“身份证明”,只有实现了这个接口的类才能被称为 Filter。它定义了 Filter 的基本行为,包括 init()、doFilter() 和 destroy() 三个核心方法。

  • javax.servlet.FilterChain 接口: Filter 并不是孤军奋战,它通常与其他 Filter 组成一个团队,协同工作。FilterChain 接口就代表了这个团队,它维护了一个 Filter 链条,并提供了 doFilter() 方法,用于将请求传递给链条中的下一个 Filter 或最终的目标资源。

  • javax.servlet.FilterConfig 接口: 每个 Filter 在工作时都需要一些配置信息,例如 Filter 的名称、初始化参数等。FilterConfig 接口就提供了获取这些配置信息的途径,让 Filter 能够根据配置信息进行个性化的工作。

二、实现 Filter

2.1 创建 Filter

打造一个专属 Filter 非常简单,只需三步即可完成:

  1. 实现 javax.servlet.Filter 接口: 这是成为 Filter 的必要条件,你需要实现 init()、doFilter() 和 destroy() 三个方法。

  2. 编写过滤逻辑: 在 doFilter() 方法中编写你的过滤逻辑,例如检查用户是否登录、记录请求日志等。

  3. 配置 Filter: 告诉 Servlet 容器你的 Filter 的信息,包括 Filter 的名称、类名以及要拦截的 URL 地址等。

2.2 代码示例
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化操作,例如获取配置参数String param = filterConfig.getInitParameter("paramName");System.out.println("Filter 初始化参数:" + param);}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {// 预处理操作,例如打印请求路径HttpServletRequest req = (HttpServletRequest) request;System.out.println("请求路径:" + req.getRequestURI());// 调用 chain.doFilter() 方法,将请求传递给下一个 Filter 或目标资源chain.doFilter(request, response);// 后处理操作,例如打印响应内容System.out.println("响应内容:" + response.getContentType());}@Overridepublic void destroy() {// 销毁操作,例如释放资源System.out.println("Filter 销毁");}
}
  • init方法:过滤器的初始化方法。在web服务器启动的时候会自动的创建Filter过滤器对象,在创建过滤器对象的时候会自动调用init初始化方法,这个方法只会被调用一次。

  • doFilter方法:这个方法是在每一次拦截到请求之后都会被调用,所以这个方法是会被调用多次的,每拦截到一次请求就会调用一次doFilter()方法。

  • destroy方法: 是销毁的方法。当我们关闭服务器的时候,它会自动的调用销毁方法destroy,而这个销毁方法也只会被调用一次。

2.3 配置 Filter

配置 Filter 有两种方式:

  • 使用 web.xml 文件配置: 这是传统的配置方式,需要在 web.xml 文件中添加 <filter> 和 <filter-mapping> 元素来定义 Filter 和其拦截路径。

<filter><filter-name>myFilter</filter-name> <filter-class>com.example.MyFilter</filter-class><init-param><param-name>paramName</param-name><param-value>paramValue</param-value></init-param>
</filter><filter-mapping><filter-name>myFilter</filter-name><url-pattern>/myServlet</url-pattern> 
</filter-mapping>

  • 使用 @WebFilter 注解配置: 这是 Servlet 3.0 之后提供的更简洁的配置方式,可以直接在 Filter 类上使用 @WebFilter 注解来定义 Filter 和其拦截路径。

@WebFilter(filterName = "myFilter", urlPatterns = "/myServlet", initParams = {@WebInitParam(name = "paramName", value = "paramValue")
})
public class MyFilter implements Filter {// ...
}

2.4 拦截路径

执行流程我们搞清楚之后,接下来再来介绍一下过滤器的拦截路径,Filter可以根据需求,配置不同的拦截资源路径:

拦截路径urlPatterns值含义
拦截具体路径/login只有访问 /login 路径时,才会被拦截
目录拦截/stus/*访问/stus下的所有资源,都会被拦截
拦截所有/*访问所有资源,都会被拦截

三、Spring Boot 中使用 Filter

在 Spring Boot 项目中,使用 Filter 更加方便,你只需要使用 @Component 注解将 Filter 注册为 Spring Bean,并使用 @WebFilter 注解配置其拦截路径即可。

3.1 大致步骤
  • 第1步,定义过滤器 :1.定义一个类,实现 Filter 接口,并重写其所有方法。

  • 第2步,配置过滤器:Filter类上加 @WebFilter 注解,配置拦截资源的路径。引导类上加 @ServletComponentScan 开启Servlet组件支持。

  • 第3步,当我们在Filter类上面加了@WebFilter注解之后,接下来我们还需要在启动类上面加上一个注解@ServletComponentScan,通过这个@ServletComponentScan注解来开启SpringBoot项目对于Servlet组件的支持。

3.2 示例代码:
@Component
@WebFilter(urlPatterns = "/*", filterName = "loginFilter")  //配置过滤器要拦截的请求路径( /* 表示拦截浏览器的所有请求 )
public class LoginFilter implements Filter {@Override //初始化方法, 只调用一次public void init(FilterConfig filterConfig) throws ServletException {System.out.println("init 初始化方法执行了");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("DemoFilter   放行前逻辑.....");//放行请求filterChain.doFilter(servletRequest,servletResponse);System.out.println("DemoFilter   放行后逻辑.....");}@Override //销毁方法, 只调用一次public void destroy() {System.out.println("destroy 销毁方法执行了");}}

四、Filter 执行流程

4.1 FilterChain

当多个 Filter 同时拦截同一个请求时,它们会组成一个 FilterChain,就像一条链条一样,依次对请求进行处理。FilterChain 维护了 Filter 的执行顺序,并通过 doFilter() 方法将请求传递给下一个 Filter。

4.2 执行流程
  1. 当一个请求到达 Servlet 容器时,容器会根据请求的 URL 地址找到所有匹配的 Filter,并将它们添加到一个 FilterChain 中。

  2. 容器调用 FilterChain 的 doFilter() 方法,开始执行 Filter 链。

  3. FilterChain 依次调用每个 Filter 的 doFilter() 方法,每个 Filter 都有机会对请求进行处理。

  4. 在 Filter 的 doFilter() 方法中,可以调用 chain.doFilter(request, response) 方法将请求传递给下一个 Filter,也可以选择不调用该方法,直接返回响应,结束请求处理流程。

  5. 如果 Filter 调用了 chain.doFilter(request, response) 方法,则 FilterChain 会将请求传递给下一个 Filter,直到最后一个 Filter 执行完毕。

  6. 最后一个 Filter 执行完毕后,FilterChain 会将请求传递给目标资源(例如 Servlet 或 JSP)。

  7. 目标资源执行完毕后,会生成响应,响应会按照 FilterChain 的反方向依次经过每个 Filter 的 doFilter() 方法,每个 Filter 都有机会对响应进行处理。

  8. 最终,响应会返回给客户端。

  9. 然而执行顺序其实是和过滤器的类名有关系。以注解方式配置的Filter过滤器,它的执行优先级是按时过滤器类名的自动排序确定的,类名排名越靠前,优先级越高。

4.3 图示
请求----->
[Filter 1] --> [Filter 2] --> [目标资源]<-----响应请求:1 -> 2
响应:2 -> 1完整:1 -> 2 -> 2 -> 1

五、小练习:Filter 实现登录校验

5.1 需求分析:

假设我们正在开发一个电商网站,用户需要登录才能进行下单操作。为了保证网站安全,我们需要使用 Filter 对所有请求进行拦截,检查用户是否登录,如果未登录,则跳转到登录页面。

5.2 代码实现:
@Component
@WebFilter(urlPatterns = {"/order/*"}, filterName = "authFilter")
public class AuthFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse res = (HttpServletResponse) response;// 获取用户信息User user = (User) req.getSession().getAttribute("user");// 判断用户是否登录if (user == null) {// 未登录,跳转到登录页面res.sendRedirect("/login");return;}// 已登录,放行请求chain.doFilter(request, response);}
}

5.3 代码解读:
  • 我们使用 @WebFilter 注解将 AuthFilter 声明为一个 Filter,并设置其拦截路径为 /order/*,表示拦截所有以 /order/ 开头的请求。

  • 在 doFilter() 方法中,我们首先获取用户信息。

  • 然后,我们判断用户是否登录,如果未登录,则跳转到登录页面,并使用 return 关键字结束请求处理流程。

  • 如果用户已登录,则调用 chain.doFilter(request, response) 方法,将请求传递给下一个 Filter 或目标资源。

六、总结:

Filter 是 Java Web 开发中一个非常重要的组件,它可以帮助我们实现各种功能,例如用户登录校验、日志记录、字符编码转换等。掌握 Filter 的使用,可以让我们开发出更加安全、稳定、高效的 Web 应用。

最后,希望上文能够帮助各位看官全面了解和掌握 Filter,并在实际项目中灵活运用它来解决各种问题。感谢各位看官的观看,下期见,谢谢~


http://www.mrgr.cn/news/41458.html

相关文章:

  • C++【类和对象】(再探构造函数、类型转换与static成员)
  • 如何选择与运用编程工具提升工作效率的秘密武器
  • 基于物理信息神经网络(PINN)求解Burgers方程(附PyTorch源代码)
  • 进程和线程之间的通用方式
  • [20241002] OpenAI融资文件曝光,ChatGPT年收入涨4倍,月费5年内翻倍
  • OpenGL笔记十九之相机系统
  • WSL--安装各种软件包
  • CompletableFuture常用方法
  • 计算机网络思维导图
  • 【微服务】组件、基础工程构建(day2)
  • C++中substr用法记录
  • 云原生(四十一)| 阿里云ECS服务器介绍
  • 什么是 Supply chain attack(供应链攻击)
  • 差分基准站
  • MySQL高阶2051-商店中每个成员的级别
  • Blazor开发框架Known-V2.0.13
  • JavaWeb
  • 基于深度学习的乳腺癌分类识别与诊断系统
  • 【YOLO目标检测行人与车数据集】共5607张、已标注txt格式、有训练好的yolov5的模型
  • 【C++】set容器和map容器的基本使用