Tomcat 学习之 Filter 过滤器

news2024/9/21 2:48:28

目录

1 Filter 介绍

2 Filter 的生命周期

3 Filter 和 FilterChain

4 Filter 拦截过程

5 FilterConfig

6 Filter 使用


1 Filter 介绍

        在 Tomcat 中,Filter 是一种用于拦截请求过滤响应的组件,可以在请求到达 Servlet 之前或响应离开 Servlet 之后对其进行处理。

Filter 的主要应用场景包括:

  1. 权限控制:可以使用 Filter 来检查请求的用户是否具有访问特定资源的权限
  2. 日志记录:可以使用 Filter 来记录请求和响应的信息,以便进行监控和故障排除
  3. 性能监控:可以使用 Filter 来测量请求的处理时间和响应时间,以便进行性能优化
  4. 数据加密和解密:可以使用 Filter 来对请求和响应进行加密和解密,以保护敏感信息的安全

2 Filter 的生命周期

Filter 的生命周期由 Tomcat 容器管理,包含以下几个方法:

  1. 构造器方法,在 web 工程启动的时候执行
  2. init 初始化方法,在 web 工程启动的时候执行
  3. doFilter 过滤方法,每次拦截到请求,就会执行
  4. destroy 销毁,停止 web 工程的时候,就会销毁 Filter 过滤器

3 Filter 和 FilterChain

Filter 接口

public interface Filter {
   // 容器创建的时候调用, 即启动 Tomcat 的时候调用
   public void init(FilterConfig filterConfig) throws ServletException;
   // 由 FilterChain 调用, 并且传入 FilterChain 本身, 最后回调 FilterChain 的 doFilter() 方法
   public void doFilter(ServletRequest request, ServletResponse response,
       FilterChain chain) throws IOException, ServletException;
   // 容器销毁的时候调用, 即关闭 Tomcat 的时候调用
   public void destroy();
 }

FilterChain 接口

public interface FilterChain {
   // 由 Filter.doFilter() 中的 chain.doFilter 调用
   public void doFilter(ServletRequest request, ServletResponse response)
     throws IOException, ServletException;
}

        当 Tomcat 接收到 URL 请求时,它会根据在 web.xml 文件中配置的过滤器和映射路径来创建 FilterChain。如果某个请求匹配了一些过滤器的映射路径,那么这些过滤器将被添加到 FilterChain。创建了 FilterChain 之后,就开始执行 doFilter,进行请求的链式处理。

过滤器执行顺序:

  • 通过 web.xml 配置的 Filter 过滤器,执行顺序由 <filter-mapping> 标签的配置顺序决定。<filter-mapping> 靠前,则 Filter 先执行,靠后则后执行。通过修改 <filter-mapping> 的顺序便可以修改 Filter 的执行顺序
  • 通过 @WebFilter 注解配置的 Filter 过滤器,无法进行排序,若需要对 Filter 过滤器进行排序,建议使用 web.xml 进行配置

4 Filter 拦截过程

        如图是 Filter 拦截过程示意图。所有 Filter 和 Web 资源都默认执行在同一个线程中(因为Filter 和 Web 资源通常是在 HttpServlet 容器中运行的,而 HttpServlet 容器是基于单线程模型的)。对于 FilterChain 中的 Filter,它们都使用同一 Request 对象。

以下是 Filter 拦截过程的一般步骤:

  1. 客户端发送请求到给 Web 服务器
  2. Web 服务器接收到请求后,将请求传递给 HttpServlet 容器
  3. HttpServlet 容器根据请求的 URL 路径和配置的映射信息,确定应该调用哪些 Filter
  4. Filter 的 doFilter() 方法被调用,该方法将接收请求和响应对象作为参数
  5. 在 doFilter() 方法中,Filter 可以执行各种操作,例如检查请求头、修改请求参数、处理权限验证等
  6. 如果 Filter 决定继续处理请求,它可以通过调用 filterChain.doFilter() 方法将请求传递给下一个 Filter(如果有下一个 Filter)或 Web 资源(没有下一个 Filter)
  7. 下一个 Filter 的 doFilter() 方法被调用,直到请求到达最终的目标资源
  8. 目标资源处理请求并生成响应,响应通过 Filter 链反向传递,每个 Filter 都可以在响应离开之前对其进行修改或处理
  9. 最终,响应被发送回客户端,客户端接收到处理后的结果

FilterConfig

        FilterConfig 是 Filter 过滤器的配置文件类。Tomcat 每次创建 Filter 的时候,也会同时创建一个 FilterConfig 类,它包含了 Filter 配置文件的配置信息。
FilterConfig 类的作用是获取 filter 过滤器的配置内容
  • 获取 Filter 的名称 filter-name 的内容
  • 获取在 Filter 中配置的 init-param 初始化参数
  • 获取 ServletContext 对象
