直接看代码吧 以下代码只是思路 不能直接使用 使用redis的
思路: 主要看这个方法sendCount 这里会会判断 多少小时内redis key存在多少如果超过了多少条则返回false 如果key的value不在传入的规定的时间 内则移除最前面添加的
接着在最后面发送短信之后往KEY里面右侧添加数据 注意这里的redis类型是list
@Resource
private AliyunPropert aliyunPropert;
/**
* signName是阿里云短信国内消息的签名名称
*/
private final static String setSignName = "xxx";
//1分钟
private final static String SMS_TIMEOUT_REDIS_KEY1M = "SMS:TIMEOUT:REDISKEY1M_";
//1小时
private final static String SMS_TIMEOUT_REDIS_KEY1H = "SMS:TIMEOUT:REDISKEY1H_";
//24小时
private final static String SMS_TIMEOUT_REDIS_KEY24H = "SMS:TIMEOUT:REDISKEY24H_";
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
TbuMsgSendMapper tbuMsgSendMapper;
/**
* @param phoneNumbers: 手机号
* @param map: 模板参数map {"sellerName":"123456","orderSn":"123456"}
* @param templateCode: 阿里云短信模板code
* @param type 短信类型
* @Description: 对接阿里云短信服务实现短信发送
* 发送验证码类的短信时,每个号码每分钟最多发送一次,每个小时最多发送5次。其它类短信频控请参考阿里云
* @Version: V1.0
*/
@RsionLock(key = "aliyunSmsService_send", value = "#phoneNumbers", lockTime = 2, waitTime = 2)
public Result send(String phoneNumbers, Map<String, String> map, String templateCode, String type) {
try {
//1分钟
String key1m = SMS_TIMEOUT_REDIS_KEY1M + phoneNumbers + type;
//1小时
String key1h = SMS_TIMEOUT_REDIS_KEY1H + phoneNumbers + type;
//24小时
String key24h = SMS_TIMEOUT_REDIS_KEY24H + phoneNumbers + type;
//验证手机号是否符合规则
boolean mobile = Validator.isMobile(phoneNumbers);
if (!mobile) {
return new Result().getError(SmsResultCode.VERMOBILE);
}
//验证短信模板是否为空templateCode
if (StringUtils.isBlank(templateCode)) {
return new Result().getError(SmsResultCode.VERTEMPLATECODE);
}
//每个号码每分钟最多发送1次
if (redisTemplate.hasKey(key1m)) {
//"该手机号:" + phoneNum + " 剩余:" + redisTemplate.getExpire(phoneNum) + "秒后可再次进行发送!"
return new Result().getError(MessageFormat.format(SmsResultCode.YZMERRORTIMEOUT, phoneNumbers, redisTemplate.getExpire(key1m)));
}
Boolean bolTimeOut1H = sendCount(key1h, 5, 1);
//每个小时最多发送5次
if (!bolTimeOut1H) {
return new Result().getError(SmsResultCode.VERMOBILE_TIME1H);
}
//24小时内只能发送20次
Boolean bolTimeOut24H = sendCount(key24h, 20, 24);
if (!bolTimeOut24H) {
return new Result().getError(SmsResultCode.VERMOBILE_TIME24H);
}
long l = System.currentTimeMillis();
SendSmsResponse sendSmsResponse = sendSms(phoneNumbers, JSON.toJSONString(map), templateCode);
TbuMsgSend tbuMsgSend = new TbuMsgSend();
tbuMsgSend.setC_mobile(phoneNumbers);
tbuMsgSend.setM_type(type);
tbuMsgSend.setC_result(sendSmsResponse.getCode());
tbuMsgSend.setC_result_detail(sendSmsResponse.getMessage());
tbuMsgSend.setRequestid(sendSmsResponse.getRequestId());
tbuMsgSend.setBack_up(sendSmsResponse.getBizId());
String dt = DateUtil.format(new Date(), "yyyyMMddHHmmss");
tbuMsgSend.setCreate_time(dt);
tbuMsgSend.setUpdate_time(dt);
String code = "";
if (map.containsKey("code")) {
code = map.get("code");
tbuMsgSend.setC_content(code);
}
if (sendSmsResponse.getCode().equals("OK")) {
redisTemplate.opsForList().rightPush(key1h, l + "");
redisTemplate.opsForList().rightPush(key24h, l + "");
// 发送成功之后往redis中存入该手机号以及验证码 并设置超时时间 1 分钟
redisTemplate.opsForValue().set(key1m, code, 1, TimeUnit.MINUTES);
//记录到数据库
insertTbuMsgSend(tbuMsgSend);
return new Result().getOk(MessageFormat.format(SmsResultCode.YZMSUCCESS, phoneNumbers), "");
} else {
//记录到数据库
insertTbuMsgSend(tbuMsgSend);
//发送失败
return new Result().getError(sendSmsResponse.getCode(), sendSmsResponse.getMessage());
}
} catch (Exception e) {
//throw new CommonException(CodeMsg.SERVER_ERROR, SmsResultCode.ERROR);
return new Result().getError(SmsResultCode.ERROR);
}
}
public void insertTbuMsgSend(TbuMsgSend tbuMsgSend) {
try {
if (tbuMsgSend == null) {
log.error("短信记录失败,mobile为空");
return;
}
tbuMsgSendMapper.insertTbuMsgSend(tbuMsgSend);
log.error("短信已记录:{}" + tbuMsgSend.getC_mobile());
} catch (Exception e) {
log.error("短信记录失败:{}" + tbuMsgSend.getC_mobile());
}
}
/**
* 同一个手机号一小时内发送短讯是否超过count次
*
* @param key key 的拼接是 key + 手机号 + 业务类型
* @param count 次数
* @param h 小时 必须整数
* @author
*/
public Boolean sendCount(String key, int count, int h) {
Boolean boo = true;
long size = redisTemplate.opsForList().size(key);
if (size <= count) {
//redisTemplate.opsForList().rightPush(key, System.currentTimeMillis() + "");
boo = true;
} else {
List<String> t = redisTemplate.opsForList().range(key, 0, (int) size);
Long now = System.currentTimeMillis();
if (now - Long.valueOf(t.get(0)) > h * 60 * 60 * 1000) {
//最开始的一条距现在超过一小时就移除左边的,并添加一条
redisTemplate.opsForList().leftPop(key);
//redisTemplate.opsForList().rightPush(key, System.currentTimeMillis() + "");
boo = true;
} else {//最左的一条也在n小时内,不能发送短信
boo = false;
}
}
return boo;
}
/**
* @param phoneNumbers: 手机号
* @param templateParamJson: 模板参数json {"sellerName":"123456","orderSn":"123456"}
* @param templateCode: 阿里云短信模板code
* @Description: 对接阿里云短信服务实现短信发送
* 发送验证码类的短信时,每个号码每分钟最多发送一次,每个小时最多发送5次。其它类短信频控请参考阿里云
* @Date: 2019/4/18 16:35
* @Version: V1.0
*/
public SendSmsResponse sendSms(String phoneNumbers, String templateParamJson, String templateCode) {
//可自助调整超时时间
//设定连接超时
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
//设定读取超时
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
// 封装短信发送对象
Sms sms = new Sms();
sms.setPhoneNumbers(phoneNumbers);
sms.setTemplateParam(templateParamJson);
sms.setTemplateCode(templateCode);
// 获取短信发送服务机
IAcsClient acsClient = getClient();
//获取短信请求
SendSmsRequest request = getSmsRequest(sms);
SendSmsResponse sendSmsResponse = new SendSmsResponse();
try {
sendSmsResponse = acsClient.getAcsResponse(request);
} catch (ClientException e) {
log.error("发送短信发生错误。错误代码是 [{}],错误消息是 [{}],错误请求ID是 [{}],错误Msg是 [{}],错误类型是 [{}]",
e.getErrCode(),
e.getMessage(),
e.getRequestId(),
e.getErrMsg(),
e.getErrorType());
}
return sendSmsResponse;
}
AliyunPropert 类只是阿里云的配置文件类
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
/**
* @Auther: heng
* @Date: 2020/12/9 16:58
* @Description: AliyunPropert
* @Version 1.0.0
*/
@Getter
@Setter
@PropertySource(value = "classpath:aliyun.properties", encoding = "UTF-8")
@ConfigurationProperties(prefix = "aliyun.sms")
@Configuration
public class AliyunPropert {
/**
* 短信API产品名称(短信产品名固定,无需修改)
*/
private String product;
/**
* 短信API产品域名,接口地址固定,无需修改
*/
private String domain;
/**
* 此处需要替换成开发者自己的accessKeyId和accessKeySecret(在阿里云访问控制台寻找)
* TODO: 这里要写成你自己生成的
*/
private String accessKeyId; //
/**
* accessKeySecret
* TODO: 这里要写成你自己生成的
*/
private String accessKeySecret;
/**
* cn-hangzhou
*/
private String regionId;
/**
* 发送日期 支持30天内记录查询,格式yyyyMMdd
*/
private String dateFormat;
/**
* cn-hangzhou
*/
private String endpointName;
}