2023.12.3 关于 Spring 拦截器 和 过滤器

目录

引言

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 {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("拦截器:执行 preHandle 方法。");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("拦截器:执行 postHandle 方法。");}@Overridepublic 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 则表示拦截器 验证未通过 后续的流程和目标方法不要执行了* */@Overridepublic 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 {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic 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 {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("过滤器:执行 init 方法");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("过滤器:开始执行 doFilter 方法");
//        请求放行filterChain.doFilter(servletRequest,servletResponse);System.out.println("过滤器:结束执行 doFilter 方法");}@Overridepublic 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 {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("过滤器:执行 init 方法");}@Overridepublic 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 方法");}@Overridepublic 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 项目中

使用场景不同

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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CefSharp 获取POST(AJAX)、GET消息返回值(request)

CefSharp作为专门为爬虫工具开发的库比Selenium这种开发目的是页面测试工具然后用来做爬虫的工具要贴心得多。我们操作网页的时候发送或者做了某个动作提交表单之后需要知道我们的动作或者提交是否成功,因为有的页面会因为网络延迟问题提交失败,需要准确…

VSCode 开发C/C++实用插件分享——koroFileHeader

相关文章 VSCode 开发C/C实用插件分享——codegeex VSCode 开发C/C实用插件分享——koroFileHeader 一、koroFileHeader二、使用步骤1.安装2.头文件注释配置3.函数注释配置 一、koroFileHeader 在有些场景下,我们需要在文件头添加一些作者、文件描述、时间和版权描述…

12月第一天,给搞电商的家人们整活儿!

今年,大家出门的热情直线飙升! 特种兵旅游带火N个小众城市、Citywalk大军激活大街小巷的商业活力、线下演出火爆带动各地文旅指数狂飙,户外运动也乘风而上,徒步/露营/钓鱼/骑行/冲浪/滑雪等花式运动在各大社媒平台集中刷屏&#…

pytorch 常用api笔记

view_as()函数 函数定义:view_as(tensor) [参数为一个Tensor张量] 该函数的作用是将调用函数的变量,转变为同参数tensor同样的形状。 例子 data1 [[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 0], [10, 11]]] t1 torch.Tensor(data1).long() # size2…

vue3 vue-cropper@next 实现图片裁切功能

Vue Cropper 实现上传图片预览&#xff0c;裁切上传效果 下载 pnpm add vue-croppernext使用 <template><inputref"inputRef"class"hidden"accept".png,.jpeg,.jpg"multipletype"file"change"handleUploadChange&quo…

使用Redis构建简易社交网站(2)-处理用户关系

目的 本文目的&#xff1a;实现用户关注和取消关注功能。&#xff08;完整代码附在文章末尾&#xff09; 相关知识 在我之前的文章 《使用Redis构建简易社交网站(1)-创建用户与动态界面》中提到了如何实现简易社交网站中创建新用户和创建新动态功能。 那这篇文章将教会你掌…

03 数仓平台 Kafka

kafka概述 定义 Kafka 是一个开源的分布式事件流平台&#xff08;Event Streaming Plantform&#xff09;&#xff0c;主要用于大数据实时领域。本质上是一个分布式的基于发布/订阅模式的消息队列&#xff08;Message Queue&#xff09;。 消息队列 在大数据场景中主要采用…

电压驻波比

电压驻波比 关于IF端口的电压驻波比 一个信号变频后&#xff0c;从中频端口输出&#xff0c;它的输出跟输入是互异的。这个电压柱波比反映了它输出的能量有多少可以真正的输送到后端连接的器件或者设备。

ffmpeg 任意文件读取漏洞/SSRF漏洞 (CVE-2016-1897/CVE-2016-1898)

漏洞描述 影响范围 FFmpeg 2.8.x < 2.8.5FFmpeg 2.7.x < 2.7.5FFmpeg 2.6.x < 2.6.7FFmpeg 2.5.x < 2.5.10 漏洞环境及利用 搭建docker环境 访问8080端口看到上传界面 由于vulhub并没有讲述该漏洞如何复现&#xff0c;我们需要进入环境查看源码 <?php if(!…

Motion Plan之轨迹生成笔记 (2)

Motion Plan之搜索算法笔记 Motion Plan之基于采样的路径规划算法笔记 Motion Plan之带动力学约束路径搜索 什么是基于优化的轨迹生成 Optimization-Based Trajectory Planning&#xff08;基于优化的轨迹规划&#xff09;是一种常用的方法&#xff0c;用于生成自动化系统&am…

【数值计算方法(黄明游)】函数插值与曲线拟合(二):Newton插值【理论到程序】

​ 文章目录 一、近似表达方式1. 插值&#xff08;Interpolation&#xff09;2. 拟合&#xff08;Fitting&#xff09;3. 投影&#xff08;Projection&#xff09; 二、Lagrange插值1. 拉格朗日插值方法2. Lagrange插值公式a. 线性插值&#xff08;n1&#xff09;b. 抛物插值&…

EM32DX-C2【C#】

1说明&#xff1a; 分布式io&#xff0c;CAN总线&#xff0c;C#上位机二次开发&#xff08;usb转CAN模块&#xff09; 2DI&#xff1a; 公共端是&#xff1a; 0V【GND】 X0~X15&#xff1a;自带24v 寄存器地址&#xff1a;0x6100-01 6100H DI输入寄存器 16-bit &#x…