2023.12.3 关于 Spring Boot 拦截器 和 过滤器

目录

引言

Spring 拦截器实现

实例理解

Spring 过滤器实现

实例理解

拦截器和过滤器的区别 

出身不同

触发时机不同

底层实现不同

支持的项目类型不同

使用场景不同


引言

  • 原生 Spring AOP 实现统一拦截有两个难点
  • 难点一:定义拦截规则表达式 
  • 难点二:在切面中获取到 HttpSession

Spring 拦截器实现

  • 为了解决原生 Spring AOP 实现统一拦截的难点
  • Spring 提供了具体的实现拦截器 HandlerInterceptor
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class TestInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截器:执行 preHandle 方法。");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("拦截器:执行 postHandle 方法。");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("拦截器:执行 afterCompletion 方法。");
    }
}
  • preHandle 在请求方法执行前被调用,也就是在调用目标方法之前被调用
  • postHandle 在请求方法执行后被调用,但是会在 DispatcherServlet 进行渲染视图之前被执行
  • afterCompletion 会在整个请求结束之后再执行,也就是在 DispatcherServlet 渲染了对应的视图之后再执行

实例理解

  • 此处我们想要实现 用户登录验证 的判断
步骤一
  • 创建自定义拦截器,此处创建了一个 LoginInterceptor 类实现 HandlerInterceptor 接口
  • 用户登录验证 属于执行目标方法之前就应对其进行判断,所以此处重写 preHandler 方法,并在方法中编写相应的业务代码
package com.example.demo.component;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/*
* 自定义拦截器
* */
@Component
public class LoginInterceptor implements HandlerInterceptor {
    /*
    * 调用目标方法之前执行的方法
    * 此方法返回 boolean 类型的值 如果返回的为 true 表示拦截器 验证成功 继续走后续的流程
    * 如果返回 false 则表示拦截器 验证未通过 后续的流程和目标方法不要执行了
    * */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        用户登录判断业务
        HttpSession session  = request.getSession(false);
        if(session != null && session.getAttribute("session_userinfo") != null) {
//            用户已经登录
            return true;
        }
//        到达此处说明用户未登录
//        我们可以直接重定向到登录页面
//        response.sendRedirect("/login.html");
//        此处我们未写登录页面,所以我们直接返回一个 401 表示客户端错误
        response.setStatus(401);
        return false;
    }
}

步骤二
  • 将自定义拦截器加入到系统配置
  • 设置拦截规则
package com.example.demo.config;

import com.example.demo.component.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
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 MyConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")//拦截所有的 url  /* 代表一级 /** 代表多级
                .excludePathPatterns("/user/login") //排除 url /user/login 不拦截
                .excludePathPatterns("/user/register") 
                .excludePathPatterns("/css/**") //排除 css 文件夹下的所有文件
                .excludePathPatterns("/js/**") //排除 js 文件夹下的所有文件
                .excludePathPatterns("/image/**") //排除 image 文件夹下的所有文件
        ;
    }
}

  • 设置完拦截器后的交互流程图

Spring 过滤器实现

  • 过滤器的实现可以使用 Servlet 3.0 提供的 @WebFilter 注解
  • 配置过滤的 URL 规则、实现 Filter 接口 、重写接口中的 doFilter 方法
package com.example.demo.component;

import org.springframework.stereotype.Component;

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

@Component
@WebFilter(urlPatterns = "/*")
public class TestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器:执行 init 方法");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("过滤器:开始执行 doFilter 方法");
//        请求放行
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("过滤器:结束执行 doFilter 方法");
    }

    @Override
    public void destroy() {
        System.out.println("过滤器:执行 destroy 方法");
    }
}

  • init  在容器启动时会被调用,整个程序运行期只会被调用一次,用于实现 Filter 对象的初始化
  • doFilter 具体过滤功能的实现,通过此方法对请求进行过滤处理
  • destory 用于 Filter 销毁前完成相关资源的回收工作

注意:

  • filterChain.doFilter(servletRequest,servletResponse); (请求放行)
  • 该行代码的作用是将请求传递给过滤器链中的下一个过滤器或目标资源(执行下一个流程)
  • 如果没有这行代码,那么请求将会在当前的过滤器中停止,不会继续向下传递

实例理解

  • 此处我们想实现 敏感词过滤
package com.example.demo.component;

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

