过滤器,监听器与拦截器的区别

过滤器,监听器与拦截器的区别

​ 过滤器和监听器不是Spring MVC中的组件,而是Servlet的组件,由Servlet容器来管理。拦截器是Spring MVC中的组件,由Spring容器来管理

​ Servlet过滤器与Spring MVC 拦截器在Web应用中所处的层次如下图所示:
在这里插入图片描述

过滤器Filter

过滤器是Servlet的高级特性之一,是实现Filter接口的Java类。其基本功能就是对Servlet的调用进行干预,在Servlet请求和响应的过程中增加一些特定的功能。

应用场景

在过滤器中修改字符编码(CharacterEncodingFilter)、在过滤器中修改HttpServletRequest的一些参数,如:过滤低俗文字、危险字符、敏感词过滤、响应信息压缩、控制权限、控制转向、做一些业务逻辑判断等

工作原理

使用Filter完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。

  1. 当服务器启动,会创建Filter对象,并调用init方法,只调用一次。

  2. 当访问资源,路径与Filter的拦截路径匹配,会执行Filter中的doFilter方法,

  3. 当服务器关闭时,会调用Filter的destroy方法来进行销毁操作。

Filter接口

通过看Filter接口代码,其有三个方法:

public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {
    }
 
    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
 
    default void destroy() {
    }
}
  • init(FilterConfig conf)方法:用于执行过滤器的初始化工作,web容器会在web项目启动时自动调用该方法。

  • doFilter(ServletRequest request,SerlvetResponse response,FilterChain chain)方法:当请求和响应被过滤器拦截后,都会交给doFilter来处理:其中两个参数分别是被拦截request和response对象,可以使用chain的doFliter方法来放行。

  • destroy()方法:用于释放关闭Filter对象打开的资源,在web项目关闭时,由web容器自动调用该方法。

开发一个Filter

开发一个过滤器比较简单,第一步实现Filter接口,第二步配置过滤器
实现Filter接口:

import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
 
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
 
@Component
@WebFilter(filterName = "myFilter",urlPatterns = {"/*"})
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
 
        //获取filter名字
        String filterName = filterConfig.getFilterName();
 
        //获取filter里配置的init-param配置指定参数的值,如果参数不存在,则返回 null
        String email = filterConfig.getInitParameter("email");
 
        //获取filter里配置的init-param配置所有参数值,如果过滤器没有初始化参数,则返回一个空的 Enumeration
        Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();
 
        //返回对调用者在其中执行操作的 ServletContext 的引用。
        ServletContext servletContext = filterConfig.getServletContext();
    }
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
 
        //统一编码处理
        httpRequest.setCharacterEncoding("UTF-8");
        httpResponse.setContentType("text/html;charset=UTF-8");
 
        //添加name属性
        httpRequest.setAttribute("name", "tom");
 
        //获取请求中的所有cookie
        Cookie[] cookies = httpRequest.getCookies();
        if (cookies != null) {
            StringBuilder sb = new StringBuilder();
            for (Cookie cookie : cookies) {
                String cookieName = cookie.getName();
                String cookieValue = cookie.getValue();
                //设置cookie的相关属性
                ResponseCookie lastCookie = ResponseCookie.from(cookieName, cookieValue).httpOnly(true).sameSite("Lax").build();
                httpResponse.addHeader(HttpHeaders.SET_COOKIE, lastCookie.toString());
            }
 
            filterChain.doFilter(httpRequest, httpResponse);
        }
    }
 
    @Override
    public void destroy() {
 
    }
}

配置Filter:
(1)在web.xml中配置

<filter>
    <filter-name>myFilter</filter-name>
    <filter-class>com.lsl.mylsl.filter.MyFilter</filter-class>
    <init-param>
        <param-name>email</param-name>
        <param-value>15***011@qq.com</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>myFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter>配置

fliter-name:指为过滤器的名字

filter-class:过滤器的完整类名

init-param:用于为过滤器指定初始化参数,它的子元素指定参数的名字

<filter-mapping>配置

filter-name:你在<fliter>中声明的filter-name

url-patten:设置 filter 所拦截的请求路径(过滤器关联的URL样式)

(2)注解配置

@WebFilter(filterName = "myFilter",urlPatterns = {"/*"})

(3)配置类配置

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class MyFilterConfig {
 
    @Bean
    public FilterRegistrationBean myFilter(){
        FilterRegistrationBean fb = new FilterRegistrationBean();
        //设置filter启动顺序
        fb.setOrder(1);
        fb.setFilter(new MyFilter());
        fb.addInitParameter("email","15***11@qq.com");
        //设置拦截请求规则,这里拦截所有请求
        fb.addUrlPatterns("/*");
        return fb;
    }
}

