redis-限制用户每天访问不同接口的次数

该博客探讨了如何利用Redis实现业务需求,限制每个用户每天访问不同接口的次数。通过对比Redis的多种数据结构,如string、list、set和hash,最终选择了hash类型来存储接口和承运商的访问次数,以减少内存浪费并便于更新操作。文章提供了业务流程图,并分享了SpringBoot中操作Redis Hash数据结构的示例代码及解决JedisDataException的方法链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 业务需求

限制每个用户每天访问不同接口的次数,如:每个承运商每天只能根据运单号查询客户信息50次,每个承运商每天只能根据运单号查询商品信息30次。

  • 方案选择

Redis是一个key-value存储系统,存放的value类型相对较多包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型),同时redis具有时效性,所以此处采用redis的方式实现业务需求。

  • 选用redis哪种数据结构方式

value为string类型:key用于标识不同接口不同承运商,value代表对应承运商每天访问的客户信息的次数,虽然可以实现业务需求,但接口标志一直重复存储,浪费了内存。
A接口(承运商1)—>N A接口(承运商2)—>N …
B接口(承运商1)—>N B接口(承运商2)—>N …

value为集合类型:用这种方式还不如用value为string类型的方式。

value为hash类型:key用于存放接口标识,value为一个Map集合用来存放不同承运商访问对应接口的次数。这种方式如果要修改对应的访问次数只需要通过(接口标志+承运商标志)就可以直接修改,同时接口标志不会重复存储,避免了内存的浪费。
A接口—>{承运商1—>N,承运商2—>N …}B接口—>{承运商1—>N,承运商2—>N …}

在这里插入图片描述

通过springboot的RedisTemplate操作redis hash数据结构的方法:
https://blog.youkuaiyun.com/weixin_37490221/article/details/78135036

redis.clients.jedis.exceptions.JedisDataException: ERR hash value is not an integer异常解决方案:
https://blog.youkuaiyun.com/qq_31071543/article/details/85158305

可以使用Spring AOP(面向切面编程)来实现接口限制访问次数的功能。 首先,需要定义一个注解来标识需要限制访问次数接口,比如@AccessLimit: ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AccessLimit { int seconds(); int maxCount(); } ``` 然后,在AOP切面中实现对该注解的解析和限制访问次数的功能: ```java @Aspect @Component public class AccessLimitAspect { private final RedisTemplate<String, Integer> redisTemplate; @Autowired public AccessLimitAspect(RedisTemplate<String, Integer> redisTemplate) { this.redisTemplate = redisTemplate; } @Around("@annotation(accessLimit)") public Object around(ProceedingJoinPoint point, AccessLimit accessLimit) throws Throwable { // 获取方法名和参数作为缓存的key MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); String methodName = method.getName(); Object[] args = point.getArgs(); String key = methodName + Arrays.toString(args); // 获取当前时间戳和过期时间戳 long currentTime = System.currentTimeMillis(); long expireTime = currentTime + accessLimit.seconds() * 1000; // 查询缓存中的访问次数 Integer count = redisTemplate.opsForValue().get(key); if (count == null) { // 缓存中没有该key,表示该接口第一次被访问,设置访问次数为1并设置过期时间 redisTemplate.opsForValue().set(key, 1, accessLimit.seconds(), TimeUnit.SECONDS); } else { if (count >= accessLimit.maxCount()) { // 访问次数超过限制,返回错误信息 throw new RuntimeException("访问次数超过限制"); } else { // 访问次数加1并更新过期时间 redisTemplate.opsForValue().increment(key, 1); redisTemplate.expire(key, expireTime - currentTime, TimeUnit.MILLISECONDS); } } // 执行目标方法 return point.proceed(); } } ``` 在这个切面中,我们使用了Redis作为缓存来存储接口访问次数和过期时间。在每次访问限制接口时,我们先根据方法名和参数作为缓存的key查询缓存中的访问次数,如果缓存中没有该key,则表示该接口第一次被访问,设置访问次数为1并设置过期时间。如果缓存中已经有该key,则判断访问次数是否超过限制,如果超过限制则返回错误信息,否则访问次数加1并更新过期时间。最后执行目标方法。 要使用该AOP切面,只需要在需要限制访问次数接口上添加@AccessLimit注解即可: ```java @RestController public class UserController { @AccessLimit(seconds = 60, maxCount = 5) @GetMapping("/user/info") public String getUserInfo(@RequestParam("id") Integer id) { // ... } } ``` 这样,就可以对getUserInfo接口进行访问次数限制了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值