拦截器学习

什么是拦截器

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 中对应的方法)以及所有拦截该请求的拦截器。拦截器就是在这里被调用开始工作的。

拦截器的工作流程
正常流程

 

中断流程

如果在Interceptor1.preHandle中报错或返回false ,那么接下来的流程就会被中断,但注意被执行过的拦截器的afterCompletion仍然会执行。

应用场景

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

登录验证,判断用户是否登录。
权限验证,判断用户是否有权限访问资源,如校验token
日志记录,记录请求操作日志(用户ip,访问时间等),以便统计请求访问量。
处理cookie、本地化、国际化、主题等。
性能监控,监控请求处理时长等。
如何自定义一个拦截器
自定义一个拦截器非常简单,只需要实现 HandlerInterceptor 这个接口即可,该接口有三个可以实现的方法,如下:

preHandle() 方法:改方法会在控制方法前执行,器返回值表示是否知道如何写一个接口。中断后续操作。当其返回值为true时,表示继续向下执行;当其返回值为 false 时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等 )
postHandle()方法: 该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图作出进一步的修改。
afterCompletion()方法:该方法会在整个请求完成,即视图渲染结束之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作。

如何使其在Spring Boot中生效

其实想要在Spring Boot生效其实很简单,只需要定义一个配置类,实现 WebMvcConfigurer 这个接口,并且实现其中的 addInterceptiors() 方法即可,代码演示如下:

@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate  XXX xxx;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//不需要拦截的urlfinal  String[] commonExclude={};registry.addInterceptor(xxx).excludePathPatterns(commonExclude)}
}

实际使用
场景模拟

通过拦截器防止用户暴力请求连接,使用用户IP来限制访问次数 。达到多少次数禁止该IP访问。

思路
记录用户IP访问次数,第一次访问时在redis中创建一个有效时长1秒的key,当第二次访问时key值+1,当值大于等于5时在redis中创建一个5分钟的key,当拦截器查询到reids中有当前IP的key值时返回false限制用户请求接口 。

实现过程
第一步,创建一个拦截器,代码如下:

@Slf4j
public class IpUrlLimitInterceptor implements HandlerInterceptor {@ResourceRedisUtils redisUtils;private static  final  String LOCK_IP_URL_KEY="lock_ip_";private static  final String IP_URL_REQ_TIME="ip_url_times_";//访问次数限制private static final long LIMIT_TIMES=5;//限制时间 秒为单位private static final int IP_LOCK_TIME=300;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("request请求地址uri={},ip={}",request.getRequestURI(), IpUtils.getRequestIP(request));if(ipIsLock(IpUtils.getRequestIP(request))){log.info("ip访问被禁止={}",IpUtils.getRequestIP(request));throw  new Exception("当前操作过于频繁,请5分钟后重试");}if (!addRequestTime(IpUtils.getRequestIP(request),request.getRequestURI())){log.info("当前{}操作过于频繁,请5分钟后重试",IpUtils.getRequestIP(request));throw  new Exception("当前操作过于频繁,请5分钟后重试");}return true;}private boolean addRequestTime(String ip, String uri) {String key = IP_URL_REQ_TIME+ip+uri;if(redisUtils.hasKey(key)){long time=redisUtils.incr(key,(long)1);if(time >=LIMIT_TIMES){redisUtils.set(LOCK_IP_URL_KEY+ip,IP_LOCK_TIME);return false;}}else {boolean set = redisUtils.set(key, (long) 1, 1);}return  true;}private boolean ipIsLock(String ip) {if(redisUtils.hasKey(LOCK_IP_URL_KEY+ip)){return true;}return false;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {HandlerInterceptor.super.afterCompletion(request, response, handler, ex);}
}

第二步,定义一个获取IP的工具类,代码如下:

@Slf4j
public class IpUtils {public  static  String getRequestIP(HttpServletRequest request){String ip = request.getHeader("x-forwarded-for");if(ip != null && ip.length() !=0 && "unknown".equalsIgnoreCase(ip)){// 多次反向代理后会有多个ip值,第一个ip才是真实ipif( ip.indexOf(",")!=-1 ){ip = ip.split(",")[0];}}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){ip = request.getHeader("Proxy-Client-IP");log.info("Proxy-Client-IP ip: " + ip);}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_CLIENT_IP");log.info("HTTP_CLIENT_IP ip: " + ip);}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_X_FORWARDED_FOR");log.info("HTTP_X_FORWARDED_FOR ip: " + ip);}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("X-Real-IP");log.info("X-Real-IP ip: " + ip);}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();log.info("getRemoteAddr ip: " + ip);}return  ip;}
}

第二步,在Spring Boot中配置这个拦截器,代码如下:

@Configuration
public class WebConfig implements WebMvcConfigurer {@BeanIpUrlLimitInterceptor getIpUrlLimitInterceptor(){return  new IpUrlLimitInterceptor();};@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(getIpUrlLimitInterceptor()).addPathPatterns("/**");}
}

 结果:

 

总结

该拦截器是全局生效的,可能有些场景某个接口不需要限制,这样我们可以把这个拦截器改造成注解方式应用。某些接口需要则加上注解即可。

参考:https://www.cnblogs.com/origin-zy/p/16776547.html 

