【JavaWeb】过滤器 Filter

news2024/12/26 4:34:10

文章目录

  • 过滤器是什么?
  • 一、过滤器概述
  • 二、过滤器工作位置图解
  • 三、Filter接口API
  • 四、过滤器使用
    • 4.1 定义一个过滤器类,编写功能代码:
    • 4.2 xml配置:
    • 4.3 定义 servletG 目标资源 模拟测试 :
    • 4.4 过滤图解
  • 五、过滤器生命周期
  • 六、过滤器链的使用
    • 6.1 图解过滤链
    • 6.2 测试过滤链
    • 6.3 工作流程图解
  • 七、注解方式配置过滤器
    • 7.1 一个比较完整的Filter的XML配置
    • 7.2 将xml配置转换成注解方式实现
  • 总结


过滤器是什么?

  • Filter ,即 过滤器 ,是JAVAEE技术规范之一,
  • 作用目标资源的请求进行过滤的一套技术规范
  • 是Java Web项目中最为实用的技术之一

客户端发送请求 先经过filter的doFilter方法,这个方法控制是否放行请求到达目标,
不放行 即 使用filter的方式返回响应给客户端;
放行之后 请求即正常到达目标servlet
放行后 还可以对 响应数据进行处理


一、过滤器概述

  • Filter接口定义了过滤器的开发规范,所有的过滤器都要实现该接口

  • Filter的工作位置是项目中所有目标资源之前,容器在创建HttpServletRequestHttpServletResponse对象后,会先调用FilterdoFilter方法

  • Filter的doFilter方法可以控制请求是否继续,

    • 如果放行,则请求继续,
    • 如果拒绝,则请求到此为止,由过滤器本身做出响应
  • Filter不仅可以对请求做出过滤,也可以在目标资源做出响应前,对响应再次进行处理

  • Filter是GOF中责任链模式的典型案例

  • Filter的常用应用包括但不限于: 登录权限检查,解决网站乱码,过滤敏感字符,日志记录,性能分析… …

二、过滤器工作位置图解

1

三、Filter接口API

  • 源码
package jakarta.servlet;

import java.io.IOException;

public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    default void destroy() {
    }
}
  • API
API目标
default public void init(FilterConfig filterConfig)初始化方法,由容器调用并传入初始配置信息filterConfig对象
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)过滤方法,核心方法,过滤请求,决定是否放行,响应之前的其他处理等都在该方法中
default public void destroy()销毁方法,容器在回收过滤器对象之前调用的方法

四、过滤器使用

  1. 创建类 实现Filter接口
  2. 重写doFilter方法
  3. 可选择调用放行方法 将请求传下去 :
    3.1. filterChain.doFilter(servletRequest, servletResponse);
    3.2. 不写此方法 就是不放行请求到目标资源 卡这了

目标:开发一个日志记录过滤器

  • 用户请求到达目标资源之前,记录用户的请求资源路径
  • 响应之前记录本次请求目标资源运算的耗时
  • 可以选择将日志记录进入文件,为了方便测试,这里将日志直接在控制台打印

4.1 定义一个过滤器类,编写功能代码:

package com.doug.filters;

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Description:
 */
public class LoggingFilter implements Filter {
    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //父类转子类 能够使用子类独有的方法
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;

        //拼接日志
        String requestURI = req.getRequestURI();
        String time = dateFormat.format(new Date());
        String beforeLogging = requestURI + "在" + time + "被请求了";
        // 打印日志
        System.out.println(beforeLogging);

        // 获取系统时间
        long t1 = System.currentTimeMillis();
        //放行请求
        filterChain.doFilter(servletRequest, servletResponse);
        // 获取系统时间
        long t2 = System.currentTimeMillis();

        //  拼接日志文本
        String afterLogging = requestURI + "在" + time + "的请求耗时:" + (t2 - t1) + "毫秒";
        // 打印日志
        System.out.println(afterLogging);

    }
}

