04-过滤器和拦截器有什么区别?【Java面试题总结】

news2024/11/29 10:58:30

过滤器和拦截器有什么区别?

  • 运行顺序不同:过滤器是在 Servlet 容器接收到请求之后,但在 Servlet被调用之前运行的;而拦截器则是在Servlet 被调用之后,但在响应被发送到客户端之前运行的。

image-20230828220547278

  • 过滤器Filter 依赖于 Servlet 容器,属于Servlet规范的一部分,可以在web.xml中进行配置或者使用注解(如@WebFilter)进行配置;而 拦截器Interceptor 不依赖于 Servlet 容器,一般可以在Spring配置文件中进行配置或使用注解(如@Interceptor)来配置拦截器;
  • Filter的执行由Servlet容器回调完成,而拦截器通常通过动态代理的方式来执行;
  • Filter的生命周期由Servlet容器管理,而拦截器则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用会更方便。

知识扩展

过滤器的使用场景:

  • 身份验证:对请求进行身份验证,检查用户是否登录或具有访问权限。
  • 请求日志记录:记录请求的详细信息,如URL、参数、请求时间等。
  • 数据加工:对请求或响应的数据进行处理,例如压缩、解密、加密等。
  • 编码转换:对请求和响应的编码进行转换,以适应不同的字符编码要求。

简单的过滤器代码案例,用于记录请求的访问日志、请求时间记录:

新建LoggingFilter实现Filter类,获取request中的方法、URL,在过滤器链执行完成前后分别记录时间来获取请求处理时间

package com.springboot.learn.filter;

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

/**
 * <p>Class: LoggingFilter</p>
 * <p>Description: 日志Filter</p>
 *
 * @author zhouyi
 * @version 1.0
 * @date 2023/8/28
 */
public class LoggingFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化方法
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        long start = System.nanoTime();
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();
        String method = httpRequest.getMethod();
        System.out.println("Request received - Method: " + method + ", URI: " + requestURI + " ,useTime:" + (System.nanoTime() - start));
        // 继续执行请求链
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // 销毁方法
    }
}

在Servlet 中,我们需要在web.xml中配置过滤器,在SpringBoot中没有web.xml的概念,我们通过其他方式配置,如下

方式一:通过FilterRegistrationBean来配置

FilterRegistrationBean是Spring Boot提供的一个用于注册和配置过滤器的辅助类。它允许你以编程的方式定义过滤器,并将其注册到Servlet容器中。FilterRegistrationBean提供了一系列方法来配置过滤器的属性,包括过滤器实例、URL匹配模式、过滤器执行顺序、Dispatcher类型等。

通过使用FilterRegistrationBean,你可以更灵活地配置过滤器,并且不依赖于传统的基于web.xml配置的方式。你可以将FilterRegistrationBean作为一个Spring Bean进行管理,可以通过注入方式获取并设置过滤器的属性

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean registFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new LoggingFilter());
        registration.addUrlPatterns("/*");
        registration.setName("LoggingFilter");
        registration.setOrder(1);
        return registration;
    }
}

常见用法

  • setFilter(Filter filter):设置过滤器实例。
  • addUrlPatterns(String... urlPatterns):设置URL匹配模式,指定过滤器要拦截的URL路径模式。
  • setOrder(int order):设置过滤器的执行顺序,数字越小越先执行。
  • setDispatcherTypes(DispatcherType... dispatcherTypes):设置过滤器的Dispatcher类型,指定过滤器要拦截的请求类型,如REQUEST、FORWARD、INCLUDE、ASYNC等。
  • 其他方法还包括设置过滤器名称、初始化参数、是否启用异步支持等。

功能验证

@RestController
@RequestMapping("/test")
public class TestController {

    @GetMapping("/user")
    public String queryUser(String id) {
        return id;
    }
}

访问接口请求,发现控制台已打印出我们想要的信息。

image-20230829090935672

