对接阿里云短信发送

对接阿里云短信

1.配置sdk:

    <!--阿里云短信SDK-->
    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-java-sdk-core</artifactId>
    </dependency>
    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
    </dependency>

2.编写阿里云发送短信工具类

package com.base.cn.platform.os.common.utils.sms;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.base.cn.platform.os.common.utils.StringUtils;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

/**
 * 阿里短信发送工具
 */
public class ALSmsSendUtils {
    private static Logger logger = LoggerFactory.getLogger(ALSmsSendUtils .class);
    private static Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();


    /**
     * 阿里云短信接口
     *
     * @param mobile	接收人手机号码,多个号码使用','隔开
     * @param content   消息内容: 验证码,提示信息等
     * @param tempId	模板Id
     * @param appKey
     * @param appSecret
     * @return
     */
    static boolean aliSendMessage(String mobile, Map<String,String> content, String tempId, String appKey, String appSecret,String sig) {
        try {
            if (StringUtils.isEmpty(mobile) || StringUtils.isEmpty(content) || StringUtils.isEmpty(tempId)
                    || StringUtils.isEmpty(appKey) || StringUtils.isEmpty(appSecret)){
                logger.error("----------发送短信失败: 参数错误");
                return false;
            }
            //初始化ascClient,暂时不支持多region(请勿修改)
            IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", appKey, appSecret);
            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", "Dysmsapi", "dysmsapi.aliyuncs.com");
            IAcsClient acsClient = new DefaultAcsClient(profile);

            //组装请求对象
            SendSmsRequest request = new SendSmsRequest();
            //使用post提交
            request.setMethod(MethodType.POST);
			/* 必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,
			批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式;
			发送国际/港澳台消息时,接收号码格式为00+国际区号+号码,如“0085200000000”*/
            request.setPhoneNumbers(mobile);
            //必填:短信签名-可在短信控制台中找到
            request.setSignName(sig);
            //必填:短信模板-可在短信控制台中找到
            request.setTemplateCode(tempId);
            //可选:模板中的变量替换JSON串,如模板内容为"您的验证码为${code}"时,此处的值为{"code":content}
            logger.info("----------------短信接口传入参数----------------   "+ gson.toJson(content));
            request.setTemplateParam(gson.toJson(content));
            //请求失败这里会抛ClientException异常
            SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
            //直接返回调用结果
            if (sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) {
                return true;
            } else {
                logger.info("----------------短信接口返回的数据----------------");
                logger.info("Code = " + sendSmsResponse.getCode());
                logger.info("Message = " + sendSmsResponse.getMessage());
                logger.info("RequestId = " + sendSmsResponse.getRequestId());
                logger.info("BizId = " + sendSmsResponse.getBizId());
                return false;
            }
        } catch (Exception e) {
            logger.error("----------发送短信方法异常: MobileSend.sendMessage");
            e.printStackTrace();
            return false;
        }
    }
}

3.编写发送短信方法

 /**
     * 发送短信
     *
     * @param mobile 手机事情
     * @param tempId 内容模板ID
     * @return true发送成功,false发送失败
     * @throws Exception
     */
    private boolean send(String mobile, String tempId){
        // 填写你的配置信息
        Map<String, String> configMap = getSmsConfig();
        String AppKey = configMap.get("AppKey"); //填写你的AppKey
        String appId = configMap.get("appId");//填写你的appId
        String appSecret = configMap.get("appSecret"); //填写你的appSecret

        //限制防盗刷,开始------------------
        if (!StringUtils.isMobile(mobile) || StringUtils.isEmpty(tempId)) {
            return false;
        }
        //非法发送(或过于频繁发送)
        if (!safetyVerification(appId, mobile, tempId)) {
            return false;
        }
        //请求来源
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        request.getHeader("referer");

        //限制防盗刷,结束------------------

        //-------------执行发送------开始
        //生成6位验证码
        String codeNum = StringUtils.getRandStr(6);
        logger.info("-----------------------验证码:"+codeNum);
        boolean status =false;
        
        Map<String, String> context = new HashMap();
        context.put("codeNum",codeNum);
        //调用阿里云短信发送功能
        status = ALSmsSendUtils.aliSendMessage(mobile,context, tempId, appId, appSecret,configMap.get("sig")); //sig 是短信签名
        

        if (status) {
            //设置安全验证数据
            setSafetyData(AppKey, mobile, tempId, codeNum);
            return true;
        }
        //-------------执行发送------结束
        return false;
    }

4.其他方法

判断是否是标准手机号:

    public static boolean isMobile(String mobile) {
        if (isNotEmpty(mobile)) {
            return Pattern.matches("^[1][0-9]{10}$", mobile);
        }
        return false;
    }

安全验证:

 /**
     * 安全验证
     *
     * @param appKey
     * @param mobile
     * @param tempId
     * @return true验证通过,false验证未通过
     */
    private boolean safetyVerification(String appKey, String mobile, String tempId) {
        String commKey = getCommonKey(appKey, mobile, tempId);

        //验证上次发送时间,判断是否频繁发送(1分钟内只能发送一次)
        String timeKey = commKey + "time";
        //得到上次发送时间
        Date upTime = (Date) customCacheChannel.get(J2CacheRegion.ONE_MINUTE_REGION.getKey(), timeKey).getValue();
        if (ObjectUtils.isNotEmpty(upTime)) {
            //如果上一次发送未起过一分钟,则视为频繁发送
            if ((new Date().getTime() - upTime.getTime()) < ONE_MINUTE) {
                logger.info("+++++++++++++++++++++++++++++单一操作过于频繁发送");
                return false;
            }
        }

        //频繁发送验证通过,再验证单一操作24小时内的发送量
        String everyDayStartTimeKey = commKey + "every_day_time_start";
        Date everyDayStartTime = (Date) customCacheChannel.get(J2CacheRegion.ONE_DAY_REGION.getKey(), everyDayStartTimeKey).getValue();
        //如果有数据
        if (ObjectUtils.isNotEmpty(everyDayStartTime)) {
            //如果上一次的同一个操作第一次发送未超过24小时
            if ((new Date().getTime() - everyDayStartTime.getTime()) < ONE_DAY) {
                String numKey = commKey + "num";//发送量的Key
                Integer sendNum = (Integer) customCacheChannel.get(J2CacheRegion.ONE_DAY_REGION.getKey(), numKey).getValue();
                if (ObjectUtils.isNotEmpty(sendNum)) {
                    //如果在24小时内,单一操作量已超过最大量,则验证不通过
                    if (sendNum.intValue() >= MAX_SEND_NUM) {
                        logger.info("----------------------------单一操作24小时内发送量已达到最大量");
                        return false;
                    }
                }
            }
        }
        return true;
    }