说明

  • doFilter方法中的请求响应对象是以父接口的形式声明的,实际传入的实参就是HttpServletRequest和HttpServletResponse子接口级别的,可以安全强转
  • filterChain.doFilter(request,response); 这行代码的功能是放行请求,如果没有这一行代码,则请求到此为止
  • filterChain.doFilter(request,response);在放行时需要传入requestresponse,意味着请求和响应对象要继续传递给后续的资源,这里没有产生新的request和response对象

4.2 xml配置:

    <!--配置filter,并为filter起别名-->
    <filter>
        <filter-name>loggingFilter</filter-name>
        <filter-class>com.doug.filters.LoggingFilter</filter-class>
    </filter>
    
    <!--为别名对应的filter配置要过滤的目标资源-->
    <filter-mapping>
        <filter-name>loggingFilter</filter-name>
        
		<!--  可以用获取servlet别名的方式      -->
        <servlet-name>sg1</servlet-name>
        
		<!--  或者 使用获取servletG 路径的方式      -->
     <url-pattern>/servletG</url-pattern>
     
	 <!-- 或者 通过后缀名确定过滤资源-->
        <url-pattern>*.html</url-pattern>
    </filter-mapping>

说明:

  • filter-mapping标签中定义了过滤器对那些资源进行过滤
  • 子标签url-pattern通过映射路径确定过滤范围
    • /servletA 精确匹配,表示对servletA资源的请求进行过滤
    • *.html表示对以.action结尾的路径进行过滤
    • /* 表示对所有资源进行过滤
    • 一个filter-mapping下可以配置多个url-pattern
  • 子标签servlet-name通过servlet别名确定对那些servlet进行过滤
    • 使用该标签确定目标资源的前提是servlet已经起了别名
    • 一个filter-mapping下可以定义多个servlet-name
    • 一个filter-mapping下,servlet-nameurl-pattern子标签可以同时存在

4.3 定义 servletG 目标资源 模拟测试 :

@WebServlet(value = "/servletG",name = "sg1")
public class ServletG extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().write("servletG处理请求的方法,耗时10毫秒");
        System.out.println("servletG处理请求的方法,耗时10毫秒");
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

结果

4.4 过滤图解

在这里插入图片描述

五、过滤器生命周期

过滤器作为web项目的组件之一,和Servlet的生命周期类似,
略有不同,没有servlet的load-on-startup的配置,
默认就是系统启动立刻构造

阶段对应方法执行时机执行次数
创建对象构造器web应用启动时1
初始化方法void init(FilterConfig filterConfig)构造完毕1
过滤请求void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)每次请求多次
销毁default void destroy()web应用关闭时1次

六、过滤器链的使用

一个web项目中,可以同时定义多个过滤器,
多个过滤器对同一个资源进行过滤时,工作位置有先后,整体形成一个工作链,
称之为过滤器链

  • 过滤器链中的过滤器的顺序filter-mapping顺序决定
  • 每个过滤器过滤的范围不同,针对同一个资源来说,过滤器链中的过滤器个数可能是不同的
  • 如果某个Filter是使用ServletName进行匹配规则的配置,那么这个Filter执行的优先级要更低

6.1 图解过滤链

1

6.2 测试过滤链

  1. 定义servlet
@WebServlet("/servletH")
public class ServletH extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("servletH service method  invoked");
    }
}
  1. 创建多个Filter
    三个过滤器代码
public class Filter1  implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("filter1 before chain.doFilter code invoked");

        filterChain.doFilter(servletRequest,servletResponse);

        System.out.println("filter1 after  chain.doFilter code invoked");

    }
}


public class Filter2 implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("filter2 before chain.doFilter code invoked");

        filterChain.doFilter(servletRequest,servletResponse);

        System.out.println("filter2 after  chain.doFilter code invoked");

    }
}


public class Filter3 implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("filter3 before chain.doFilter code invoked");

        filterChain.doFilter(servletRequest,servletResponse);

        System.out.println("filter3 after  chain.doFilter code invoked");

    }
}
  1. xml 定义多个filtermapping 标签
   <filter>
        <filter-name>filter1</filter-name>
        <filter-class>com.doug.filters.Filter1</filter-class>
    </filter>

    <filter>
        <filter-name>filter2</filter-name>
        <filter-class>com.doug.filters.Filter2</filter-class>
    </filter>

    <filter>
        <filter-name>filter3</filter-name>
        <filter-class>com.doug.filters.Filter3</filter-class>
    </filter>

    <!--filter-mapping的顺序决定了过滤器的工作顺序-->
    <filter-mapping>
        <filter-name>filter1</filter-name>
        <url-pattern>/servletH</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>filter2</filter-name>
        <url-pattern>/servletH</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>filter3</filter-name>
        <url-pattern>/servletH</url-pattern>
    </filter-mapping>

流程

6.3 工作流程图解

2

七、注解方式配置过滤器

1

7.1 一个比较完整的Filter的XML配置

<!--配置filter,并为filter起别名-->
<filter>
    <filter-name>loggingFilter</filter-name>
    <filter-class>com.doug.filters.LoggingFilter</filter-class>
    <!--配置filter的初始参数-->
    <init-param>
        <param-name>dateTimePattern</param-name>
        <param-value>yyyy-MM-dd HH:mm:ss</param-value>
    </init-param>
</filter>
<!--为别名对应的filter配置要过滤的目标资源-->
<filter-mapping>
    <filter-name>loggingFilter</filter-name>
    <!--通过映射路径确定过滤资源-->
    <url-pattern>/servletA</url-pattern>
    <!--通过后缀名确定过滤资源-->
    <url-pattern>*.html</url-pattern>
    <!--通过servlet别名确定过滤资源-->
    <servlet-name>servletBName</servlet-name>
</filter-mapping>

7.2 将xml配置转换成注解方式实现

@WebFilter(
        filterName = "loggingFilter",
        initParams = {@WebInitParam(name="dateTimePattern",value="yyyy-MM-dd HH:mm:ss")},
        urlPatterns = {"/servletA","*.html"},
        servletNames = {"servletBName"}
)
public class LoggingFilter  implements Filter {
    private SimpleDateFormat dateFormat ;

    /*init初始化方法,通过filterConfig获取初始化参数
    * init方法中,可以用于定义一些其他初始化功能代码
    * */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 获取初始参数
        String dateTimePattern = filterConfig.getInitParameter("dateTimePattern");
        // 初始化成员变量
        dateFormat=new SimpleDateFormat(dateTimePattern);
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 参数父转子
        HttpServletRequest request =(HttpServletRequest)  servletRequest;
        HttpServletResponse  response =(HttpServletResponse)  servletResponse;
        // 拼接日志文本
        String requestURI = request.getRequestURI();
        String time = dateFormat.format(new Date());
        String beforeLogging =requestURI+"在"+time+"被请求了";
        // 打印日志
        System.out.println(beforeLogging);
        // 获取系统时间
        long t1 = System.currentTimeMillis();
        // 放行请求
        filterChain.doFilter(request,response);
        // 获取系统时间
        long t2 = System.currentTimeMillis();
        String afterLogging =requestURI+"在"+time+"的请求耗时:"+(t2-t1)+"毫秒";
        // 打印日志
        System.out.println(afterLogging);

    }
}