image-20230829091007295

方式二:通过@WebFilter注解实现

在过滤器中添加注解 @WebFilter进行配置,同样可以设置url匹配模式,过滤器名称等。

/**
 * <p>Class: LoggingFilter2</p>
 * <p>Description: 日志Filter</p>
 *
 * @author zhouyi
 * @version 1.0
 * @date 2023/8/28
 */
@WebFilter(urlPatterns = "/*", filterName = "LoggingFilter2")
public class LoggingFilter2 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化方法
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        long start = System.nanoTime();
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();
        String method = httpRequest.getMethod();
        System.out.println("【LoggingFilter2】Request received - Method: " + method + ", URI: " + requestURI + " ,useTime:" + (System.nanoTime() - start));
        // 继续执行请求链
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // 销毁方法
    }
}

注意,@WebFilter这个注解是Servlet3.0的规范,并不是Spring boot提供的。除了这个注解以外,我们还需在配置类中加另外一个注解:@ServletComponetScan,指定扫描的包,放在启动类上面。
在这里插入图片描述

访问请求,发现过滤器的两种配置方式均已实现

image-20230829093337412

拦截器的使用场景:

  • 权限检查:在请求处理方法执行之前,检查用户是否具有执行该操作的权限。
  • 日志记录:记录请求的详细信息、处理时间等,用于跟踪和监控。
  • 数据转换:在请求处理方法执行前后,对请求或响应的数据进行转换和处理。
  • 异常处理:捕获请求处理方法中抛出的异常,并进行相应的处理和响应。

在SpringBoot中实现拦截器有两种方式

(1)实现HandlerInterceptor接口,并实现相应的方法

(2)继承HandlerInterceptorAdapter类,并重写里面的方法

方式一:实现HandlerInterceptor接口

public class LoggingInterceptor implements HandlerInterceptor {

    long start = System.nanoTime();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 在请求处理方法执行之前的预处理逻辑
        start = System.nanoTime();
        // 返回 true 表示继续执行后续的拦截器和请求处理方法,返回 false 表示终止执行
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 在请求处理方法执行之后的后处理逻辑
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();
        String method = httpRequest.getMethod();
        System.out.println("【HandlerInterceptor】Request received - Method: " + method + ", URI: " + requestURI + " ,useTime:" + (System.nanoTime() - start));
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 在视图渲染完成后的清理逻辑
    }
}

配置拦截器

