Springboot sends the verification code redis to control the number of SMS sending within the specified time

 

Look at the code directly. The following code is just an idea and cannot be used directly to use redis.  

Idea: Mainly look at this method sendCount. This will determine how many redis keys exist in the number of hours. If the number of redis keys is exceeded, it will return false. If the value of the key is not within the specified time, remove the first added 

After the message is then transmitted to the rearmost adding data right inside KEY Note that the list type is redis

    @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;
    }

The AliyunPropert class is just the configuration file class of Alibaba Cloud



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;
}

 

Guess you like

Origin blog.csdn.net/qq_39313596/article/details/110957746