springboot 发送验证码 redis控制在规定时间内的短信发送规定次数思路

直接看代码吧 以下代码只是思路 不能直接使用 使用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;
}

猜你喜欢

转载自blog.csdn.net/qq_39313596/article/details/110957746