获取验证码:随机数据(纯数字):

    /**
     * 获取随机数据(纯数字)
     *
     * @param n 几位
     * @return 随机字符串
     */
    public static String getRandStr(int n) {
        Random random = new Random();
        String sRand = "";
        for (int i = 0; i < n; i++) {
            String rand = String.valueOf(random.nextInt(10));
            sRand += rand;
        }
        return sRand;
    }

    private CustomCacheChannel customCacheChannel;
    /**
     * 设置安全验证数据
     *
     * @param appKey 腾讯云KEY
     * @param mobile 手机号
     * @param tempId 腾讯云短信模板ID
     * @param code   验证码(用于缓存验证)
     */
    private void setSafetyData(String appKey, String mobile, String tempId, String code) {

        String commKey = getCommonKey(appKey, mobile, tempId);

        //缓存每次发送时间点,用于判断是否频繁发送(1分钟内只能发送一次)
        String timeKey = commKey + "time";
        customCacheChannel.set(J2CacheRegion.ONE_MINUTE_REGION.getKey(), timeKey, new Date());

        //设置每天第一次发送时间点,
        //如果缓存有数据则判断是否超过24小时,如果超过24小时则重新设置时间点(因为要验证24小时内发送量)
        String everyDayStartTimeKey = commKey + "every_day_time_start";//缓存每天第一次发送时间
        Date everyDayStartTime = (Date) customCacheChannel.get(J2CacheRegion.ONE_DAY_REGION.getKey(), everyDayStartTimeKey).getValue();
        if (ObjectUtils.isNotEmpty(everyDayStartTime)) {
            if ((new Date().getTime() - everyDayStartTime.getTime()) >= ONE_DAY) {
                customCacheChannel.set(J2CacheRegion.ONE_DAY_REGION.getKey(), everyDayStartTimeKey, new Date());
            }
        } else {
            customCacheChannel.set(J2CacheRegion.ONE_DAY_REGION.getKey(), everyDayStartTimeKey, new Date());
        }

        //设置已发送的量,每天同一个操作发送短信量有限制
        String numKey = commKey + "num";//发送量的Key
        Integer sendNum = (Integer) customCacheChannel.get(J2CacheRegion.ONE_DAY_REGION.getKey(), numKey).getValue();
        if (!ObjectUtils.isNotEmpty(sendNum)) {
            sendNum = 1;
        } else {
            sendNum = sendNum.intValue() + 1;
        }
        logger.info("------------------mobile send num :" + sendNum);
        customCacheChannel.set(J2CacheRegion.ONE_DAY_REGION.getKey(), numKey, sendNum);
        //缓存验证码
        customCacheChannel.set(J2CacheRegion.THIRD_MINUTE_REGION.getKey(), commKey, code);
    }
 /**
     * 获取共用KEY
     *
     * @param appKey
     * @param mobile
     * @param tempId
     * @return
     */
    private String getCommonKey(String appKey, String mobile, String tempId) {
        return appKey + "_" + mobile + "_" + tempId;
    }
package com.base.cn.platform.os.common.j2cache;

/**
 * J2Cache的空间枚举
 * @author s.li
 * @date 2019/02/27
 */
public enum J2CacheRegion {
    /**缓存30天*/
    THIRTY_DAY_REGION("gdxuxue-thirty_day_region","10000, 30d"),
    /**缓存7天*/
    SEVEN_DAY_REGION("gdxuxue-seven_day_region","10000, 7d"),
    /**缓存1天*/
    ONE_DAY_REGION("gdxuxue-one_day_region","10000, 1d"),
    /**缓存12小时*/
    TWELVE_HOURS_REGION("gdxuxue-twelve_hours_region","10000, 12h"),
    /**缓存6小时*/
    SEX_HOURS_REGION("gdxuxue-sex_hours_region","10000, 6h"),
    /**缓存2小时*/
    TWO_HOURS_REGION("gdxuxue-two_hours_region","10000, 2h"),
    /**缓存1小时*/
    ONE_HOURS_REGION("gdxuxue-one_hours_region","10000, 1h"),
    /**缓存30分钟*/
    THIRTY_MINUTE_REGION("gdxuxue-thirty_minute_region","10000, 30m"),
    /**缓存3分钟*/
    THIRD_MINUTE_REGION("gdxuxue-third_minute_region","10000, 3m"),
    /**缓存1分钟*/
    ONE_MINUTE_REGION("gdxuxue-one_minute_region","10000, 1m"),
    /**缓存30秒*/
    THIRTY_SECOND_REGION("gdxuxue-thirty_second_region","10000, 30s");

    private String key;
    private String value;

    J2CacheRegion(String key,String value){
        this.key = key;
        this.value = value;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

发布了114 篇原创文章 · 获赞 52 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Smile_Sunny521/article/details/101758339