Java接口限制请求次数

定义接口访问频率注解

/**  * 接口访问频率注解,默认一分钟只能访问60次  */  
@Documented  
@Target(ElementType.METHOD)  
@Retention(RetentionPolicy.RUNTIME)  
public @interface RequestLimit {  // 限制时间 单位:秒(默认值:一分钟)  long period() default 60;  // 允许请求的次数(默认值:60次)  long count() default 60;  }

定义切点和处理逻辑,这里使用了redis进行计数

@Aspect
@Component
@Log4j2
public class RequestLimitAspect {@Autowiredprivate RedisUtil redisUtil;// 切点@Pointcut("@annotation(requestLimit)")public void controllerAspect(RequestLimit requestLimit) {}@Around("controllerAspect(requestLimit)")public Object doAround(ProceedingJoinPoint joinPoint, RequestLimit requestLimit) throws Throwable {// get parameter from annotationlong period = requestLimit.period();long limitCount = requestLimit.count();String key = "requestLimit";Object countStr = redisUtil.get(key);if (countStr == null) {redisUtil.set(key, "1",period);return  joinPoint.proceed();} else {int count = Integer.parseInt(String.valueOf(countStr));if (count >= limitCount) {log.error("接口拦截:请求超过限制频率");return HyResponse.fail("超过请求次数,请一分钟后再次请求!");}else {redisUtil.set(key, String.valueOf(count + 1), period);return  joinPoint.proceed();}}}
}

最后直接在需要限制的请求接口上加上@RequestLimit注解

