最近突然接到个需求,因为项目中使用的谷歌地图的三方API每调用一次需要刀,所以客户怕使用过量,想要加个可调节的次数控制具体到当前每小时和每天的数量限制,想到得解决方案就是使用redis当计数器在数据库配好次数规则,实现起来也非常简单
1.设置好计数器的key和缓存,这里为了方便就直接用redisson自带的功能了
//小时调用次数 RAtomicLong counterHour = redisson.getAtomicLong(RedisKeys.GOOGLE_MAP_HOUR_KEY);
// 获取一小时内的接口调用次数 long hourCount = counterHour.get();
2.规则校验这里就是读库校验规则然后通过就是加一
SysConfig configHour = sysConfigService.selectConfigById(ConfigKeys.GOOGLE_MAP_HOUR_APIKEY); if (Long.parseLong(configHour.getConfigValue())<=hourCount){ return Result.success(false); } counterHour.incrementAndGet();
3.然后就是更新缓存时间了,这里有个细节,需要计算出当前的时间到下个整点时间的秒数,而不是重新设置一小时,不然这样这个key就变成永久的了每天的key就不会生效,每天和每小时的逻辑差不多,就不写出来了
setNextHourExpiration(counterHour,1);
private static void setNextHourExpiration(RAtomicLong counter,Integer type) { if (type == 1){ LocalDateTime now = LocalDateTime.now(); LocalTime nextHour = LocalTime.of(now.getHour() + 1, 0); LocalDateTime nextHourDateTime = now.with(nextHour); Duration duration = Duration.between(now, nextHourDateTime); long expireTime = duration.getSeconds(); counter.expire(expireTime, TimeUnit.SECONDS); } if (type == 2){ LocalDateTime now = LocalDateTime.now(); LocalDateTime nextDay = now.plus(1, ChronoUnit.DAYS).with(LocalTime.MIN); Duration duration = Duration.between(now, nextDay); long expireTime = duration.getSeconds(); counter.expire(expireTime, TimeUnit.SECONDS); } }
前端调用API前都要调用这个接口获取许可才能调用否则就是拒绝