@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 可添加多个,/**是对所有的请求都做拦截
        registry.addInterceptor(new LoggingInterceptor()).addPathPatterns("/**").excludePathPatterns("/login", "/register");
    }
}

运行时发现拦截器也生效

image-20230829131735838

image-20230829132120906

方式二:继承HandlerInterceptorAdapter

public class LoggingInterceptor2 extends HandlerInterceptorAdapter {

    long start = System.nanoTime();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 在请求处理方法执行之前的预处理逻辑
        start = System.nanoTime();
        // 返回 true 表示继续执行后续的拦截器和请求处理方法,返回 false 表示终止执行
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 在请求处理方法执行之后的后处理逻辑
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();
        String method = httpRequest.getMethod();
        System.out.println("【LoggingInterceptor2】Request received - Method: " + method + ", URI: " + requestURI + " ,useTime:" + (System.nanoTime() - start));
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 在视图渲染完成后的清理逻辑
    }
}

通过继承HandlerInterceptorAdapter类来实现拦截器的方式,也需要配置拦截器。和方式一的配置是一样的

@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 可添加多个,/**是对所有的请求都做拦截
        registry.addInterceptor(new LoggingInterceptor()).addPathPatterns("/**").excludePathPatterns("/login", "/register");
        registry.addInterceptor(new LoggingInterceptor2()).addPathPatterns("/**").excludePathPatterns("/login", "/register");
    }
}

运行时发现,两种方式的拦截器均已实现。
在这里插入图片描述
image-20230829133146147

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

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

相关文章

【优先级队列】

文章目录 基于无序数组实现基于有序数组的实现基于堆的实现合并多个有序链表-力扣 23 题 基于无序数组实现 要点 入队保持顺序&#xff0c;在数组尾部插入即可出队前找到优先级最高的出队&#xff0c;相当于一次选择排序 基于有序数组的实现 要点 入队后排好序&#xff0c…

企业架构LNMP学习笔记8

1、 运维人员需要考虑安全性、稳定性。 安装&#xff1a; 解压进入到目录&#xff1a; shell > tar zxf php-7.2.12.tar.gz shell > cd php-7.2.12 安装依赖软件&#xff1a; yum -y install libxml2-devel libjpeg-devel libpng-devel freetype-devel curl-devel op…

企业应用系统 PHP项目支持管理系统Dreamweaver开发mysql数据库web结构php编程计算机网页

一、源码特点 PHP 项目支持管理系统是一套完善的web设计系统 应用于企业项目管理&#xff0c;从企业内部的各个业务环境总体掌握&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 php项目支撑管理系统2 二、功能介绍 (1)权限管理&#xff1…

Android 使用OpenCV实现实时人脸识别,并绘制到SurfaceView上

1. 前言 上篇文章 我们已经通过一个简单的例子&#xff0c;在Android Studio中接入了OpenCV。 之前我们也 在Visual Studio上&#xff0c;使用OpenCV实现人脸识别 中实现了人脸识别的效果。 接着&#xff0c;我们就可以将OpenCV的人脸识别效果移植到Android中了。 1.1 环境说…

一个基于YAPI接口生产代码的开源工具

前后端分离的开发模式是一种趋势&#xff0c;但如果缺少好的开发工具跟管理模式&#xff0c;会使得前后端开发人员相互等待&#xff0c;扯皮等问题。从而影响项目的交付进度。 通过实践摸索&#xff0c;YAPI是一款很适合前后端分离开发的协助工具。它以项目为维度&#xff0c;可…

arduino仿真 SimulIDE1.0仿真器

SimulIDE 是一个开源的电子电路模拟器&#xff0c;支持模拟各种电子元器件的行为&#xff0c;可以帮助电子工程师和爱好者进行电路设计和测试。以下是 SimulIDE 的安装和使用说明&#xff1a; 安装 SimulIDE SimulIDE 可以在 Windows、Linux 和 Mac OS X 等操作系统上安装。您…

取证工具prodiscover的基本操作

前言提醒 取证工具ProDiscover在网上讲解操作的文章实在太少&#xff0c;一是prodiscover是用于磁盘取证的工具&#xff0c;本身比较小众比不上其他的编程软件能用到的地方多&#xff0c;二是这个工具是用来恢复提取磁盘中被删除的文件&#xff0c;是比较隐晦的软件。 需要注…

CSAPP的Lab学习——AttackLab

文章目录 前言一、阶段一攻击二、阶段二攻击三、阶段三攻击四、阶段四攻击五、阶段五攻击总结 前言 一个本硕双非的小菜鸡&#xff0c;备战24年秋招。刚刚看完CSAPP&#xff0c;真是一本神书啊&#xff01;遂尝试将它的Lab实现&#xff0c;并记录期间心酸历程。 代码下载 官方…

【AWS实验】 配置中转网关及对等连接

文章目录 实验概览目标实验环境任务 1&#xff1a;查看网络拓扑并创建基准任务 2&#xff1a;创建中转网关任务 3&#xff1a;创建中转网关挂载任务 4&#xff1a;创建中转网关路由表任务 4.1&#xff1a;创建路由表关联任务 4.2&#xff1a;创建路由传播 任务 5&#xff1a;更…

velodyne_msgs/VelodyneScan数据流消息转化为sensor_msgs/PointCloud2点云帧消息

目的 在查看一个开源数据集时&#xff0c;点云信息格式为velodyne_msgs/VelodyneScan&#xff0c;无法在rviz中显示&#xff0c;需要转换为sensor_msgs/PointCloud2。 软件版本 Ubuntu20.04 Noetic 激光雷达型号 32线激光雷达velodyne 32E 参考方法 ROS Noetic velodyn…

【DP】CF Edu 21 E

Problem - E - Codeforces 题意&#xff1a; 思路&#xff1a; 就是一个 N为1e5&#xff0c;M为3e5的背包问题&#xff0c;不过特殊条件是 w < 3 我们去从最简单的情况开始考虑 当只有w 1的物品和w 2的物品时&#xff0c;考虑贪心地把物品按价值排序&#xff0c;然后选…

Python数据分析实战-判断一组序列(列表)的变化趋势(附源码和实现效果)

实现功能 判断一组序列&#xff08;列表&#xff09;的变化趋势 实现代码 from sklearn.linear_model import LinearRegression import numpy as np # 计算相邻两个数之间的差值的均值&#xff0c;并判断变化趋势。 def trend(lst):diff [lst[i1] - lst[i] for i in range(…

Python之循环-三元表达式

Python之循环-三元表达式 continue, break break 结束循环 break语句可以提前结束循环。然后执行循环之后的语句。 continue continue用于跳出当前循环&#xff0c;执行下一次循环。 示例&#xff1a; 如下示例中是一个for循环&#xff0c;range(10)&#xff0c;然后遍历r…

【高效编程技巧】编程菜鸟和编程大佬的差距究竟在哪里?

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《高效编程技巧》《C语言进阶》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 &#x1f4cb; 前言1.如何写出好的代码&#xff1f;1.2 如何分析一个函数写的怎么样 2. 代码板式的重要性2.1 代码…

【C++】学习STL中的stack和queue

❤️前言 今天这篇博客的内容主要关于STL中的stack、queue和priority_queue三种容器。 正文 stack和queue的使用方式非常简单&#xff0c;我们只要根据之前学习数据结构的经验和文档介绍就可以轻松上手。于是我们直接开始对它们的模拟实现。 stack和queue的模拟实现 stack和q…

redis实战-实现优惠券秒杀解决超卖问题

全局唯一ID 唯一ID的必要性 每个店铺都可以发布优惠券&#xff1a; 当用户抢购时&#xff0c;就会生成订单并保存到tb_voucher_order这张表中&#xff0c;而订单表如果使用数据库自增ID就存在一些问题&#xff1a; id的规律性太明显&#xff0c;容易被用户根据id的间隔来猜测…

不同路径【动态规划】

不同路径 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&#xff1f;…

python 美国总统身高统计与分析

美国总统身高统计与分析 1.安装依赖2.下载数据集3.数据处理4.结果展示 1.安装依赖 pip install pandas pip install numpy pip install matplotlib2.下载数据集 链接&#xff1a;https://pan.baidu.com/s/1aZLtkLyvQvRLb9tJ-B1krA 提取码&#xff1a;thms –来自百度网盘超级…

Spring Cloud 系列之OpenFeign:(8)链路追踪续

传送门 Spring Cloud Alibaba系列之nacos&#xff1a;(1)安装 Spring Cloud Alibaba系列之nacos&#xff1a;(2)单机模式支持mysql Spring Cloud Alibaba系列之nacos&#xff1a;(3)服务注册发现 Spring Cloud 系列之OpenFeign&#xff1a;(4)集成OpenFeign Spring Cloud …

无涯教程-JavaScript - CUBEMEMBERPROPERTY函数

描述 CUBEMEMBERPROPERTY函数从多维数据集返回成员属性的值。使用此函数可以验证多维数据集中是否存在成员名称,并返回该成员的指定属性。 语法 CUBEMEMBERPROPERTY (connection, member_expression, property)争论 Argument描述Required/OptionalconnectionName of the co…