	@RequestLimit(count = 60)@GetMapping("/test")public HyResponse test() {return HyResponse.success();}

RedisUtil工具类

import java.util.*;
import java.util.concurrent.TimeUnit;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;public class RedisUtil {private RedisTemplate<String, Object> redisTemplate;public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {this.redisTemplate = redisTemplate;}// =============================common============================/*** 指定缓存失效时间** @param key  键* @param time 时间(秒)* @return*/public boolean expire(String key, long time) {try {if (time > 0) {redisTemplate.expire(key, time, TimeUnit.SECONDS);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 根据key 获取过期时间** @param key 键 不能为null* @return 时间(秒) 返回0代表为永久有效*/public long getExpire(String key) {return redisTemplate.getExpire(key, TimeUnit.SECONDS);}/*** 判断key是否存在** @param key 键* @return true 存在 false不存在*/public boolean hasKey(String key) {try {return redisTemplate.hasKey(key);} catch (Exception e) {e.printStackTrace();return false;}}/*** 删除缓存** @param key 可以传一个值 或多个*/@SuppressWarnings("unchecked")public void del(String... key) {if (key != null && key.length > 0) {if (key.length == 1) {redisTemplate.delete(key[0]);} else {redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));}}}// ============================String=============================/*** 普通缓存获取** @param key 键* @return 值*/public Object get(String key) {return key == null ? null : redisTemplate.opsForValue().get(key);}/*** 普通缓存放入** @param key   键* @param value 值* @return true成功 false失败*/public boolean set(String key, Object value) {try {redisTemplate.opsForValue().set(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 普通缓存放入并设置时间** @param key   键* @param value 值* @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期* @return true成功 false 失败*/public boolean set(String key, Object value, long time) {try {if (time > 0) {redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);} else {set(key, value);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 递增** @param key 键* @return*/public long incr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递增因子必须大于0");}return redisTemplate.opsForValue().increment(key, delta);}/*** 递减** @param key 键* @return*/public long decr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递减因子必须大于0");}return redisTemplate.opsForValue().increment(key, -delta);}// ================================Map=================================/*** HashGet** @param key  键 不能为null* @param item 项 不能为null* @return 值*/public Object hget(String key, String item) {return redisTemplate.opsForHash().get(key, item);}/*** 通过key 获取所有的field +value** @param key* @return*/public Map<String, Object> hgetall(final String key) {return (Map<String, Object>) redisTemplate.execute(new RedisCallback() {public Map<String, Object> doInRedis(RedisConnection connection) throws DataAccessException {try {Map<byte[], byte[]> values = connection.hGetAll(key.getBytes());if (CollectionUtils.isEmpty(values)) {return new HashMap<>();} else {// 将Map<byte[],byte[]>转换为Map<String,String>Map<String, Object> allValueMap = new HashMap<>(values.size());Iterator itor = values.keySet().iterator();while (itor.hasNext()) {byte[] mapKey = (byte[]) itor.next();allValueMap.put(new String(mapKey), values.get(mapKey));}return allValueMap;}} catch (Exception e) {e.printStackTrace();} finally {}return new HashMap<>();}});}/*** 通过key 获取所有的field +value** @param key* @return*/public Map<String, String> hgetallStr(final String key) {return (Map<String, String>) redisTemplate.execute(new RedisCallback() {public Map<String, String> doInRedis(RedisConnection connection) throws DataAccessException {try {Map<byte[], byte[]> values = connection.hGetAll(key.getBytes());if (CollectionUtils.isEmpty(values)) {return new HashMap<>();} else {// 将Map<byte[],byte[]>转换为Map<String,String>Map<String, String> allValueMap = new HashMap<>(values.size());Iterator itor = values.keySet().iterator();while (itor.hasNext()) {byte[] mapKey = (byte[]) itor.next();allValueMap.put(new String(mapKey), new String(values.get(mapKey), "utf-8"));}return allValueMap;}} catch (Exception e) {e.printStackTrace();} finally {}return new HashMap<>();}});}/*** 获取hashKey对应的所有键值** @param key 键* @return 对应的多个键值*/public Map<Object, Object> hmget(String key) {return redisTemplate.opsForHash().entries(key);}/*** HashSet** @param key 键* @param map 对应多个键值* @return true 成功 false 失败*/public boolean hmset(String key, Map<String, Object> map) {try {redisTemplate.opsForHash().putAll(key, map);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** HashSet 并设置时间** @param key  键* @param map  对应多个键值* @param time 时间(秒)* @return true成功 false失败*/public boolean hmset(String key, Map<String, Object> map, long time) {try {redisTemplate.opsForHash().putAll(key, map);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 向一张hash表中放入数据,如果不存在将创建** @param key   键* @param item  项* @param value 值* @return true 成功 false失败*/public boolean hset(String key, String item, Object value) {try {redisTemplate.opsForHash().put(key, item, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 向一张hash表中放入数据,如果不存在将创建** @param key   键* @param item  项* @param value 值* @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间* @return true 成功 false失败*/public boolean hset(String key, String item, Object value, long time) {try {redisTemplate.opsForHash().put(key, item, value);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 删除hash表中的值** @param key  键 不能为null* @param item 项 可以使多个 不能为null*/public Long hdel(String key, Object... item) {Long delete = redisTemplate.opsForHash().delete(key, item);return delete;}/*** 判断hash表中是否有该项的值** @param key  键 不能为null* @param item 项 不能为null* @return true 存在 false不存在*/public boolean hHasKey(String key, String item) {return redisTemplate.opsForHash().hasKey(key, item);}/*** hash递增 如果不存在,就会创建一个 并把新增后的值返回** @param key  键* @param item 项* @param by   要增加几(大于0)* @return*/public double hincr(String key, String item, double by) {return redisTemplate.opsForHash().increment(key, item, by);}/*** hash递减** @param key  键* @param item 项* @param by   要减少记(小于0)* @return*/public double hdecr(String key, String item, double by) {return redisTemplate.opsForHash().increment(key, item, -by);}// ============================set=============================/*** 根据key获取Set中的所有值** @param key 键* @return*/public Set<Object> sGet(String key) {try {return redisTemplate.opsForSet().members(key);} catch (Exception e) {e.printStackTrace();return null;}}/*** 根据value从一个set中查询,是否存在** @param key   键* @param value 值* @return true 存在 false不存在*/public boolean sHasKey(String key, Object value) {try {return redisTemplate.opsForSet().isMember(key, value);} catch (Exception e) {e.printStackTrace();return false;}}/*** 将数据放入set缓存** @param key    键* @param values 值 可以是多个* @return 成功个数*/public long sSet(String key, Object... values) {try {return redisTemplate.opsForSet().add(key, values);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 将set数据放入缓存** @param key    键* @param time   时间(秒)* @param values 值 可以是多个* @return 成功个数*/public long sSetAndTime(String key, long time, Object... values) {try {Long count = redisTemplate.opsForSet().add(key, values);if (time > 0)expire(key, time);return count;} catch (Exception e) {e.printStackTrace();return 0;}}/*** 获取set缓存的长度** @param key 键* @return*/public long sGetSetSize(String key) {try {return redisTemplate.opsForSet().size(key);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 移除值为value的** @param key    键* @param values 值 可以是多个* @return 移除的个数*/public long setRemove(String key, Object... values) {try {Long count = redisTemplate.opsForSet().remove(key, values);return count;} catch (Exception e) {e.printStackTrace();return 0;}}// ===============================list=================================/*** 获取list缓存的内容** @param key   键* @param start 开始* @param end   结束 0 到 -1代表所有值* @return*/@Deprecatedpublic List<Object> lGet(String key, long start, long end) {try {return redisTemplate.opsForList().range(key, start, end);} catch (Exception e) {e.printStackTrace();return null;}}/*** 弹出最右边的元素,弹出之后该值在列表中将不复存在* @param key* @return*/public Object lRPop(String key) {try {return redisTemplate.opsForList().rightPop(key);} catch (Exception e) {e.printStackTrace();return null;}}/*** 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止* @param key* @return*/public Object lRPop(String key, long timeout, TimeUnit unit) {try {return redisTemplate.opsForList().rightPop(key,timeout,unit);} catch (Exception e) {e.printStackTrace();return null;}}/*** 将所有指定的值插入存储在键的列表的头部。如果键不存在,则在执行推送操作之前将其创建为空列表。(从左边插入)* @param key* @param value* @return*/public boolean lLPush(String key, Object value) {try {redisTemplate.opsForList().leftPush(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 将所有指定的值插入存储在键的列表的头部。如果键不存在,则在执行推送操作之前将其创建为空列表。(从左边插入)* @param key* @param value* @param time  失效时间* @return*/public boolean lLPush(String key, Object value, long time) {try {redisTemplate.opsForList().leftPush(key, value);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/***     incrby = 加指定值 ,key 不存在时候会设置 key,并认为原来的 value 是 0* @param key*/@SuppressWarnings({"unchecked", "rawtypes"})public void incrby(final String key, final long value) {try {if(key != null) {redisTemplate.execute(new RedisCallback() {@Overridepublic Object doInRedis(RedisConnection connection) throws DataAccessException {Long retValue = connection.incrBy(key.getBytes(), value);return retValue;}});}} catch (Exception e) {e.printStackTrace();}}/*** 删除指定key的hash* @param key* @return* @throws Exception*/public boolean deleteKey(final String key) throws Exception {return redisTemplate.delete(key);}
}

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

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

相关文章

微分阻尼作用的理解

先说阻尼的作用,阻尼能够缩短系统整定时间,减小系统响应的振动幅度。 1、CODESYS位置式PID(完整ST源代码) CODESYS位置式PID(完整ST源代码)_codesys pid功能块-CSDN博客文章浏览阅读1.2k次,点赞2次,收藏2次。CODESYS增量式PID完整源代码请参看下面文章链接:CODESYS增量式…

【代码随想录】day55

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、392判断子序列二、115不同的子序列 一、392判断子序列 双指针&#xff1a; class Solution { public:bool isSubsequence(string s, string t) {int i 0;int…

卡码网笔试题 | 114 小欧的平均数、115 组装手机、116 小欧的卡牌

114 小欧的平均数 这题审题要仔细一些&#xff0c;注意题目的真正意思其实是要我们确定三个数的奇偶性&#xff0c;当其中两个分别为一个奇数一个偶数时&#xff0c;我们可以调整第三个数&#xff0c;之后切换到可以匹配的状态下再次调整刚才那两个数中的一个。而不是找到加起…

[图解]SysML和EA建模住宅安全系统-04

1 00:00:01,200 --> 00:00:04,710 我们首先来看一下需求图的一些要点 2 00:00:05,810 --> 00:00:07,080 需求图用来干什么 3 00:00:07,210 --> 00:00:12,080 用来记录文本形式的一些需求 4 00:00:12,090 --> 00:00:13,480 和需求的素材 5 00:00:14,540 --> …

南网上行通信规约报文解析软件

本文分享一个南网上行通信规约20140617 报文解析软件 下载链接: https://pan.baidu.com/s/1ngbBG-yL8ucRWLDflqzEnQ 提取码: y1de 主界面如下图所示&#xff1a; 本软件同时支持南网上行通信规约20140617-Fn查询功能 软件同时支持多种规约类型&#xff0c;如&#xff1a;国网…

基于springboot实现酒店管理系统项目【项目源码+论文说明】

基于springboot实现酒店管理系统演示 摘要 时代的发展带来了巨大的生活改变&#xff0c;很多事务从传统手工管理转变为自动管理。自动管理是利用科技的发展开发的新型管理系统&#xff0c;这类管理系统可以帮助人完成基本的繁琐的反复工作。酒店是出门的必需品&#xff0c;无论…

Kotlin扩展函数和运算符重载

扩展函数 fun String.lettersCount():Int{var count 0for(i in this){if(i.isLetter())count}return count } fun main(){val str:String "12we"println(str.lettersCount()) } 相当于直接将方法写在类里面。函数体内可以直接使用this而不用传参。 运算符重载 …

【算法】买卖股票的最佳时机【JS方案】

【算法】买卖股票的最佳时机 问题描述基本概念和作用说明解决方案暴力解法一次遍历法代码示例 总结与讨论 在前端开发中&#xff0c;虽然我们主要关注的是构建用户界面和交互逻辑&#xff0c;但掌握一些基本的算法和数据结构知识也是非常有用的。今天&#xff0c;我们就来探讨一…

STM32多个外部中断可能共享同一个中断向量

在STM32F4系列微控制器中&#xff0c;多个外部中断可能共享同一个中断向量&#xff08;例如&#xff0c;EXTI9_5_IRQn&#xff09;&#xff0c;因此需要在中断服务例程&#xff08;ISR&#xff09;中区分是哪个中断线触发了中断。对于PB6和PB7&#xff0c;它们都连接到EXTI9_5_…

维修MAHLO / BR贝加莱5D5202.05工控机电脑 人机界面液晶显示屏

贝加莱5D5202.05触摸屏 我们的维修业务&#xff1a; AB、ABB、贝加莱、博世力士乐、霍尼韦尔、艾默生、伦茨、施耐德、西门子、AMAT、松下、三菱、NSK、安川、欧姆龙、日立、光洋、台达、基恩士、横河、东芝等 深圳捷达工控维修是一家专注于人机界面触摸屏的全球维修商&#…

vsCode 设置上下级文件夹目录分离展示?

默认情况下&#xff0c;vsCode目录文件夹会使用/合并展示在一行&#xff0c;这样视觉上看着并不直观&#xff0c;设置目录文件分离展示方法如下&#xff1a; 1、点击左下角设置图标&#xff0c;点击setting&#xff1b; 2、搜索栏输入compact&#xff1b; 3、取消勾选第一个选…

OV SSL证书年度成本概览:确保企业级安全的经济之选

随着网络安全意识的日益增强&#xff0c;SSL证书成为了网站安全的标配&#xff0c;尤其是对于企业而言&#xff0c;选择一款既能确保数据传输安全又符合预算的证书至关重要。在众多SSL证书中&#xff0c;组织验证型&#xff08;Organization Validation&#xff0c;简称OV&…

互联网轻量级框架整合之装配Bean

依赖注入和依赖查找 应该说IoC的工作方式有两种&#xff0c;一种是依赖查找&#xff0c;通过资源定位&#xff0c;把对应的资源查找出来&#xff0c;例如通过JNDI找到数据源&#xff0c;依赖查找被广泛使用在第三方的资源注入上&#xff0c;比如在Web项目中&#xff0c;数据源往…

3588 pwm android12 的操作,包含 NDK native C++

问题&#xff1a; 客户需要在android12 的界面上操作板卡上的 PWM 蜂鸣器设备。 过程&#xff1a; 1 了解一下 3588 android12 源码的 关于PWM 的驱动。 设备树找不到 pwm 但是&#xff0c; 还不知道&#xff0c;android12 最终包含的 设备树是哪个&#xff0c;但是经过我的…

Gone框架介绍17 - 创建一个可运行在生产环境的Web项目

gone是可以高效开发Web服务的Golang依赖注入框架 github地址&#xff1a;https://github.com/gone-io/gone 文档原地址&#xff1a;https://goner.fun/zh/guide/auto-gen-priest.html 请帮忙在github上点个 ⭐️吧&#xff0c;这对我很重要 &#xff1b;万分感谢&#xff01;&a…

ReentrantLock和 synchronized

文章目录 Lock 接口和synchronized的区别Lock 接口和synchronized 对比它有什么优势 Synchronizedsynchronized 底层实现原理sychronized 的自旋锁、偏向锁、轻量级锁、重量级锁synchronized 锁升级 ReentrantLockLock 接口的主要方法ReadWriteLock 读写锁 Lock 接口和synchron…

【Unity-Timeline进度条显示与拖动】

利用Unity 自带的Timeline 可轻松实现场景的巡检漫游效果&#xff0c; 基本使用参考以下链接: Unity中的Timeline Unity学习笔记——TimeLine的简单使用方法&#xff08;一&#xff09; 这里主要介绍如何通过滑动条控制播放的进度&#xff0c;效果图附上。 话不多说&#xff…

Minecraft 我的世界服务器Java版开服联机教程

本教程使用Paper核心开服 1、进入控制面板 1.2、第一次购买服务器会安装游戏端&#xff0c;大约5分钟左右&#xff0c;如果长时间处于安装状态请联系客服 2、开启服务器 2.1、等待出现同意Minecraft EULA 协议时&#xff0c;点击“我接受” 2.2、等待running出现服务器就打开了…

【C++】 C++ 编写 鸡兔同笼程序

文章目录 “鸡兔同笼”问题是一个经典的数学问题&#xff0c;要求根据总头数和总腿数来计算鸡和兔的数量。假设鸡有 2 条腿&#xff0c;兔有 4 条腿。可以通过以下步骤求解这个问题&#xff1a; 1 .设鸡的数量为 x&#xff0c;兔的数量为 y。2.根据题意&#xff0c;我们有以下…

vue 微信小程序 uniapp 微信头像上传裁剪功能

效果如图&#xff1a; 操作流程&#xff1a; 个人中心–点击设置头像–选择图片-裁剪–选取–上传 template <view class"meilan" style"position: relative;"><u-row justify"space-between"><u-col span"3">设置头…