三种Filter配置的优缺点:

    第一种xml的配置需要在xml中写配置,但是现在大部分是springboot项目开发,都是重注解轻配置,现在不怎么使用了。如果xml中配置了多个filter,那么按上下先后顺序依次起作用。

    第二种注解配置,写法比较简单,但是有一个缺点,多个filter没法控制先后顺序。如果想用这个注解,但是还想控制filter的先后顺序,网上有个说法,就是按filter的名字首字母顺序来确定先后顺序,比如有多个filter的名字是AdminFilter和UserFilter,那么就是前者先生效后者后生效。

    第三种配置类配置,我个人比较倾向于这个(当然如果就是一个简单filter,用注解最简单方便),有xml配置的所有功能。可以定义启动顺序,初始化参数等。

拦截器Interceptor

Spring MVC中的拦截器( Interceptor)类似于Servlet中的过滤器( Filter ),它主要用于拦截用户请求并作出相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。

工作原理

一个拦截器,只有 preHandle 方法返回 true , postHandle 、 afterCompletion 才有可能被执行;如果 preHandle 方法返回 false ,则该拦截器的 postHandle 、 afterCompletion 必然不会被执行。拦截器不是Filter,却实现了Filter的功能,其原理在于:

    所有的拦截器 (Interceptor) 和处理器 (Handler) 都注册在 HandlerMapping 中。

	Spring MVC 中所有的请求都是由 DispatcherServlet 分发的。当请求进入 DispatcherServlet.doDispatch() 时候,首先会得到处理该请求的 Handler (即 Controller 中对应的方法)以及所有拦截该请求的拦截器。拦截器就是在这里被调用开始工作的。

应用场景

拦截器本质上是面向切面编程(AOP),符合横切关注点的功能都可以放在拦截器中来实现,主要的应用场景包括:

  • 登录验证,判断用户是否登录。
  • 权限验证,判断用户是否有权限访问资源,如校验token
  • 日志记录,记录请求操作日志(用户Ip,访问时间等),以便统计请求访问量。
  • 处理Cookie、本地化、国际化、主题等。
  • 性能监控,监控请求处理时长等。

拦截器执行顺序

在这里插入图片描述
在这里插入图片描述

拦截器接口HandlerInterceptor

package org.springframework.web.servlet;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
 
public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }
 
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }
 
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

从代码可以看出,拦截器接口有三个方法,分别的作用是:

preHandle方法叫做预处理方法,本方法在控制器方法(MyController的方法)之前执 行,用户的请求最先到达此方法,在这个方法中可以获取请求的信息,验证请求是否符合要求。以验证用户是否登录,验证用户是否有权限访问某个链接地址(url)。如果返回true则放行,返回false则拦截。

postHandle方法叫做后处理方法。在controller中的方法之后执行的。能够获取到处理器方法的返回值 mv,可以修改mv中的数据和视图。可以影响到最后的执行结果。主要是对原来的执行结果做二次修正

afterCompletion方法最后执行的方法,在页面渲染之后执行。在请求处理完成后执行的,框架中规定是当你的视图处理完成后,对视图进行了forword。就任务请求处理完成。一般做资源回收工作的,程序请求过程中创建了一些对象。在这里可以删除,吧占用的内存回收

开发一个拦截器Interceptor

开发一个拦截器需要2步,第一步实现HandlerInterceptor接口来定义一个拦截器,第二步就是配置拦截器了

(1)定义一个拦截器:

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
 
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
 
public class MyInterceptor implements HandlerInterceptor {
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        
        //在拦截的请求了添加属性,在对应请求的controller中的request中就可以获取该参数了
        //比如String userName = (String)request.getAttribute("userName");
        request.setAttribute("userName","lsl");
        
        //获取cookie
        Cookie[] cookies = request.getCookies();
 
        //设置header属性
        response.addHeader("SameSite","Lax");
        
        //添加cookie
        Cookie cookie = new Cookie("name","lsl");
        response.addCookie(cookie);
        
        return true;
    }
 
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
 
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

(2)配置拦截器:

package com.lsl.mylsl.interceptor;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
/**
 * 拦截器配置类
 */
@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {
 
    /**
     * 配置拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(myInterceptor())
                .addPathPatterns("/api/lsl/**")//需要拦截的请求
                .addPathPatterns("/api/mjx/**")//需要拦截的请求
                .excludePathPatterns("/api/debug/**")//不拦截的请求
                .excludePathPatterns("api/lsl/getName");//不拦截的请求
    }
 
    /**
     * 注入拦截器到spring容器
     * @return
     */
    @Bean
    public MyInterceptor myInterceptor(){
        return new MyInterceptor();
    }
}

过滤器与拦截器工作流程

在这里插入图片描述

过滤器和拦截器区别