      :https://www.cnblogs.com/bantiaoxianyu/p/16381542.html

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

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

相关文章

【SpringCloud微服务--Eureka服务注册中心】

SpringCloud微服务全家桶学习笔记【持续更新】 gitee仓库 内容:SpringCloud SpringCloud alibaba 技术栈:Java8mavengit,githubNginxRabbitMQSpringBoot2.0 微服务架构概述 微服务架构是一种架构模式,它提倡将单一应用程序划…

局域网内部如何实现文件夹共享

这里写自定义目录标题 1.创建文件夹test2.选择共享--添加用户3.选择高级共享 1.创建文件夹test 2.选择共享–添加用户 3.选择高级共享

three.js 纹理

默认情况下,您在 Three.js 中渲染的所有内容都会发送到屏幕上。毕竟,如果你看不到它,渲染它有什么意义呢?事实证明,有一个非常重要的点:在数据发送到屏幕(从而丢失)之前捕获数据。 …

容器编排学习(九)服务管理与用户权限管理

一 service管理 1 概述 容器化带来的问题 自动调度:在 Pod 创建之前,用户无法预知 Pod 所在的节点,以及 Pod的IP 地址一个已经存在的 Pod 在运行过程中,如果出现故障,Pod也会在新的节点使用新的IP 进行部署应用程…

Java“牵手”微店商品详情数据,微店商品详情API接口,微店API接口申请指南

微店平台商品详情接口是开放平台提供的一种API接口,通过调用API接口,开发者可以获取微店商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片等详细信息 。 获取商品详情接口API是一种用于获取电商平台上商品详情数据的接口,通过…

举例说明PyTorch函数torch.cat与torch.stack的区别

一、torch.cat与torch.stack的区别 torch.cat用于在给定的维度上连接多个张量,它将这些张量沿着指定维度堆叠在一起。 torch.stack用于在新的维度上堆叠多个张量,它会创建一个新的维度,并将这些张量沿着这个新维度堆叠在一起。 二、torch.…

03JVM_类加载

一、类加载与字节码技术 1.类文件结构 2.字节码指令 3.编译期处理 4.类加载阶段 5.类加载器 6.运行期优化 1.类文件结构 类文件结构 1.1 魔数magic 介绍 每个java class文件的前4个字节是魔数:0x CAFEBABE。魔数作用在于分辨出java class文件和非java clas…

Vuepress样式修改内容宽度

1、相关文件 一般所在目录node_modules\vuepress\theme-default\styles\wrapper.styl 2、调整宽度,截图中是已经调整好的,在我电脑上显示刚刚好。

026:vue中el-progress逆向倒计时方式显示

第026个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下,本专栏提供行之有效的源代码示例和信息点介绍,做到灵活运用。 (1)提供vue2的一些基本操作:安装、引用,模板使…

Kubernetes dashboardv2.7.0安装指南:从零开始搭建可视化界面

一、K8S管理控制台 Kubernetes Web UI(或Kubernetes Dashboard)是用于管理和监视Kubernetes集群的不同工具和用户界面。以下是一些常见的Kubernetes Web UI工具和用户界面: Kubernetes Dashboard: Kubernetes官方提供的Web用户界面&#xf…

MYSQL的慢查询

通过查询SQL的执行频次,我们就能够知道当前数据库到底是增删改为主,还是查询为主。 那假如说是以查询为主,次数我们可以借助于慢查询日志。接下来,我们就来介绍一下MySQL中的慢查询日志。 慢查询日志 慢查询日志记录了所有执行时间…

VirtualBox(内有Centos 7 示例安装)

1常见概念以及软件安装 1.1 虚拟化技术: 虚拟化技术指的是将计算机的各种硬件资源加以抽象、转换、分割,最后组合 起来的技术。其目的和作用主要是打破硬件资源不可分的情况,方便程序员自 己集成所需资源。 1.2 Virtual Box 其是虚拟化技术作…

图解三重积分的对称性

1.图解三重积分的对称性 关于三重积分详见:三重积分(Triple Integral) 三重积分的对称性原理与二重积分类似,关于二重积分的对称性详见:图解二重积分的对称性 被积函数 f ( x , y , z ) f(x,y,z) f(x,y,z)可以有不同的物理意义,…

SSMP整合综合案例【SpringBoot的基本增删改查】

一、基本页面 主页面 添加 删除 分页 条件查询 实体类开发————使用Lombok快速制作实体类 Dao开发————整合MyBatisPlus,制作数据层测试 Service开发————基于MyBatisPlus进行增量开发,制作业务层测试类 Controller开发————基于Restful…

【Two Stream network (Tsn)】(二) 阅读笔记

贡献 将深度神经网络应用于视频动作识别的难点,是如何同时利用好静止图像上的 appearance information以及物体之间的运动信息motion information。本文主要有三点贡献: 1.提出了一种融合时间流和空间流的双流网络; 2.证明了直接在光流上训…

【Spring面试】五、Bean扩展、JavaConfig、@Import

文章目录 Q1、如何在Spring创建完所有的Bean之后做扩展?Q2、Spring容器启动时,为什么先加载BeanFactoryPostProcess?Q3、Bean的生产顺序是由什么决定的?Q4、Spring有哪几种配置方式Q5、JavaConfig是如何替代spring.xml的?Q6、Com…

SpringMVC基础入门及工作流程---全方面详细介绍

一,SpringMVC概念 Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简…

赋能工业物联网 | 数据驱动,加速智能制造

行业背景 工业物联网场景下,随着智能设备及物联网技术的广泛应用,数据是最重要的资源之一,企业需要对各种机器、设备和传感器产生的时序数据进行采集、存储与分析。 因此,何为行之有效的数据库解决方案?企业普遍更为…

MySQL--数据库基础

数据库分类 数据库大体可以分为 关系型数据库 和 非关系型数据库 常用数据类型 数值类型: 分为整型和浮点型: 字符串类型 日期类型

【PTA】浙江大学计算机与软件学院2019年考研复试上机自测

个人学习记录,代码难免不尽人意。 呃,今天做了做19年的复试上机题,死在hash表上了,后面详细解释。心态要好,心态要好 7-1 Conway’s Conjecture John Horton Conway, a British mathematician active in recreational…