@WebFilter(urlPatterns = "/*")
public class SensitiveWordsFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器:执行 init 方法");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("过滤器:开始执行 doFilter 方法");
        // 获取用户提交的信息
        String message = servletRequest.getParameter("message");
        // 敏感词库
        String[] sensitiveWords = {"敏感词1", "敏感词2"};
        for (String sensitiveWord : sensitiveWords) {
            if (message.contains(sensitiveWord)) {
                message = message.replace(sensitiveWord, "*");
            }
        }
        servletRequest.setAttribute("message", message);
        // 请求放行
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("过滤器:结束执行 doFilter 方法");
    }

    @Override
    public void destroy() {
        System.out.println("过滤器:执行 destroy 方法");
    }
}

拦截器和过滤器的区别 

  • 主要有 5 个方面

出身不同

  • 拦截器 来自于 Spring 框架
  • 过滤器 来自于 Servlet 

触发时机不同

  • 请求执行顺序为:
  • 请求进入容器 ——> 进入过滤器 ——> 进入 Servlet ——> 进入拦截器 ——> 进入控制器(Controller)

底层实现不同

拦截器

  • 基于 Java 的 Servlet 规范实现的,通过实现 HandleInterceptor 接口来实现拦截器功能
  • 在 Spring Boot 框架的执行流程中,拦截器被注册在 DispatcherServlet 的 doDispatch 方法中,该方法是 Spring Boot 框架的核心方法,用于处理请求和响应
  • 程序每次执行时都会调用 doDispatch 方法,并验证拦截器链(一个应用中可以同时存在多个拦截器,每个拦截器均按提前配置好的顺序执行),之后再根据拦截器返回的结果,进行下一步的处理
  • 如果返回的是 true 则将继续调用目标方法
  • 如果返回的是 false 则直接返回验证失败给前端

过滤器

  • 基于方法回调

支持的项目类型不同

  • 拦截器 是 Spring 中的一个组件,因此拦截器即可以用在 Web 项目中,同时还可以用在 Application 或 Swing 程序中
  • 过滤器 是 Servlet 规范中定义的,所以过滤器要依赖于 Servlet 容器,它只能用在 Web 项目中

使用场景不同

  • 拦截器 更接近业务系统,所以拦截器主要用来实现项目中的业务判断,如登录判断、权限判断、日志记录等
  • 过滤器 通常是用来实现通用功能过滤的,如敏感词过滤、字符集编码设置、响应数据压缩 等

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

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

相关文章

四. 基于环视Camera的BEV感知算法-DETR3D

目录 前言0. 简述1. 算法动机&开创性思路2. 主体结构3. 损失函数4. 性能对比总结下载链接参考 前言 自动驾驶之心推出的《国内首个BVE感知全栈系列学习教程》,链接。记录下个人学习笔记,仅供自己参考 本次课程我们来学习下课程第四章——基于环视Cam…

arm平台编译so文件回顾

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、几个点二、回顾过程 1.上来就执行Makefile2.编译第三方开源库.a文件 2.1 build.sh脚本2.2 Makefile3.最终编译三、其它知识点总结 前言 提示:这…

ES6中的继承,String类型方法的拓展

ES6中的继承: 主要是依赖extends关键字来实现继承,使用了extends实现继承不一定要constructor和super,因为没有的话会默认产生并调用它们。 在实现继承时,如果子类中有constructor函数,必须得在constructor中调用一下s…

我对迁移学习的一点理解——领域适应(系列3)

文章目录 1. 领域适应(Domain Adaptation)的基本概念2.领域适应(Domain Adaptation)的目标3.领域适应(Domain Adaptation)的实现方法4.领域适应(Domain Adaptation)的可以解决的问题…

javaScript(六):DOM操作

文章目录 1、DOM介绍2、DOM:获取Element对象3、DOM:事件监听3.1、事件介绍3.2、常见事件3.3、设置事件的两种方式3.4、事件案例 1、DOM介绍 概念 Document Object Model ,文档对象模型 将标记语言的各个组成部分封装为对应的对象&#xff1a…

leetcode 100.相同的树

涉及到递归,最好多画图理解,希望对你们有帮助 100.相同的树 题目 给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。 题目链接…

一文掌握Ascend C孪生调试

1 What,什么是孪生调试 Ascend C提供孪生调试方法,即CPU域模拟NPU域的行为,相同的算子代码可以在CPU域调试精度,NPU域调试性能。孪生调试的整体方案如下:开发者通过调用Ascend C类库编写Ascend C算子kernel侧源码&am…

项目记录:SpringBoot+Vue部署在阿里云服务器

