最近的一个需求要求实现每天给用户发短信不超过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
好了,结束