总结

过滤器开发中应用的场景 :

  • 日志的记录
  • 性能的分析
  • 乱码的处理
  • 事务的控制
  • 登录的控制
  • 跨域的处理
  • … …

关于tomcat 10 在xml 配置 过滤器 导包是 jakarta 不是 'javax 会报红
但是可以正常使用…
1
1
不想爆红:

  1. 就降低 tomcat版本 为tomcat9
    主要是servlet-api 版本问题

  2. 添加依赖也可以
    因为以上没有使用maven 所以没有pom.xml添加依赖

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

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

相关文章

香港服务器IP段4c和8c的区别及SEO选择建议

随着互联网的快速发展&#xff0c;服务器IP段的选择对于网站SEO优化至关重要。香港服务器IP段4C和8C是两种常见的IP段&#xff0c;它们在SEO优化中具有不同的特点和优势。本文将详细介绍这两种IP段的区别&#xff0c;并给出相应的SEO选择建议。 一、香港服务器IP段4C和8C的区别…

每日coding 2846. 边权重均等查询 236. 二叉树的最近公共祖先 35. 搜索插入位置 215. 数组中的第K个最大元素 2. 两数相加

2846. 边权重均等查询 xs&#xff0c;已放弃&#xff0c;考到直接寄 236. 二叉树的最近公共祖先 236. 二叉树的最近公共祖先 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&…