@Override
public void init(FilterConfig filterConfig) throws ServletException {
    // 1、获取 Filter 的名称 filter-name 的内容
    System.out.println("filter-name 的值是:" + filterConfig.getFilterName());
    // 2、获取在 web.xml 中配置的 init-param 初始化参数
    System.out.println("初始化参数 username 的值是:" + filterConfig.getInitParameter("username"));
    System.out.println("初始化参数 url 的值是:" + filterConfig.getInitParameter("url"));
    // 3、获取 ServletContext 对象
    System.out.println(filterConfig.getServletContext());
}

6 Filter 使用

工程目录

web.xml 配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- <display-name> 元素常用于配置 servlet、过滤器或其他 Web 组件的显示名称。
    这个显示名称主要用于在管理界面或日志中标识该组件,以方便识别和管理。 -->
    <!-- 标识项目名 -->
    <display-name>ServletTest</display-name>

    <!-- 定义首页文件,也就是用户直接输入域名时跳转的页面(如http://localhost:8080/)-->
    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
    </welcome-file-list>


    <!--filter 标签用于配置一个 Filter 过滤器-->
    <filter>
        <!--给 filter 起一个别名-->
        <filter-name>AdminFilter1</filter-name>
        <!--配置 filter 的全类名-->
        <filter-class>com.test.AdminFilter1</filter-class>
        <!-- 设置 Servlet 初始化参数
        可以通过 FilterConfig.getInitParamenter(String name) 方法访问初始化参数 -->
        <init-param>
            <param-name>username</param-name>
            <param-value>root</param-value>
        </init-param>
        <init-param>
            <param-name>url</param-name>
            <param-value>jdbc:mysql://localhost3306/test</param-value>
        </init-param>
    </filter>
    <!-- 设置 filter 映射 -->
    <filter-mapping>
        <!-- 和 filter 标签中的 filter-name 对应 -->
        <filter-name>AdminFilter1</filter-name>
        <!-- 设置匹配的路径,这里设置为 /img/* 表示访问 img 目录下的图片都会调用该 filter(AdminFilter) -->
        <url-pattern>/img/*</url-pattern>
    </filter-mapping>
    <filter>
        <filter-name>AdminFilter2</filter-name>
        <filter-class>com.test.AdminFilter2</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>AdminFilter2</filter-name>
        <url-pattern>/img/*</url-pattern>
    </filter-mapping>
</web-app>

login.jsp 

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>登录</title>
    </head>
    <body>
    <form action="http://localhost:8080/servlettest/loginServlet" method="get">
        用户名: <input type="text" name="username"/> <br>
        密 码: <input type="password" name="password"/> <br>
        <input type="submit" />
    </form>
    </body>
</html>

LoginServlet 类

package com.test;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
            IOException {
        resp.setContentType("text/html; charset=UTF-8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if ("root".equals(username) && "123456".equals(password)) {
            System.out.println("设置 Seesion: {user : " + username + " }");
            req.getSession().setAttribute("user",username);
            System.out.println("登录成功!");
            resp.getWriter().write("登录 成功!!!");
        } else {
            System.out.println("登录失败!");
            req.getRequestDispatcher("/login.jsp").forward(req,resp);
        }
    }
}

AdminFilter1 类

package com.test;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;

public class AdminFilter1 implements Filter {

    // doFilter 方法,专门用于拦截请求。可以做权限检查
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain
            filterChain) throws IOException, ServletException {
        System.out.println("过滤器 AdminFilter1");
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpSession session = httpServletRequest.getSession();
        Object user = session.getAttribute("user");
        // System.out.println("登录用户: " + user);
        // 如果等于 null,说明还没有登录
        if (user == null) {
            System.out.println("未登录,跳转到登录页面");
            servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);
            return;
        } else {
            // 让程序继续往下访问用户的目标资源
            System.out.println("AdminFilter1 调用 doFilter 方法");
            filterChain.doFilter(servletRequest,servletResponse);
            System.out.println("AdminFilter1 结束了 doFilter 方法的调用");
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 1、获取 Filter 的名称 filter-name 的内容
        System.out.println("filter-name 的值是:" + filterConfig.getFilterName());
        // 2、获取在 web.xml 中配置的 init-param 初始化参数
        System.out.println("初始化参数 username 的值是:" + filterConfig.getInitParameter("username"));
        System.out.println("初始化参数 url 的值是:" + filterConfig.getInitParameter("url"));
        // 3、获取 ServletContext 对象
        System.out.println(filterConfig.getServletContext());
    }
}

AdminFilter2 类

package com.test;

import javax.servlet.*;
import java.io.IOException;

public class AdminFilter2 implements Filter {

    // doFilter 方法,专门用于拦截请求。可以做权限检查
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain
            filterChain) throws IOException, ServletException {
        System.out.println("过滤器 AdminFilter2");
        System.out.println("AdminFilter2 调用 doFilter 方法");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("AdminFilter2 结束了 doFilter 方法的调用");
    }
}

运行演示图

运行流程:

  1. 启动服务器 Tomcat,创建 AdminFilter1 和 AdminFilter2 对象,获取 FilterConfig 配置并初始化,创建 LoginServlet 对象,获取 ServletConfig 配置并初始化,进入首页文件 login.jsp
  2. 客户端尝试请求访问 http://localhost:8080/servlettest/img/2.jpg,由过滤器 AdminFilter1 处理,输出“过滤器 AdminFilter1”和“未登录,跳转到登录页面”,之后跳转到 login.jsp 进行登录
  3. 输入账号:root,密码:123456,由 LoginServlet 的 doGet() 方法处理,设置 Seesion: {user : root },输出“登录成功!”
  4. 客户端再次请求访问 http://localhost:8080/servlettest/img/2.jpg,由过滤器 AdminFilter1 和 AdminFilter2 依次处理(调用 filterChain.doFilter 方法后可以对响应结果进行处理),之后返回响应结果给客户端
  5. 客户端得到响应结果,显示图片

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1464822.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

宝塔面板mysql使用root账户远程登录

今日在弄数据库备份&#xff0c;我们两台服务器&#xff0c;一台测试环境一个正式环境&#xff1b;使用linux宝塔面板&#xff0c;数据库都是服务器本地mysql&#xff0c;打算在测试服务器添加远程数据库备份正式环境的数据库&#xff0c;需要注意的是添加远程服务器后必须点一…

QEMU源码全解析 —— virtio(22)

接前一篇文章&#xff1a;QEMU源码全解析 —— virtio&#xff08;21&#xff09; 前几回讲解了virtio驱动的加载。本回开始讲解virtio驱动的初始化。 在讲解virtio驱动的初始化之前&#xff0c;先要介绍virtio配置的函数集合变量virtio_pci_config_ops。实际上前文书也有提到…

开源博客项目Blog .NET Core源码学习(9:Autofac使用浅析)

开源博客项目Blog使用Autofac注册并管理组件和服务&#xff0c;Autofac是面向.net 的开源IOC容器&#xff0c;支持通过接口、实例、程序集等方式注册组件和服务&#xff0c;同时支持属性注入、方法注入等注入方式。本文学习并记录Blog项目中Autofac的使用方式。   整个Blog解…

hash,以及数据结构——map容器

1.hash是什么&#xff1f; 定义&#xff1a;hash,一般翻译做散列、杂凑&#xff0c;或音译为哈希&#xff0c;是把任意长度的输入&#xff08;又叫做预映射pre-image&#xff09;通过散列算法变换成固定长度的输出&#xff0c; 该输出就是散列值。这种转换是一种压缩映射&…

【selenium】三大切换 iframe 弹窗alert 句柄window 和 鼠标操作

目录 一、iframe 1、切换方式&#xff1a; 1、第一种情况&#xff1a; 2、第二种情况&#xff1a; 方式1: 先找到iframe&#xff0c;定位iframe元素&#xff08;可以通过元素定位的各种方式&#xff1a;xpath&#xff0c;css等等&#xff09;&#xff0c;用对象接收&…

vue后台管理添加水印简单方式watermark-package

详情参考:https://www.npmjs.com/package/watermark-package 示例方法 <el-button type"primary" click"AddWatermark">添加水印</el-button><el-button type"primary" click"RemoveWatermark">清除水印</el-but…

7 个值得收藏的 Python 身份验证库

在数字化转型时代&#xff0c;每一个数据字节都成为潜在的金矿&#xff0c;保护数据变得至关重要。将数字领域视为一座古老的宫殿&#xff0c;虽然里面装饰着宝藏&#xff08;读&#xff1a;数据&#xff09;&#xff0c;但大门&#xff08;读&#xff1a;身份验证&#xff09;…

Qt 事件

1. 事件 事件是对各种应用程序需要知道的由应用程序内部或者外部产生的事情或者动作的通称。在Qt中使用一个对象来表示一个事件&#xff0c;它继承自QEvent类。 2. 事件和信号 事件与信号并不相同&#xff0c;比如我们使用鼠标点击了一下界面上的按钮&#xff0c;那么就会产生…

信钰证券:炒股死记8句口诀?新手须知!

炒股死记以下8句口诀&#xff1a; 1、早上大跌可加仓&#xff0c;早上大涨要减仓 当个股在开盘后呈现大跌的状况&#xff0c;很有可能是主力在使用低开进行洗盘操作&#xff0c;散户能够考虑在此刻加仓&#xff0c;等股价反弹时&#xff0c;好做T卖出&#xff0c;赚取一定的差…

【Appium UI自动化】pytest运行常见错误解决办法

通过Appium工具录制代码在pycharm上运行报错&#xff1a; 错误一&#xff1a; 1.提示 setup() 方法运行 error failed 解决办法&#xff1a;未创建 init __ 方法&#xff0c;创建一个空的__init.py文件就解决了。 原因&#xff1a; 错误二&#xff1a; 2.运行代码&#xff…

文心一言 VS 讯飞星火 VS chatgpt (199)-- 算法导论15.2 1题

一、用go语言&#xff0c;对矩阵规模序列(5&#xff0c;10&#xff0c;3&#xff0c;12&#xff0c;5&#xff0c;50&#xff0c;6)&#xff0c;求矩阵链最优括号化方案。 文心一言&#xff0c;代码正常运行&#xff1a; 在Go语言中&#xff0c;为了找到矩阵链乘法的最优括号…

船舶制造5G智能工厂数字孪生可视化平台,推进船舶行业数字化转型

船舶制造5G智能工厂数字孪生可视化平台&#xff0c;推进船舶行业数字化转型。随着数字化时代的到来&#xff0c;船舶行业正面临着前所未有的机遇与挑战。为了适应这一变革&#xff0c;船舶制造企业需要加快数字化转型的步伐&#xff0c;提高生产效率、降低成本并增强市场竞争力…

C 嵌入式系统设计模式 09:硬件适配器模式

本书的原著为&#xff1a;《Design Patterns for Embedded Systems in C ——An Embedded Software Engineering Toolkit 》&#xff0c;讲解的是嵌入式系统设计模式&#xff0c;是一本不可多得的好书。 本系列描述我对书中内容的理解。本文章描述访问硬件的设计模式之二&…

JAVA毕业设计128—基于Java+Springboot+Vue的共享单车租赁管理系统(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootVue的共享单车租赁管理系统(源代码数据库)128 一、系统介绍 本项目前后端分离&#xff0c;本系统分为管理员、用户两种角色 1、用户&#xff1a; 注册、登录、…

Java学习笔记2024/2/22

面向对象进阶部分学习方法&#xff1a; 特点&#xff1a; 逻辑性没有那么强&#xff0c;但是概念会比较多。 记忆部分重要的概念&#xff0c;理解课堂上讲解的需要大家掌握的概念&#xff0c;多多练习代码。 今日内容 复习回顾 static关键字 继承 教学目标 能够掌握st…

【移动安全】MobSF联动安卓模拟器配置动态分析教程

原文链接 MobSF联动安卓模拟器配置动态分析教程 实现方式 Windows开启安卓模拟器并进行相关配置作为调试客户端&#xff0c;Linux使用docker开启MobSF作为服务端。 好处&#xff1a;干净&#xff0c;部署简单&#xff0c;不用安装乱七八糟的环境&#xff0c;防止破坏其他应…

SpringCloud(14)之SpringCloud Consul

我们知道 Eureka 2.X 遇到困难停止开发了&#xff0c;所以我们需要寻找其他的替代技术替代Eureka&#xff0c;这一小 节我们就讲解一个新的组件Consul。 一、Consul介绍 Consul 是 HashiCorp 公司推出的开源工具&#xff0c;用于实现分布式系统的服务发现与配置。与其它分布式…

【k8s核心概念与专业术语】

k8s架构 1、服务的分类 服务分类按如下图根据数据服务支撑&#xff0c;分为无状态和有状态 无状态引用如下所示&#xff0c;如果一个nginx服务&#xff0c;删除后重新部署有可以访问&#xff0c;这个属于无状态&#xff0c;不涉及到数据存储。 有状态服务&#xff0c;如redis&a…

音视频技术-电脑连接调音台时交流声的产生与消除

当电脑(笔记本/台式机)声卡通过音频线与调音台(或扩音机)连接时,能听到“交流声”。有时很轻微,有时很明显,甚至干扰正常的演讲或发言。 很多时候,我们在台上演讲时,都会使用电脑播放PPT,遇到视频时,还需要将视频中的音频扩大。电脑音频的输出口一般都是3.5的,我们…

Flutter常用命令,持续更新

目录 前言 Flutter 常用命令 Dart 常用命令 adb 常用命令&#xff08;用于 Android 开发&#xff09; 前言 当在开发Flutter项目时&#xff0c;熟悉一些常用的命令是非常重要的。这些命令可以帮助你执行各种任务&#xff0c;从构建应用程序到调试和测试。以下是一些Flutte…