Tomcat 学习之 Filter 过滤器

目录

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. 客户端得到响应结果,显示图片

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第15章-IP子网划分

1. 子网划分的需求 1.1 早期的IP地址分类 1.2 产生的问题 1.3 现实的应用场景 2. IP子网划分基础知识 2.1 概念 2.2 子网掩码 3. IP子网划分相关计算 3.1 概述 4. VLSM和CIDR 4.1 VLSM(可变长子网掩码)小 → 大&#xff1b; 4.2 CIDR(无类域间路由)大 → 小&#xff1b; 5.…

Syntax Error: Error: Cannot find module ‘node-sass‘报错解决

1.将项目中的node_modules删除掉 2.npm install重新运行安装命令 3.再npm run serve&#xff08;项目启动命令&#xff09;启动项目即可

LeetCode第二题: 两数相加

文章目录 题目描述示例 解题思路 - 迭代法Go语言实现 - 迭代法算法分析 解题思路 - 模拟法Go语言实现 - 模拟法算法分析 解题思路 - 优化模拟法主要方法其他方法的考虑 ‍ 题目描述 给出两个非空的链表用来表示两个非负的整数。其中&#xff0c;它们各自的位数是按照逆序的方…

DALL·E 3:Improving Image Generation with Better Captions

论文链接&#xff1a;https://cdn.openai.com/papers/dall-e-3.pdf DALLE3 API&#xff1a;https://github.com/Agora-X/Dalle3 官网链接&#xff1a;添加链接描述 DALLE3讲解视频&#xff1a;B站视频 推荐DALLE2的讲解视频&#xff1a;B站&#xff1a;跟李沐学AI 之前精讲的DA…

【Leetcode】235. 二叉搜索树的最近公共祖先

文章目录 题目思路代码结果 题目 题目链接 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个结点 p、q&#xff0c;最近公共祖先表示为一个结点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度…

Linux的文件操作,重拳出击( ̄︶ ̄)

Linux的文件操作 学习Linux的文件操作&#xff0c;一般需要知道一个文件如果你想要操作他&#xff0c;必须知道你对这个文件有什么操作的权限或者修改你自己对文件操作的权限。必须要知道文件有三种权限 r&#xff1a;可读 w&#xff1a;可写 x&#xff1a;可执行 在打开Linux…

【cmu15445c++入门】(10)C++锁mutex

一、锁 lock和unlock 二、 代码 // This program shows a small example of the usage of std::mutex. The // std::mutex class provides the mutex synchronization primitive. // std::mutex 类提供互斥同步原语。// Includes std::cout (printing) for demo purposes. #i…

超详细的MyCat安装部署

MyCat概述 介绍 Mycat是开源的、活跃的、基于Java语言编写的MySQL数据库中间件。可以像使用mysql一样来使用 mycat&#xff0c;对于开发人员来说根本感觉不到mycat的存在。 开发人员只需要连接MyCat即可&#xff0c;而具体底层用到几台数据库&#xff0c;每一台数据库服务器里…

预测性维修系统的功能分析和建设建议

随着工业领域的不断发展&#xff0c;设备状态监测、健康管理和智能诊断变得愈发重要。预测性维修系统通过先进的技术和可靠性评估&#xff0c;帮助企业判断设备状态&#xff0c;识别故障早期征兆&#xff0c;并生成故障预判&#xff0c;从而提出检维修建议。在这一背景下&#…

【前端素材】推荐优质后台管理系统Be admin平台模板(附源码)

一、需求分析 后台管理系统&#xff08;或称作管理后台、管理系统、后台管理平台&#xff09;是一种专门用于管理网站、应用程序或系统后台运营的软件系统。它通常由一系列功能模块组成&#xff0c;为管理员提供了管理、监控和控制网站或应用程序的各个方面的工具和界面。以下…

前端面试篇-JS篇2

37、事件模型(事件代理)(重要) 是指从事件发生开始,到所有处理函数执行完,所经历的过程。大概包括: 3个阶段 1)捕获阶段: 首先 Window 捕获事件,之后往目标传递,在到达目标节点之前的过程,就是捕获阶段(Capture Phase) 2)目标阶段: 真正触发点击的元素,事件会触发…

天哪!还有这些逆天的fofa​语句?(二)

接上文 天哪&#xff01;还有这些逆天的fofa语句&#xff1f; 再分享几条&#xff0c;个人觉得比较有意思的fofa语句。 情侣飞行器 之前写过文章的&#xff0c;有兴趣的师傅可以试着翻翻以前的文章去破解密码 fofa语句&#xff1a;"static/js/index.d2dcdf5b.js"…

88. 合并两个有序数组——javascript实现

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&#xff0c;使合并后的数组同样按 非递减顺序 排列。 注意&#xff1a;最终&#xff0c;合并后数组…

Spring Bean 相关注解

目录 Autowired Component,Repository,Service, Controller RestController Scope Configuration Autowired 自动导入对象到类中&#xff0c;被注入进的类同样要被 Spring 容器管理比如&#xff1a;Service 类注入到 Controller 类中。 Service public class UserService …

vite搭配vue2创建工程

一、安装vite npm init vite2.8.0 vite默认支持的是vue3&#xff0c; 这里选择框架和版本vanilla&#xff0c; 方便以后自己安装vue2. 二、修改package.json 默认生成的pacakage.json文件 {"name": "vite-project","private": true,"v…

lv20 QT入门与基础控件 1

1 QT简介 QT是挪威Trolltech开发的多平台C图形用户界面应用程序框架 典型应用 2 工程搭建 2.1 新建ui工程 不要写中文路径 2.1 不勾选UI&#xff08;主讲&#xff09; 3 QT信号与槽机制 语法&#xff1a;Connect&#xff08;A, SIGNLA(aaa()), B, SLOT(bbb())&#xff09;…

操作系统--零拷贝

一、直接内存访问&#xff08;DMA&#xff09;技术 什么是 DMA 技术&#xff1f;简单理解就是&#xff0c;在进行 I/O 设备和内存的数据传输的时候&#xff0c;数据搬运的工作全部交给 DMA 控制器&#xff0c;而 CPU 不再参与任何与数据搬运相关的事情&#xff0c;这样 CPU 就…

【数据结构】栈OJ题《用栈实现队列》(题库+解析+代码)

1. 前言 通过前面栈的实现和详解大家对队列应该有一定熟悉了&#xff0c;现在上强度开始做题吧 栈详解&#xff1a;http://t.csdnimg.cn/9Fsbs 本体的做题思路也可以参考上一篇文章&#xff0c;就是有一点点不同。 用队列实现栈&#xff1a;http://t.csdnimg.cn/V2qjW 2. …

图形系统开发实战课程:进阶篇(上)——7.图形交互操作: 视点控制与动画

图形开发学院&#xff5c;GraphAnyWhere 课程名称&#xff1a;图形系统开发实战课程&#xff1a;进阶篇(上)课程章节&#xff1a;“图形交互操作: 视点控制与动画”原文地址&#xff1a;https://www.graphanywhere.com/graph/advanced/2-7.html 第七章 图形交互操作: 视点控制与…

MAUI 需要先部署项目,然后才能进行调试。请在配置服务器中启动部署。

刚刚创建完MAUI项目&#xff0c;选中windows&#xff0c;运行的时候提示这个 解决方案 选择菜单【项目】-> 【概述】 打开界面如下 然后点击【发布】&#xff0c;再点击【添加发布配置文件】&#xff0c;再点【下一步】 然后就可以运行了