Ali cloud docking SMS
1. Configure 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. Write Ali cloud send SMS Tools
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. Write method to send text messages
/**
* 发送短信
*
* @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. Other methods
Determine whether the standard phone number:
public static boolean isMobile(String mobile) {
if (isNotEmpty(mobile)) {
return Pattern.matches("^[1][0-9]{10}$", mobile);
}
return false;
}
safety verification:
/**
* 安全验证
*
* @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;
}
Get codes: random data (plain numbers):
/**
* 获取随机数据(纯数字)
*
* @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;
}
}