利用redis+lua优雅实现每天给用户发短信次数限制

最近的一个需求要求实现每天给用户发短信不超过3次,并且发短信间隔不能小于1小时,思来想去有没有什么比较好的实现方式呢,最终决定用redis+lua来实现,第一次写lua脚本。还不太熟练,不过完美的把功能实现了,废话不多说,上代码

1.controller层的调用

package com.example.lua.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;


@RestController
public class Test1Controller {
    @Autowired
    private StringRedisTemplate redisTemplate;
 
    @RequestMapping("test1")
    public void test() {
        System.out.println("xxxxxxxxxxxxxx");
            //调用lua脚本并执行
            DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>();
            redisScript.setResultType(Boolean.class);//返回类型是Long
            redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/clear-local-key1.lua")));

            LocalDateTime now = LocalDateTime.now();
            int dayOfYear = now.getDayOfYear();
            int minute = now.getMinute();
            int hour = now.getHour();

            String userId = "123";
            //默认value
            String limitValue = "1."+(hour * 60 + minute);
            //当晚23:59:59秒过期
            int expireTime = (24*60 - (hour * 60 + minute))*60;
            Boolean ans = redisTemplate.execute(redisScript, Arrays.asList("sms_limit_key:"+userId+":"+dayOfYear), limitValue,String.valueOf(expireTime));
            if(ans) {
                System.out.println("发短信给用户");
            }
    }
}

2.lua脚本的编写

local sms_send_key = KEYS[1];
local sms_send_value = ARGV[1];
local expire_time = ARGV[2];
--解析string字符串 分解出.前缀和.后缀(str = '1.234'  prefix = 1 suffix = 234)
local function parse(str)
    local start_index ,end_index = string.find(str,".",1)
    local prefix = string.sub(str,1,start_index)
    local suffix = string.sub(str,start_index+2,-1)
    return prefix,suffix
end

local value  = redis.call("setnx",sms_send_key,sms_send_value)
--设置成功 说明之前不存在
if(value == 1)
      then   redis.call("expire",sms_send_key,expire_time)
      return true;
else
      local oldValue = tostring(redis.call("get",sms_send_key))
      local oldPre,oldSuf = parse(oldValue)
      local newPre,newSuf = parse(sms_send_value)
--超过60分钟可以发送
        if tonumber(oldPre) <=2 and (tonumber(newSuf) - tonumber(oldSuf)) >= 60
            then
            local newValue = tostring(-0)..'.'..tostring(oldSuf)
            redis.call("incrbyfloat",sms_send_key,sms_send_value)
            redis.call("incrbyfloat",sms_send_key,tonumber(newValue))
            return true;
        else
            return false;
        end
end

好了,结束

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值