目录 一、服务器配置 二、后端代码打包 三、前端项目打包 四、nginx配置 一、服务器配置 部署项目需要一个服务器,我们可以选择阿里云的云服务器ECS,在实例界面可以对服务器进行管理: 然后需要在mobaxterm配置jdk、mysql和nginx。注意配…

排序算法之七:归并排序(递归)

基本思想 基本思想: 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列&#xff1…

Mendix版的电商京东首页长什么样儿?

前言 世界需要大前端。大前端需要Mendix。 近日经常有企业IT侧的朋友反应,自家需要一个神奇的内容管理平台,来快速打造随需应变的公司官网,亦或企业官微,如果能在小程序里呈现产品营销类的功能更好。首先要肯定的是,…

tuxera2023破解版免费下载 NTFS for Mac读写工具(附序列号)

Tuxera ntfs 2023 破解安装包是一个mac读写ntfs磁盘工具允许您访问,它允许您访问NFTS 驱动器上的文件。 该应用程序提供访问访问Mac 设备中NFTS 格式文件的驱动力,因此您有权基于格式文件进行无困难的访问Windows 数据。 在发生电力灾难或断电时使用防损…

NodeJs脚手架(Koa)的简单使用

文章目录 前言一、与express的区别express-generator 提供的功能如下koa-generator 提供的功能如下两个生成器共同支持的项目骨架描述如下 二、使用步骤安装 Koa 生成器使用koa2创建项目PM2的使用 三、基础目录说明配置文件package.json入口文件 bin/www核心文件 app.jsroutes …

[CTFshow 红包挑战] 刷题记录

文章目录 红包挑战7红包挑战8红包挑战9 红包挑战7 考点&#xff1a;xdebug拓展 源码 <?php highlight_file(__FILE__); error_reporting(2);extract($_GET); ini_set($name,$value);system("ls ".filter($_GET[1])."" );function filter($cmd){$cmd s…

C语言精选——选择题Day42

第一题 1. 下面程序输出的结果是&#xff08;&#xff09; #include <stdio.h> int main () {int x;x printf("I See, Sea in C");printf("x%d" , x); } A&#xff1a;2 B&#xff1a;随机值 C&#xff1a;都不是 D&#xff1a;15 答案及解析 D p…

unittest 数据驱动DDT应用

前言 一般进行接口测试时&#xff0c;每个接口的传参都不止一种情况&#xff0c;一般会考虑正向、逆向等多种组合。所以在测试一个接口时通常会编写多条case&#xff0c;而这些case除了传参不同外&#xff0c;其实并没什么区别。 这个时候就可以利用ddt来管理测试数据&#xff…

什么是高防IP,高防IP该如何选择。

高防IP&#xff0c;指的是高防御能力的IP地址。在互联网的世界里&#xff0c;网络安全问题成为一个重要的话题。作为一个用户&#xff0c;你是否曾遇到过被黑客攻击造成的网站瘫痪、信息泄露等问题&#xff1f;如果你是一个企业&#xff0c;你是否考虑过自己公司的网站和业务的…

【基于ESP32无线蓝牙上传电脑Excel透传数据】

【基于ESP32无线蓝牙上传电脑透传数据】 1. 引言2. 环境搭建2.1 硬件准备:2.2 软件准备:2.3. 配置Excel端口接收功能3. 测试代码4. 连接电脑和 ESP324.1 烧录程序4.2 启动蓝牙服务4.3 测试数据透传5. 总结1. 引言 随着物联网技术的发展,越来越多的设备开始支持无线通信,其…

java数据结构2------深入学习LinkedList

目录 一、概念 二、源码分析 1、属性 2、节点结构 3、常用方法 ①get(int index) ②add(E e) ③set(int index, E element) ④remove(int index) 三、总结 一、概念 LinkedList 是一种基于链表的集合&#xff0c;用双向链表实现的&#xff0c;提供了高效的插入和删…

设计模式篇---代理模式

文章目录 概念结构实例静态代理动态代理 总结 概念 代理模式&#xff1a;给某一个对象提供一个代理或占位符&#xff0c;并由代理对象来控制对原对象的访问。 比如我们想从其他国家买东西&#xff0c;但我们无法直接联系外国的商家&#xff0c;可以找代理商&#xff0c;让他们…

错题总结(四)

1.【一维数组】输入10个整数&#xff0c;求平均值 编写一个程序&#xff0c;从用户输入中读取10个整数并存储在一个数组中。然后&#xff0c;计算并输出这些整数的平均值。 int main() {int arr[10];int sum 0;for (int n 0; n < 10; n){scanf("%d", &arr…