向量表示在自然语言、知识图谱和图像视觉中的应用

目录 前言1 不同应用的向量表示1.1 自然语言中的向量表示1.2 知识图谱中的向量表示1.3 图像视觉中的向量表示 2 词的向量表示2.1 One-hot encoding的限制2.2 Bag-of-Words模型的不足2.3 Word Embedding的引入2.4. 词的分布式表示与语境关系 3 词向量模型3.1 CBoW&#xff08;Co…

swagger2 和 knife4j 整合

swagger整合knife4j 导入依赖 <dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.2</version></dependency>引入配置 我们自己写一个配置类也好,我这里写…

乐观锁的底层实现以及如何解决ABA问题

什么是乐观锁&#xff1f;乐观锁底层是如何实现的&#xff1f; 乐观锁是一种并发控制的策略。在操作数据的时候&#xff0c;线程读取数据的时候不会进行加锁&#xff0c;先去查询原值&#xff0c;操作的时候比较原来的值&#xff0c;看一下是都被其他线程修改&#xff0c;如果…

OpenHarmony—TypeScript到ArkTS约束说明

对象的属性名必须是合法的标识符 规则&#xff1a;arkts-identifiers-as-prop-names 级别&#xff1a;错误 在ArkTS中&#xff0c;对象的属性名不能为数字或字符串。通过属性名访问类的属性&#xff0c;通过数值索引访问数组元素。 TypeScript var x { name: x, 2: 3 };c…

STM32标准库开发—W25Q64详细介绍

W25Q64简介 Flash编程原理都是只能将1写为0&#xff0c;而不能将0写成1.所以在Flash编程之前&#xff0c;必须将对应的块擦除&#xff0c;而擦除的过程就是将所有位都写为1的过程&#xff0c;块内的所有字节变为0xFF.因此可以说&#xff0c;编程是将相应位写0的过程&#xff0c…

Ubuntu 22.04 安装tomcat

tomcat是常用的Java服务容器,这篇文章我们就来讲讲如何安装它。 更新软件包 首先是更新软件包,这是最常规的操作 sudo apt update 然后是开始安装,不多一会就可以安装好了 sudo apt install tomcat9 然后看一下状态 sudo systemctl status tomcat9 发现虽然启动了,但…

IS-IS:03 ISIS链路状态数据库

一个 OSPF 链路状态数据库是若干条 LSA 的集合。与此相似&#xff0c;一个 IS-IS 链路状态数据库是若干条 LSP 的集合。与 OSPF 链路状态数据库不同&#xff0c; IS-IS 链路状态数据库有 level-1 和 level-2 之分。 在IS-IS 协议中&#xff0c;每一条 LSP 都有一个剩余生存时间…

自学Java的第48,49,50,51天

IO流 应用场景 IO流的分类 文件字节输入流 写法 读取一个字节 读取多个字节 优化&#xff1a; 注意&#xff1a; 读取全部字节 写法 注意&#xff1a; 文件字节输出流 写法 案例&#xff1a; 写法 释放资源的方法 try-catch-finally 写法 try-with-resource 写法 字符流 …