运行的顺序不同:

过滤器是Servlet容器接收到请求后,在Servlet被调用之前运行的,而拦截器则是在Servlet被调用之后,但是在响应发送到客户端之前来运行的
在这里插入图片描述

配置方式不同:

过滤器是在web.xml里面进行配置的,拦截器是在Spring的配置文件中去进行配置

依赖的对象不同:

过滤器依赖于Servlet容器,而拦截器不依赖与Servlet容器

操作的对象不同:

过滤器中只能对request和response进行操作,拦截器可以对request,response,handler,modelAndView,execption进行操作,相当于拦截器多了对于Spring MVC生态下组件的一个操作能力
在这里插入图片描述

通俗理解:

(1)过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。(理解:就是一堆字母中取一个B)
**(2)拦截器(Interceptor)**在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。(理解:就是一堆字母中,干预它,通过验证的少点,顺便干点别的东西

转发和重定向区别

在这里插入图片描述

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

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

相关文章

代码随想录算法训练营day60

文章目录 Day60 柱状图中最大的矩形题目思路代码 Day60 柱状图中最大的矩形 84. 柱状图中最大的矩形 - 力扣&#xff08;LeetCode&#xff09; 题目 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图…

相关搜索量激增10000%!“芭比周边”产品火爆亚马逊!

据外媒报道&#xff0c;芭比娃娃是今年夏天最热的话题。今年7月份&#xff0c;“芭比娃娃”是亚马逊上搜索最多的词。第二季度&#xff0c;Shopify上的芭比娃娃销量激增了56%。知名玩具制造商美泰&#xff08;Mattel&#xff09;预计&#xff0c;受电影的推动&#xff0c;在未来…

数字员工助力农行安全生产数字化转型应用实践

党的二十大指出&#xff0c;“以数字中国建设助力中国式现代化&#xff0c;加快建设网络强国、数字中国”&#xff0c;2022年1月发布《“十四五”数字经济发展规划》提出&#xff0c;加强类人智能、自然交互与虚拟现实等技术研究。近年来&#xff0c;各大银行纷纷推出自己的数字…

跨平台开发框架Qt:面向对象、丰富API

Qt是一个跨平台C图形用户界面应用程序开发框架&#xff0c;它具有以下三大优势&#xff1a; 优良的跨平台特性&#xff1a;Qt支持多种操作系统&#xff0c;包括Windows、Linux、Solaris、HP-UX、Irix、FreeBSD等&#xff0c;使开发人员能够在不同平台上开发和部署应用程序&…

HEIF—— 1、vs2017编译Nokia - heif源码

HEIF(高效图像文件格式) 一种图片有损压缩格式,它的后缀名通常为".heic"或".heif"。 HEIF 是由运动图像专家组 (MPEG) 标准化的视觉媒体容器格式,用于存储和共享图像和图像序列。它基于著名的 ISO 基本媒体文件格式 (ISOBMFF) 标准。HEIF读写器引擎…

为生成式AI提速,亚马逊云科技Amazon EC2 P5满足GPU需求

生成式AI&#xff08;Generative AI&#xff09;已经成为全球范围内的一个重要趋势&#xff0c;得到越来越多企业和研究机构的关注和应用。纽约时间7月26日&#xff0c;亚马逊云科技数据库、数据分析和机器学习全球副总裁Swami Sivasubramanian在亚马逊云科技举办的纽约峰会上更…

无涯教程-Perl - 面向对象

Perl中的面向对象概念很大程度上基于引用以及匿名数组和哈希。让我们开始学习面向对象Perl的基本概念。 定义类 在Perl中定义一个类非常简单。类以最简单的形式对应于Perl软件包。要在Perl中创建一个类&#xff0c;我们首先构建一个包。 Perl软件包在Perl程序中提供了一个单…

python与深度学习(十四):CNN和IKUN模型二

目录 1. 说明2. IKUN模型的CNN模型测试2.1 导入相关库2.2 加载模型2.3 设置保存图片的路径2.4 加载图片2.5 图片预处理2.6 对图片进行预测2.7 显示图片 3. 完整代码和显示结果4. 多张图片进行测试的完整代码以及结果 1. 说明 本篇文章是对上篇文章IKUN模型训练的模型进行测试。…

基于Spring Boot的在线视频教育培训网站设计与实现(Java+spring boot+MySQL)

获取源码或者论文请私信博主 演示视频&#xff1a; 基于Spring Boot的在线视频教育培训网站设计与实现&#xff08;Javaspring bootMySQL&#xff09; 使用技术&#xff1a; 前端&#xff1a;html css javascript jQuery ajax thymeleaf 微信小程序 后端&#xff1a;Java sp…

【Java可执行命令】(二十)堆转储快照文件及堆信息查看工具 jmap:生成多格式堆转储文件、打印类加载器信息及查看共享对象映射信息 ~

Java可执行命令之jmap 1️⃣ 概念2️⃣ 优势和缺点3️⃣ 使用3.1 语法格式3.2 生成堆转储文件3.3 执行jmap命令查看内存使用情况3.4 执行jmap命令打印对象统计信息 4️⃣ 应用场景&#x1f33e; 总结 1️⃣ 概念 jmap 是 Java Development Kit&#xff08;JDK&#xff09;自带…

开源数据库Mysql_DBA运维实战 (部署服务篇)

前言❀ 1.数据库能做什么 2.数据库的由来 数据库的系统结构❀ 1.数据库系统DBS 2.SQL语言(结构化查询语言) 3.数据访问技术 部署Mysql❀ 1.通过rpm安装部署Mysql 2.通过源码包安装部署Mysql 前言❀ 1.数据库能做什么 a.不论是淘宝&#xff0c;吃鸡&#xff0c;爱奇艺…

挖掘Java集合:深入探索List接口与HashSet

文章目录 引言LinkedList&#xff1a;双向链表的实现构造方法LinkedList中的常用方法HashSet&#xff1a;无序且唯一的集合HashSet的实现方式LinkedHashSet&#xff1a;有序且唯一可变长度参数结论 引言 在广阔的Java编程领域中&#xff0c;集合就如同宝库&#xff0c;提供了多…

C语言 用数组名作函数参数

当用数组名作函数参数时&#xff0c;如果形参数组中各元素的值发生变化&#xff0c;实参数组元素的值随之变化。 1.数组元素做实参的情况&#xff1a; 如果已经定义一个函数&#xff0c;其原型为 void swap(int x,int y);假设函数的作用是将两个形参&#xff08;x,y&#xf…

ArcGIS制作带蒙版的遥感影像地图

这次文章我们来介绍一下&#xff0c;如何通过一个系统的步骤完成ArcGIS制作带蒙版的遥感影像地图。 主要的步骤包括&#xff1a; 1 添加行政区划数据 2 导出兴趣去乡镇矢量范围 3 添加遥感影像底图 4 制作蒙版 5 利用自动完成面制作蒙版 6 标注乡镇带晕渲文字 7 …

01《Detecting Software Attacks on Embedded IoT Devices》随笔

2023.08.05 今天读的是一篇博士论文 论文传送门&#xff1a;Detecting Software Attacks on Embedded IoT Devices 看了很长时间&#xff0c;发现有一百多页&#xff0c;没看完&#xff0c;没看到怎么实现的。 摘要 联网设备的增加使得嵌入式设备成为各种网络攻击的诱人目标&…

Cloud Studio实战——热门视频Top100爬虫应用开发

最近Cloud Studio非常火&#xff0c;我也去试了一下&#xff0c;感觉真的非常方便&#xff01;我就以Python爬取B站各区排名前一百的视频&#xff0c;并作可视化来给大家分享一下Cloud Studio&#xff01;应用链接&#xff1a;Cloud Studio实战——B站热门视频Top100爬虫应用开…

lwip不同的socket分别作为监听和客户端连接

在LWIP中&#xff0c;一个网络设备&#xff08;如以太网卡&#xff09;可以创建多个socket&#xff0c;用于处理不同的网络连接。一般&#xff0c;你可以创建一个socket用于监听&#xff08;listen&#xff09;连接&#xff0c;另一个socket用于主动发起&#xff08;connect&am…

华为OD机试(含B卷)真题2023 算法分类版,58道20个算法分类,如果距离机考时间不多了,就看这个吧,稳稳的

目录 一、数据结构1、线性表2、优先队列3、滑动窗口4、二叉树5、并查集6、栈 二、算法1、基础算法2、字符串3、图4、动态规划5、数学 三、漫画算法2&#xff1a;小灰的算法进阶参与方式 很多小伙伴问我&#xff0c;华为OD机试算法题太多了&#xff0c;知识点繁杂&#xff0c;如…

jenkins使用gitlab标签发布

关于jenkins git parameter使用gitlab标签发布和分支发布的用法 手动配置的我就不说了&#xff0c;点点点就行&#xff0c;主要是说一下在pipeline里如何使用 通过分支拉取gitlab仓库代码 pipeline {agent anyenvironment {}parameters {gitParameter(branch: , branchFilte…

ASP.NET Core学习路线图

说明 1. 先决条件 - [C#](https://www.pluralsight.com/paths/csharp) - [Entity Framework](https://www.pluralsight.com/search?qentity%20framework%20core) - [ASP.NET Core](https://www.pluralsight.com/search?qasp.net%20core) - SQL基础知识 2. 通用开发技能 -…