linux内网搭建NFS网络文件系统(rpm)

linux 内网搭建nfs网络文件系统&#xff08;rpm包&#xff09; 前言&#xff1a;一、上传安装包到服务器二、NFS服务端配置三、建立共享目录(服务器端和客户端)四、添加配置共享目录&#xff08;服务器端&#xff09;五、NFS客户端配置六、测试共享服务 前言&#xff1a; 用自…

Type-C平板接口协议芯片介绍,实现单C口充放电功能

在现代平板电脑中&#xff0c;Type-C接口已经成为了一个非常常见的接口类型。相比于传统的USB接口&#xff0c;Type-C接口具有更小的体积、更快的传输速度和更方便的插拔体验。但是&#xff0c;在使用Type-C接口的平板电脑上&#xff0c;如何实现单C口充电、放电和USB2.0数据传…

【iOS ARKit】同时开启前后摄像头BlendShapes

在上一节中已经了解了 iOS ARkit 进行BlendShapes的基本操作&#xff0c;这一小节继续实践同时开启前后摄像头进行人脸捕捉和世界追踪。 iOS设备配备了前后两个摄像头&#xff0c;在运行AR 应用时&#xff0c;需要选择使用哪个摄像头作为图像输人。最常见的AR 体验使用设备后置…

修复WordPress内部服务器错误的步骤及解决方案

WordPress是一款广泛使用的开源内容管理系统&#xff0c;但在使用过程中&#xff0c;可能会遇到各种内部服务器错误。这些错误可能由于多种原因引起&#xff0c;例如插件冲突、文件权限问题、服务器配置不当等。为了帮助您快速解决这些问题&#xff0c;本文将为您提供一套详细的…

行测-言语:2.语句表达

行测-言语&#xff1a;2.语句表达 1. 语句排序题 捆绑就是看两句话是不是讲的同一个内容&#xff0c;相同内容的句子应该相连。 1.1 确定首句 1.1.1 下定义&#xff08;……就是 / 是指&#xff09; A 1.1.2 背景引入&#xff08;随着、近年来、在……大背景 / 环境下&#…

五招搞定找不到vcruntime140.dll无法继续执行此代码问题

在计算机系统或应用程序运行过程中&#xff0c;如果出现“找不到vcruntime140.dll”这一错误提示&#xff0c;可能会引发一系列的问题和影响。vcruntime140.dll是Microsoft Visual C Redistributable的一部分&#xff0c;这是一个至关重要的运行库文件&#xff0c;对于许多基于…

one-stage/two-stage区别

One-stage和Two-stage是目标检测中的两种主要方法&#xff0c;它们在处理速度和准确性上存在显著差异。以下是两者的主要区别&#xff1a; 处理流程&#xff1a;One-stage方法通过卷积神经网络直接提取特征&#xff0c;并预测目标的分类与定位&#xff0c;一步到位&#xff0c…

他凌晨1:30给我开源的游戏加了UI|模拟龙生,挂机冒险

一、前言 新年就要到了&#xff0c;祝大家新的一年&#xff1a;&#x1f432; 龙行龘龘&#xff0c;&#x1f525; 前程朤朤&#xff01; 白泽花了点时间&#xff0c;用 800 行 Go 代码写了一个控制台的小游戏&#xff1a;《模拟龙生》&#xff0c;在游戏中你将模拟一条新生的…

C动态内存那些事

为什么存在动态内存分配&#xff1f; 首先&#xff0c;动态内存分配是计算机中一种重要的内存管理方法&#xff0c;它主要解决了静态内存分配无法灵活应对变化需求的问题。以下是几个存在动态内存分配的原因&#xff1a; 灵活性&#xff1a;动态内存分配允许程序在运行时根据需…

C/C++ LeetCode:跳跃问题

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;算法_仍有未知等待探索的博客-CSDN博客 题目链接&#xff1a;45. 跳跃游戏 II - 力扣&#xff08;LeetCode&#xff09; 一、题目 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元…