mirror of
https://gitee.com/dromara/sms4j.git
synced 2025-12-06 17:08:40 +08:00
!180 add 添加螺丝帽短信接入 并添加时间日期工具类
* add danmi短信接入 * update 补充配置案例 * add 添加SUBMAIL短信接入 * fix 腾讯云请求签名时间赋值错误 * update 提取短信异常发送结果 * add 添加螺丝帽短信接入 并添加时间日期工具类
This commit is contained in:
parent
98fa90ee1f
commit
9623b28b31
2
pom.xml
2
pom.xml
@ -61,7 +61,7 @@
|
|||||||
<solon.version>2.6.5</solon.version>
|
<solon.version>2.6.5</solon.version>
|
||||||
<redisson.version>3.17.0</redisson.version>
|
<redisson.version>3.17.0</redisson.version>
|
||||||
<jdcloud.version>1.3.3</jdcloud.version>
|
<jdcloud.version>1.3.3</jdcloud.version>
|
||||||
<hutool.version>5.8.26</hutool.version>
|
<hutool.version>5.8.28</hutool.version>
|
||||||
<xmlblend.version>2.3.0</xmlblend.version>
|
<xmlblend.version>2.3.0</xmlblend.version>
|
||||||
<activation.version>1.1.1</activation.version>
|
<activation.version>1.1.1</activation.version>
|
||||||
<mail.version>1.6.2</mail.version>
|
<mail.version>1.6.2</mail.version>
|
||||||
|
|||||||
@ -17,21 +17,45 @@ public abstract class Constant {
|
|||||||
* 用于格式化鉴权头域,给"Authorization"参数赋值
|
* 用于格式化鉴权头域,给"Authorization"参数赋值
|
||||||
*/
|
*/
|
||||||
public static final String HUAWEI_AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\"";
|
public static final String HUAWEI_AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\"";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用于格式化鉴权头域,给"X-WSSE"参数赋值
|
* 用于格式化鉴权头域,给"X-WSSE"参数赋值
|
||||||
*/
|
*/
|
||||||
public static final String HUAWEI_WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\"";
|
public static final String HUAWEI_WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\"";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 华为云国内短信访问URI
|
* 华为云国内短信访问URI
|
||||||
*/
|
*/
|
||||||
public static final String HUAWEI_REQUEST_URL = "/sms/batchSendSms/v1";
|
public static final String HUAWEI_REQUEST_URL = "/sms/batchSendSms/v1";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Content-Type
|
* Content-Type
|
||||||
*/
|
*/
|
||||||
public static final String FROM_URLENCODED = "application/x-www-form-urlencoded";
|
public static final String CONTENT_TYPE = "Content-Type";
|
||||||
|
|
||||||
public static final String ACCEPT = "application/json";
|
/**
|
||||||
|
* Authorization
|
||||||
|
*/
|
||||||
|
public static final String AUTHORIZATION = "Authorization";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accept
|
||||||
|
*/
|
||||||
|
public static final String ACCEPT = "Accept";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* x-www-form-urlencoded
|
||||||
|
*/
|
||||||
|
public static final String APPLICATION_FROM_URLENCODED = "application/x-www-form-urlencoded";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* application/json
|
||||||
|
*/
|
||||||
|
public static final String APPLICATION_JSON = "application/json";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* application/json; charset=utf-8
|
||||||
|
*/
|
||||||
public static final String APPLICATION_JSON_UTF8 = "application/json; charset=utf-8";
|
public static final String APPLICATION_JSON_UTF8 = "application/json; charset=utf-8";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,7 +66,7 @@ public abstract class Constant {
|
|||||||
/**
|
/**
|
||||||
* 云片短信国内短信请求地址
|
* 云片短信国内短信请求地址
|
||||||
*/
|
*/
|
||||||
public static final String YUNPIAN_URL = "https://sms.yunpian.com/v2";
|
public static final String YUNPIAN_URL = Constant.HTTPS_PREFIX + "sms.yunpian.com/v2";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https请求前缀
|
* https请求前缀
|
||||||
|
|||||||
@ -81,4 +81,16 @@ public abstract class SupplierConstant {
|
|||||||
* 百度云 sms
|
* 百度云 sms
|
||||||
*/
|
*/
|
||||||
public static final String BAIDU = "baidu";
|
public static final String BAIDU = "baidu";
|
||||||
|
/**
|
||||||
|
* 螺丝帽 sms
|
||||||
|
*/
|
||||||
|
public static final String LUO_SI_MAO = "luosimao";
|
||||||
|
/**
|
||||||
|
* SUBMAIL sms
|
||||||
|
*/
|
||||||
|
public static final String MY_SUBMAIL = "mysubmail";
|
||||||
|
/**
|
||||||
|
* danmi sms
|
||||||
|
*/
|
||||||
|
public static final String DAN_MI = "danmi";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package org.dromara.sms4j.comm.enumerate;
|
package org.dromara.sms4j.comm.enums;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@ -0,0 +1,215 @@
|
|||||||
|
package org.dromara.sms4j.comm.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DatePattern;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>类名: SmsDateUtils
|
||||||
|
* <p>说明: 时间日期工具类
|
||||||
|
*
|
||||||
|
* @author :bleachtred
|
||||||
|
* 2024/6/21 23:59
|
||||||
|
**/
|
||||||
|
public class SmsDateUtils extends DateUtil {
|
||||||
|
|
||||||
|
private SmsDateUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格林威治标准时间(GMT)或世界协调时间(UTC)
|
||||||
|
*/
|
||||||
|
private static final String GMT = "GMT";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 东八区
|
||||||
|
*/
|
||||||
|
private static final String GMT_8 = SmsDateUtils.GMT + "+8:00";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 天翼云、七牛云时间格式
|
||||||
|
*/
|
||||||
|
private static final String PURE_DATE_UTC_PATTERN = "yyyyMMdd'T'HHmmss'Z'";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取格林威治标准时间(GMT)或世界协调时间(UTC)
|
||||||
|
* @return TimeZone
|
||||||
|
*/
|
||||||
|
public static TimeZone gmt(){
|
||||||
|
return getTimeZone(GMT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取东八区时区
|
||||||
|
* @return TimeZone
|
||||||
|
*/
|
||||||
|
public static TimeZone gmt8(){
|
||||||
|
return getTimeZone(GMT_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取时区
|
||||||
|
* @param zoneId zoneId
|
||||||
|
* @return TimeZone
|
||||||
|
*/
|
||||||
|
public static TimeZone getTimeZone(String zoneId){
|
||||||
|
return TimeZone.getTimeZone(zoneId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取SimpleDateFormat
|
||||||
|
* @param pattern 时间格式
|
||||||
|
* @return SimpleDateFormat
|
||||||
|
*/
|
||||||
|
public static SimpleDateFormat sdfGmt(String pattern){
|
||||||
|
return sdf(pattern, gmt());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取SimpleDateFormat
|
||||||
|
* @param pattern 时间格式
|
||||||
|
* @return SimpleDateFormat
|
||||||
|
*/
|
||||||
|
public static SimpleDateFormat sdfGmt8(String pattern){
|
||||||
|
return sdf(pattern, gmt8());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取SimpleDateFormat
|
||||||
|
* @param pattern 时间格式
|
||||||
|
* @param timeZone 时区
|
||||||
|
* @return 获取SimpleDateFormat
|
||||||
|
*/
|
||||||
|
public static SimpleDateFormat sdf(String pattern, TimeZone timeZone){
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
|
||||||
|
sdf.setTimeZone(timeZone);
|
||||||
|
return sdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化时间
|
||||||
|
* @param date 时间
|
||||||
|
* @param pattern 时间格式
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String formatGmtDateToStr(Date date, String pattern){
|
||||||
|
SimpleDateFormat sdf = sdfGmt(pattern);
|
||||||
|
return sdf.format(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化时间
|
||||||
|
* @param date 时间
|
||||||
|
* @param pattern 时间格式
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String formatGmt8DateToStr(Date date, String pattern){
|
||||||
|
SimpleDateFormat sdf = sdfGmt8(pattern);
|
||||||
|
return sdf.format(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化时间
|
||||||
|
* @param date 时间
|
||||||
|
* @param pattern 时间格式
|
||||||
|
* @param timeZone 时区
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String formatDateToStr(Date date, String pattern, TimeZone timeZone){
|
||||||
|
SimpleDateFormat sdf = sdf(pattern, timeZone);
|
||||||
|
return sdf.format(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期格式:yyyy-MM-dd'T'HH:mm:ss'Z'
|
||||||
|
* @param date 时间
|
||||||
|
* @return 时间字符串
|
||||||
|
*/
|
||||||
|
public static String utcGmt(Date date){
|
||||||
|
return formatGmtDateToStr(date, DatePattern.UTC_PATTERN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期格式:yyyy-MM-dd'T'HH:mm:ss'Z'
|
||||||
|
* @param date 时间
|
||||||
|
* @return 时间字符串
|
||||||
|
*/
|
||||||
|
public static String utcGmt8(Date date){
|
||||||
|
return formatGmt8DateToStr(date, DatePattern.UTC_PATTERN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期格式:yyyyMMdd
|
||||||
|
* @param date 时间
|
||||||
|
* @return 时间字符串
|
||||||
|
*/
|
||||||
|
public static String pureDateGmt(Date date){
|
||||||
|
return formatGmtDateToStr(date, DatePattern.PURE_DATE_PATTERN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期格式:yyyyMMdd
|
||||||
|
* @param date 时间
|
||||||
|
* @return 时间字符串
|
||||||
|
*/
|
||||||
|
public static String pureDateGmt8(Date date){
|
||||||
|
return formatGmt8DateToStr(date, DatePattern.PURE_DATE_PATTERN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 天翼云、七牛云时间格式:yyyyMMdd'T'HHmmss'Z'
|
||||||
|
* @param date 时间
|
||||||
|
* @return 时间字符串
|
||||||
|
*/
|
||||||
|
public static String pureDateUtcGmt(Date date){
|
||||||
|
return formatGmtDateToStr(date, PURE_DATE_UTC_PATTERN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 天翼云、七牛云时间格式:yyyyMMdd'T'HHmmss'Z'
|
||||||
|
* @param date 时间
|
||||||
|
* @return 时间字符串
|
||||||
|
*/
|
||||||
|
public static String pureDateUtcGmt8(Date date){
|
||||||
|
return formatGmt8DateToStr(date, PURE_DATE_UTC_PATTERN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期格式:yyyy-MM-dd
|
||||||
|
* @param date 时间
|
||||||
|
* @return 时间字符串
|
||||||
|
*/
|
||||||
|
public static String normDateGmt(Date date){
|
||||||
|
return formatGmtDateToStr(date, DatePattern.NORM_DATE_PATTERN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期格式:yyyy-MM-dd
|
||||||
|
* @param date 时间
|
||||||
|
* @return 时间字符串
|
||||||
|
*/
|
||||||
|
public static String normDateGmt8(Date date){
|
||||||
|
return formatGmt8DateToStr(date, DatePattern.NORM_DATE_PATTERN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期格式:yyyy-MM-dd HH:mm:ss
|
||||||
|
* @param date 时间
|
||||||
|
* @return 时间字符串
|
||||||
|
*/
|
||||||
|
public static String normDatetimeGmt(Date date){
|
||||||
|
return formatGmtDateToStr(date, DatePattern.NORM_DATETIME_PATTERN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期格式:yyyy-MM-dd HH:mm:ss
|
||||||
|
* @param date 时间
|
||||||
|
* @return 时间字符串
|
||||||
|
*/
|
||||||
|
public static String normDatetimeGmt8(Date date){
|
||||||
|
return formatGmt8DateToStr(date, DatePattern.NORM_DATETIME_PATTERN);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -73,6 +73,28 @@ public class SmsHttpUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送post form 请求
|
||||||
|
*
|
||||||
|
* @param url 请求地址
|
||||||
|
* @param headers 请求头
|
||||||
|
* @param body 请求体(map格式请求体)
|
||||||
|
* @param username 用户名
|
||||||
|
* @param password 密码
|
||||||
|
* @return 返回体
|
||||||
|
*/
|
||||||
|
public JSONObject postBasicFrom(String url, Map<String, String> headers, String username, String password, Map<String, Object> body) {
|
||||||
|
try (HttpResponse response = HttpRequest.post(url)
|
||||||
|
.addHeaders(headers)
|
||||||
|
.basicAuth(username, password)
|
||||||
|
.form(body)
|
||||||
|
.execute()) {
|
||||||
|
return JSONUtil.parseObj(response.body());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new SmsBlendException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送post url 参数拼装url传输
|
* 发送post url 参数拼装url传输
|
||||||
*
|
*
|
||||||
@ -92,6 +114,37 @@ public class SmsHttpUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送get
|
||||||
|
*
|
||||||
|
* @param url 请求地址
|
||||||
|
* @return 返回体
|
||||||
|
*/
|
||||||
|
public JSONObject getBasic(String url, String username, String password) {
|
||||||
|
try (HttpResponse response = HttpRequest.get(url)
|
||||||
|
.basicAuth(username, password)
|
||||||
|
.execute()) {
|
||||||
|
return JSONUtil.parseObj(response.body());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new SmsBlendException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送get
|
||||||
|
*
|
||||||
|
* @param url 请求地址
|
||||||
|
* @return 返回体
|
||||||
|
*/
|
||||||
|
public JSONObject getUrl(String url) {
|
||||||
|
try (HttpResponse response = HttpRequest.get(url)
|
||||||
|
.execute()) {
|
||||||
|
return JSONUtil.parseObj(response.body());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new SmsBlendException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 线程睡眠
|
* 线程睡眠
|
||||||
*
|
*
|
||||||
|
|||||||
@ -2,6 +2,9 @@ package org.dromara.sms4j.comm.utils;
|
|||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.RandomUtil;
|
import cn.hutool.core.util.RandomUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
@ -112,18 +115,38 @@ public class SmsUtils {
|
|||||||
* @param list 要转换的list
|
* @param list 要转换的list
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public static String listToString(List<String> list) {
|
public static String joinComma(List<String> list) {
|
||||||
return CollUtil.join(list, ",");
|
return CollUtil.join(list, StrUtil.COMMA);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 以 conjunction 为分隔符将集合转换为字符串
|
* 切分字符串
|
||||||
*
|
*
|
||||||
* @param list 集合
|
* @param str 被切分的字符串
|
||||||
|
* @return 分割后的数据列表
|
||||||
|
*/
|
||||||
|
public static List<String> splitTrimComma(String str) {
|
||||||
|
return StrUtil.splitTrim(str, StrUtil.COMMA);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将手机号码 添加+86中国的电话国际区号前缀
|
||||||
|
*
|
||||||
|
* @param phones 手机号码集合
|
||||||
* @return 结果字符串
|
* @return 结果字符串
|
||||||
*/
|
*/
|
||||||
public static String arrayToString(List<String> list) {
|
public static String addCodePrefixIfNot(List<String> phones) {
|
||||||
return CollUtil.join(list, ",", str -> StrUtil.addPrefixIfNot(str, "+86"));
|
return CollUtil.join(phones, StrUtil.COMMA, SmsUtils::addCodePrefixIfNot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将手机号码 添加+86电话区号前缀
|
||||||
|
*
|
||||||
|
* @param phone 手机号码
|
||||||
|
* @return 结果字符串
|
||||||
|
*/
|
||||||
|
public static String addCodePrefixIfNot(String phone) {
|
||||||
|
return StrUtil.addPrefixIfNot(phone, "+86");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -132,10 +155,10 @@ public class SmsUtils {
|
|||||||
* @param list 集合
|
* @param list 集合
|
||||||
* @return 结果字符串
|
* @return 结果字符串
|
||||||
*/
|
*/
|
||||||
public static String[] listToArray(List<String> list) {
|
public static String[] addCodePrefixIfNotToArray(List<String> list) {
|
||||||
List<String> toStr = new ArrayList<>();
|
List<String> toStr = new ArrayList<>();
|
||||||
for (String s : list) {
|
for (String s : list) {
|
||||||
toStr.add(StrUtil.addPrefixIfNot(s, "+86"));
|
toStr.add(addCodePrefixIfNot(s));
|
||||||
}
|
}
|
||||||
return toStr.toArray(new String[list.size()]);
|
return toStr.toArray(new String[list.size()]);
|
||||||
}
|
}
|
||||||
@ -199,4 +222,48 @@ public class SmsUtils {
|
|||||||
}
|
}
|
||||||
return list.stream().filter(predicate).map(mapper).toArray(size -> array.clone());
|
return list.stream().filter(predicate).map(mapper).toArray(size -> array.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将map的value转成数组
|
||||||
|
* @param map Map
|
||||||
|
* @return 数组
|
||||||
|
*/
|
||||||
|
public static String[] toArray(Map<String, String> map){
|
||||||
|
if (isEmpty(map)) {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
return toArray(map.values(), SmsUtils::isNotEmpty, s -> s, new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将所有提交的参数升序排列,并排除部分key字段后,将key与value用"="连接起来 组成"key=value" + "&"(连接符)+ "key=value" 的方式
|
||||||
|
* @param params 参数Map
|
||||||
|
* @param excludes 排除的key
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String sortedParamsAsc(Map<String, Object> params, String... excludes) {
|
||||||
|
if (MapUtil.isEmpty(params)){
|
||||||
|
return StrUtil.EMPTY;
|
||||||
|
}
|
||||||
|
List<String> keys = new ArrayList<>(params.keySet());
|
||||||
|
if (CollUtil.isEmpty(keys)){
|
||||||
|
return StrUtil.EMPTY;
|
||||||
|
}
|
||||||
|
if (ArrayUtil.isNotEmpty(excludes)){
|
||||||
|
ArrayList<String> excludeKeys = CollUtil.toList(excludes);
|
||||||
|
keys.removeIf(key -> excludeKeys.stream().anyMatch(exclude -> exclude.equals(key)));
|
||||||
|
if (CollUtil.isEmpty(keys)){
|
||||||
|
return StrUtil.EMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(keys);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (String key : keys) {
|
||||||
|
sb.append(key).append("=").append(Convert.toStr(params.get(key))).append("&");
|
||||||
|
}
|
||||||
|
if (sb.length() > 0) {
|
||||||
|
sb.setLength(sb.length() - 1); // Remove the last '&'
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -31,6 +31,7 @@ import org.dromara.sms4j.core.proxy.processor.CoreMethodParamValidateProcessor;
|
|||||||
import org.dromara.sms4j.core.proxy.processor.RestrictedProcessor;
|
import org.dromara.sms4j.core.proxy.processor.RestrictedProcessor;
|
||||||
import org.dromara.sms4j.core.proxy.processor.SingleBlendRestrictedProcessor;
|
import org.dromara.sms4j.core.proxy.processor.SingleBlendRestrictedProcessor;
|
||||||
import org.dromara.sms4j.ctyun.config.CtyunFactory;
|
import org.dromara.sms4j.ctyun.config.CtyunFactory;
|
||||||
|
import org.dromara.sms4j.danmi.config.DanMiFactory;
|
||||||
import org.dromara.sms4j.dingzhong.config.DingZhongFactory;
|
import org.dromara.sms4j.dingzhong.config.DingZhongFactory;
|
||||||
import org.dromara.sms4j.emay.config.EmayFactory;
|
import org.dromara.sms4j.emay.config.EmayFactory;
|
||||||
import org.dromara.sms4j.huawei.config.HuaweiFactory;
|
import org.dromara.sms4j.huawei.config.HuaweiFactory;
|
||||||
@ -39,6 +40,7 @@ import org.dromara.sms4j.jdcloud.config.JdCloudFactory;
|
|||||||
import org.dromara.sms4j.chuanglan.config.ChuangLanFactory;
|
import org.dromara.sms4j.chuanglan.config.ChuangLanFactory;
|
||||||
import org.dromara.sms4j.jg.config.JgFactory;
|
import org.dromara.sms4j.jg.config.JgFactory;
|
||||||
import org.dromara.sms4j.lianlu.config.LianLuFactory;
|
import org.dromara.sms4j.lianlu.config.LianLuFactory;
|
||||||
|
import org.dromara.sms4j.luosimao.config.LuoSiMaoFactory;
|
||||||
import org.dromara.sms4j.mas.config.MasFactory;
|
import org.dromara.sms4j.mas.config.MasFactory;
|
||||||
import org.dromara.sms4j.netease.config.NeteaseFactory;
|
import org.dromara.sms4j.netease.config.NeteaseFactory;
|
||||||
import org.dromara.sms4j.provider.config.SmsConfig;
|
import org.dromara.sms4j.provider.config.SmsConfig;
|
||||||
@ -46,6 +48,7 @@ import org.dromara.sms4j.provider.factory.BaseProviderFactory;
|
|||||||
import org.dromara.sms4j.provider.factory.BeanFactory;
|
import org.dromara.sms4j.provider.factory.BeanFactory;
|
||||||
import org.dromara.sms4j.provider.factory.ProviderFactoryHolder;
|
import org.dromara.sms4j.provider.factory.ProviderFactoryHolder;
|
||||||
import org.dromara.sms4j.qiniu.config.QiNiuFactory;
|
import org.dromara.sms4j.qiniu.config.QiNiuFactory;
|
||||||
|
import org.dromara.sms4j.submail.config.SubMailFactory;
|
||||||
import org.dromara.sms4j.tencent.config.TencentFactory;
|
import org.dromara.sms4j.tencent.config.TencentFactory;
|
||||||
import org.dromara.sms4j.unisms.config.UniFactory;
|
import org.dromara.sms4j.unisms.config.UniFactory;
|
||||||
import org.dromara.sms4j.yunpian.config.YunPianFactory;
|
import org.dromara.sms4j.yunpian.config.YunPianFactory;
|
||||||
@ -234,7 +237,7 @@ public class SEInitializer {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
configMap.put("config-id", configId);
|
configMap.put("config-id", configId);
|
||||||
SmsUtils.replaceKeysSeperator(configMap, "-", "_");
|
SmsUtils.replaceKeysSeparator(configMap, "-", "_");
|
||||||
JSONObject configJson = new JSONObject(configMap);
|
JSONObject configJson = new JSONObject(configMap);
|
||||||
SupplierConfig supplierConfig = JSONUtil.toBean(configJson, providerFactory.getConfigClass());
|
SupplierConfig supplierConfig = JSONUtil.toBean(configJson, providerFactory.getConfigClass());
|
||||||
SmsFactory.createSmsBlend(supplierConfig);
|
SmsFactory.createSmsBlend(supplierConfig);
|
||||||
@ -257,12 +260,15 @@ public class SEInitializer {
|
|||||||
ProviderFactoryHolder.registerFactory(ZhutongFactory.instance());
|
ProviderFactoryHolder.registerFactory(ZhutongFactory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(LianLuFactory.instance());
|
ProviderFactoryHolder.registerFactory(LianLuFactory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(DingZhongFactory.instance());
|
ProviderFactoryHolder.registerFactory(DingZhongFactory.instance());
|
||||||
|
ProviderFactoryHolder.registerFactory(QiNiuFactory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(ChuangLanFactory.instance());
|
ProviderFactoryHolder.registerFactory(ChuangLanFactory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(JgFactory.instance());
|
ProviderFactoryHolder.registerFactory(JgFactory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(QiNiuFactory.instance());
|
|
||||||
ProviderFactoryHolder.registerFactory(BudingV2Factory.instance());
|
ProviderFactoryHolder.registerFactory(BudingV2Factory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(MasFactory.instance());
|
ProviderFactoryHolder.registerFactory(MasFactory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(BaiduFactory.instance());
|
ProviderFactoryHolder.registerFactory(BaiduFactory.instance());
|
||||||
|
ProviderFactoryHolder.registerFactory(LuoSiMaoFactory.instance());
|
||||||
|
ProviderFactoryHolder.registerFactory(SubMailFactory.instance());
|
||||||
|
ProviderFactoryHolder.registerFactory(DanMiFactory.instance());
|
||||||
if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
|
if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
|
||||||
ProviderFactoryHolder.registerFactory(JdCloudFactory.instance());
|
ProviderFactoryHolder.registerFactory(JdCloudFactory.instance());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -93,7 +93,7 @@ public class AlibabaSmsImpl extends AbstractSmsBlend<AlibabaConfig> {
|
|||||||
messages = new LinkedHashMap<>();
|
messages = new LinkedHashMap<>();
|
||||||
}
|
}
|
||||||
String messageStr = JSONUtil.toJsonStr(messages);
|
String messageStr = JSONUtil.toJsonStr(messages);
|
||||||
return getSmsResponse(SmsUtils.arrayToString(phones), messageStr, templateId);
|
return getSmsResponse(SmsUtils.addCodePrefixIfNot(phones), messageStr, templateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SmsResponse getSmsResponse(String phone, String message, String templateId) {
|
private SmsResponse getSmsResponse(String phone, String message, String templateId) {
|
||||||
@ -109,12 +109,12 @@ public class AlibabaSmsImpl extends AbstractSmsBlend<AlibabaConfig> {
|
|||||||
log.debug("requestUrl {}", requestUrl);
|
log.debug("requestUrl {}", requestUrl);
|
||||||
|
|
||||||
Map<String, String> headers = MapUtil.newHashMap(1, true);
|
Map<String, String> headers = MapUtil.newHashMap(1, true);
|
||||||
headers.put("Content-Type", Constant.FROM_URLENCODED);
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_FROM_URLENCODED);
|
||||||
SmsResponse smsResponse;
|
SmsResponse smsResponse;
|
||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postJson(requestUrl, headers, paramStr));
|
smsResponse = getResponse(http.postJson(requestUrl, headers, paramStr));
|
||||||
} catch (SmsBlendException e) {
|
} catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.getMessage(), getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
|
|||||||
@ -4,15 +4,14 @@ import cn.hutool.crypto.digest.HMac;
|
|||||||
import cn.hutool.crypto.digest.HmacAlgorithm;
|
import cn.hutool.crypto.digest.HmacAlgorithm;
|
||||||
import org.dromara.sms4j.aliyun.config.AlibabaConfig;
|
import org.dromara.sms4j.aliyun.config.AlibabaConfig;
|
||||||
import org.dromara.sms4j.comm.constant.Constant;
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
|
import org.dromara.sms4j.comm.utils.SmsDateUtils;
|
||||||
|
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.SimpleTimeZone;
|
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@ -27,18 +26,15 @@ public class AliyunUtils {
|
|||||||
*/
|
*/
|
||||||
private static final String ALGORITHM = "HMAC-SHA1";
|
private static final String ALGORITHM = "HMAC-SHA1";
|
||||||
|
|
||||||
private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
|
||||||
|
|
||||||
public static String generateSendSmsRequestUrl(AlibabaConfig alibabaConfig, String message, String phone, String templateId) throws Exception {
|
public static String generateSendSmsRequestUrl(AlibabaConfig alibabaConfig, String message, String phone, String templateId) throws Exception {
|
||||||
// 这里一定要设置GMT时区
|
// 这里一定要设置GMT时区
|
||||||
SDF.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
|
||||||
Map<String, String> paras = new HashMap<>();
|
Map<String, String> paras = new HashMap<>();
|
||||||
// 1. 公共请求参数
|
// 1. 公共请求参数
|
||||||
paras.put("SignatureMethod", ALGORITHM);
|
paras.put("SignatureMethod", ALGORITHM);
|
||||||
paras.put("SignatureNonce", UUID.randomUUID().toString());
|
paras.put("SignatureNonce", UUID.randomUUID().toString());
|
||||||
paras.put("AccessKeyId", alibabaConfig.getAccessKeyId());
|
paras.put("AccessKeyId", alibabaConfig.getAccessKeyId());
|
||||||
paras.put("SignatureVersion", "1.0");
|
paras.put("SignatureVersion", "1.0");
|
||||||
paras.put("Timestamp", SDF.format(new Date()));
|
paras.put("Timestamp", SmsDateUtils.utcGmt(new Date()));
|
||||||
paras.put("Format", "JSON");
|
paras.put("Format", "JSON");
|
||||||
paras.put("Action", alibabaConfig.getAction());
|
paras.put("Action", alibabaConfig.getAction());
|
||||||
paras.put("Version", alibabaConfig.getVersion());
|
paras.put("Version", alibabaConfig.getVersion());
|
||||||
@ -110,10 +106,10 @@ public class AliyunUtils {
|
|||||||
/**
|
/**
|
||||||
* 生成请求参数body字符串
|
* 生成请求参数body字符串
|
||||||
*
|
*
|
||||||
* @param alibabaConfig
|
* @param alibabaConfig 配置数据
|
||||||
* @param phone
|
* @param phone 手机号
|
||||||
* @param message
|
* @param message 短信内容
|
||||||
* @param templateId
|
* @param templateId 模板id
|
||||||
*/
|
*/
|
||||||
public static String generateParamBody(AlibabaConfig alibabaConfig, String phone, String message, String templateId) throws Exception {
|
public static String generateParamBody(AlibabaConfig alibabaConfig, String phone, String message, String templateId) throws Exception {
|
||||||
Map<String, String> paramMap = generateParamMap(alibabaConfig, phone, message, templateId);
|
Map<String, String> paramMap = generateParamMap(alibabaConfig, phone, message, templateId);
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package org.dromara.sms4j.baidu.config;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
import org.dromara.sms4j.provider.config.BaseConfig;
|
import org.dromara.sms4j.provider.config.BaseConfig;
|
||||||
|
|
||||||
@ -9,7 +10,7 @@ import org.dromara.sms4j.provider.config.BaseConfig;
|
|||||||
* <p>类名: BaiduConfig
|
* <p>类名: BaiduConfig
|
||||||
* <p>说明:百度智能云 sms
|
* <p>说明:百度智能云 sms
|
||||||
*
|
*
|
||||||
* @author :bleachhtred
|
* @author :bleachtred
|
||||||
* 2024/4/25 13:40
|
* 2024/4/25 13:40
|
||||||
**/
|
**/
|
||||||
@Data
|
@Data
|
||||||
@ -19,7 +20,7 @@ public class BaiduConfig extends BaseConfig {
|
|||||||
/**
|
/**
|
||||||
* 请求地址
|
* 请求地址
|
||||||
*/
|
*/
|
||||||
private String host = "https://smsv3.bj.baidubce.com";
|
private String host = Constant.HTTPS_PREFIX + "smsv3.bj.baidubce.com";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接口名称
|
* 接口名称
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import org.dromara.sms4j.provider.factory.AbstractProviderFactory;
|
|||||||
* <p>类名: BaiduFactory
|
* <p>类名: BaiduFactory
|
||||||
* <p>说明:百度智能云 sms
|
* <p>说明:百度智能云 sms
|
||||||
*
|
*
|
||||||
* @author :bleachhtred
|
* @author :bleachtred
|
||||||
* 2024/4/25 13:40
|
* 2024/4/25 13:40
|
||||||
**/
|
**/
|
||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
@ -30,7 +30,7 @@ public class BaiduFactory extends AbstractProviderFactory<BaiduSmsImpl, BaiduCon
|
|||||||
* createSms
|
* createSms
|
||||||
* <p> 建造一个短信实现对像
|
* <p> 建造一个短信实现对像
|
||||||
*
|
*
|
||||||
* @author :bleachhtred
|
* @author :bleachtred
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public BaiduSmsImpl createSms(BaiduConfig baiduConfig) {
|
public BaiduSmsImpl createSms(BaiduConfig baiduConfig) {
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import java.util.concurrent.Executor;
|
|||||||
* <p>类名: BaiduSmsImpl
|
* <p>类名: BaiduSmsImpl
|
||||||
* <p>说明:百度智能云 sms
|
* <p>说明:百度智能云 sms
|
||||||
*
|
*
|
||||||
* @author :bleachhtred
|
* @author :bleachtred
|
||||||
* 2024/4/25 13:40
|
* 2024/4/25 13:40
|
||||||
**/
|
**/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -79,7 +79,7 @@ public class BaiduSmsImpl extends AbstractSmsBlend<BaiduConfig> {
|
|||||||
if (CollUtil.isEmpty(messages)){
|
if (CollUtil.isEmpty(messages)){
|
||||||
messages = new LinkedHashMap<>();
|
messages = new LinkedHashMap<>();
|
||||||
}
|
}
|
||||||
return getSmsResponse(SmsUtils.arrayToString(phones), templateId, messages);
|
return getSmsResponse(SmsUtils.addCodePrefixIfNot(phones), templateId, messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SmsResponse getSmsResponse(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
private SmsResponse getSmsResponse(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
||||||
@ -128,7 +128,7 @@ public class BaiduSmsImpl extends AbstractSmsBlend<BaiduConfig> {
|
|||||||
if (CollUtil.isEmpty(messages)){
|
if (CollUtil.isEmpty(messages)){
|
||||||
messages = new LinkedHashMap<>();
|
messages = new LinkedHashMap<>();
|
||||||
}
|
}
|
||||||
return getSmsResponseWithClientToken(SmsUtils.arrayToString(phones), templateId, messages, clientToken);
|
return getSmsResponseWithClientToken(SmsUtils.addCodePrefixIfNot(phones), templateId, messages, clientToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SmsResponse getSmsResponseWithClientToken(String phone, String templateId, LinkedHashMap<String, String> messages, String clientToken) {
|
private SmsResponse getSmsResponseWithClientToken(String phone, String templateId, LinkedHashMap<String, String> messages, String clientToken) {
|
||||||
@ -158,7 +158,7 @@ public class BaiduSmsImpl extends AbstractSmsBlend<BaiduConfig> {
|
|||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postJson(config.getHost() + config.getAction(), headers, body));
|
smsResponse = getResponse(http.postJson(config.getHost() + config.getAction(), headers, body));
|
||||||
} catch (SmsBlendException e) {
|
} catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.getMessage(), getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == config.getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == config.getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
|
|||||||
@ -8,25 +8,23 @@ import lombok.AccessLevel;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.sms4j.baidu.config.BaiduConfig;
|
import org.dromara.sms4j.baidu.config.BaiduConfig;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
|
import org.dromara.sms4j.comm.utils.SmsDateUtils;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
public class BaiduUtils {
|
public class BaiduUtils {
|
||||||
|
|
||||||
private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建前缀字符串
|
* 创建前缀字符串
|
||||||
* @param accessKeyId 访问密钥ID
|
* @param accessKeyId 访问密钥ID
|
||||||
* @return bce-auth-v1/{accessKeyId}/{timestamp}/{expirationPeriodInSeconds }
|
* @return bce-auth-v1/{accessKeyId}/{timestamp}/{expirationPeriodInSeconds }
|
||||||
*/
|
*/
|
||||||
private static String authStringPrefix(String accessKeyId){
|
private static String authStringPrefix(String accessKeyId){
|
||||||
SDF.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
return "bce-auth-v1/" + accessKeyId + "/" + SmsDateUtils.utcGmt(new Date()) + "/1800";
|
||||||
return "bce-auth-v1/" + accessKeyId + "/" + SDF.format(new Date()) + "/1800";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -98,7 +96,7 @@ public class BaiduUtils {
|
|||||||
String authorization = authStringPrefix + "/" + "/" + signature;
|
String authorization = authStringPrefix + "/" + "/" + signature;
|
||||||
|
|
||||||
Map<String, String> headers = new HashMap<>(2);
|
Map<String, String> headers = new HashMap<>(2);
|
||||||
headers.put("Authorization", authorization);
|
headers.put(Constant.AUTHORIZATION, authorization);
|
||||||
headers.put("host", config.getHost());
|
headers.put("host", config.getHost());
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ public class BudingV2SmsImpl extends AbstractSmsBlend<BudingV2Config> {
|
|||||||
*/
|
*/
|
||||||
private int retry = 0;
|
private int retry = 0;
|
||||||
|
|
||||||
private static final String URL = "https://smsapi.idcbdy.com";
|
private static final String URL = Constant.HTTPS_PREFIX + "smsapi.idcbdy.com";
|
||||||
|
|
||||||
protected BudingV2SmsImpl(BudingV2Config config, Executor pool, DelayedTime delayed) {
|
protected BudingV2SmsImpl(BudingV2Config config, Executor pool, DelayedTime delayed) {
|
||||||
super(config, pool, delayed);
|
super(config, pool, delayed);
|
||||||
@ -70,7 +70,7 @@ public class BudingV2SmsImpl extends AbstractSmsBlend<BudingV2Config> {
|
|||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postFrom(URL + "/Api/Sent", headers, body));
|
smsResponse = getResponse(http.postFrom(URL + "/Api/Sent", headers, body));
|
||||||
} catch (SmsBlendException e) {
|
} catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.getMessage(), getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
@ -155,8 +155,8 @@ public class BudingV2SmsImpl extends AbstractSmsBlend<BudingV2Config> {
|
|||||||
|
|
||||||
private Map<String, String> getHeaders() {
|
private Map<String, String> getHeaders() {
|
||||||
Map<String, String> headers = new HashMap<>();
|
Map<String, String> headers = new HashMap<>();
|
||||||
headers.put("Accept", Constant.APPLICATION_JSON_UTF8);
|
headers.put(Constant.ACCEPT, Constant.APPLICATION_JSON_UTF8);
|
||||||
headers.put("Content-Type", Constant.FROM_URLENCODED);
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_FROM_URLENCODED);
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package org.dromara.sms4j.chuanglan.config;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
import org.dromara.sms4j.provider.config.BaseConfig;
|
import org.dromara.sms4j.provider.config.BaseConfig;
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ public class ChuangLanConfig extends BaseConfig {
|
|||||||
/**
|
/**
|
||||||
* 基础路径
|
* 基础路径
|
||||||
*/
|
*/
|
||||||
private String baseUrl = "https://smssh1.253.com/msg";
|
private String baseUrl = Constant.HTTPS_PREFIX + "smssh1.253.com/msg";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 短信发送路径
|
* 短信发送路径
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.dromara.sms4j.api.entity.SmsResponse;
|
import org.dromara.sms4j.api.entity.SmsResponse;
|
||||||
import org.dromara.sms4j.api.utils.SmsRespUtils;
|
import org.dromara.sms4j.api.utils.SmsRespUtils;
|
||||||
import org.dromara.sms4j.chuanglan.config.ChuangLanConfig;
|
import org.dromara.sms4j.chuanglan.config.ChuangLanConfig;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
import org.dromara.sms4j.comm.delayedTime.DelayedTime;
|
import org.dromara.sms4j.comm.delayedTime.DelayedTime;
|
||||||
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
@ -85,7 +86,7 @@ public class ChuangLanSmsImpl extends AbstractSmsBlend<ChuangLanConfig> {
|
|||||||
|
|
||||||
private static LinkedHashMap<String, String> buildHeaders(){
|
private static LinkedHashMap<String, String> buildHeaders(){
|
||||||
LinkedHashMap<String, String> headers = new LinkedHashMap<>(1);
|
LinkedHashMap<String, String> headers = new LinkedHashMap<>(1);
|
||||||
headers.put("Content-Type", "application/json");
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_JSON);
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +105,7 @@ public class ChuangLanSmsImpl extends AbstractSmsBlend<ChuangLanConfig> {
|
|||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postJson(reqUrl, buildHeaders(), body));
|
smsResponse = getResponse(http.postJson(reqUrl, buildHeaders(), body));
|
||||||
}catch (SmsBlendException e) {
|
}catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.getMessage(), getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package org.dromara.sms4j.cloopen.config;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
import org.dromara.sms4j.provider.config.BaseConfig;
|
import org.dromara.sms4j.provider.config.BaseConfig;
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ public class CloopenConfig extends BaseConfig {
|
|||||||
/**
|
/**
|
||||||
* REST API Base URL
|
* REST API Base URL
|
||||||
*/
|
*/
|
||||||
private String baseUrl = "https://app.cloopen.com:8883/2013-12-26";
|
private String baseUrl = Constant.HTTPS_PREFIX + "app.cloopen.com:8883/2013-12-26";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取供应商
|
* 获取供应商
|
||||||
|
|||||||
@ -44,9 +44,9 @@ public class CloopenHelper {
|
|||||||
config.getAccessKeyId(),
|
config.getAccessKeyId(),
|
||||||
this.generateSign(config.getAccessKeyId(), config.getAccessKeySecret(), timestamp));
|
this.generateSign(config.getAccessKeyId(), config.getAccessKeySecret(), timestamp));
|
||||||
Map<String, String> headers = MapUtil.newHashMap(3, true);
|
Map<String, String> headers = MapUtil.newHashMap(3, true);
|
||||||
headers.put("Accept", Constant.ACCEPT);
|
headers.put(Constant.ACCEPT, Constant.APPLICATION_JSON);
|
||||||
headers.put("Content-Type", Constant.APPLICATION_JSON_UTF8);
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_JSON_UTF8);
|
||||||
headers.put("Authorization", this.generateAuthorization(config.getAccessKeyId(), timestamp));
|
headers.put(Constant.AUTHORIZATION, this.generateAuthorization(config.getAccessKeyId(), timestamp));
|
||||||
SmsResponse smsResponse;
|
SmsResponse smsResponse;
|
||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postJson(url, headers, paramMap));
|
smsResponse = getResponse(http.postJson(url, headers, paramMap));
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package org.dromara.sms4j.ctyun.config;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
import org.dromara.sms4j.provider.config.BaseConfig;
|
import org.dromara.sms4j.provider.config.BaseConfig;
|
||||||
|
|
||||||
@ -9,7 +10,7 @@ import org.dromara.sms4j.provider.config.BaseConfig;
|
|||||||
* <p>类名: CtyunConfig
|
* <p>类名: CtyunConfig
|
||||||
* <p>说明: 天翼云短信差异配置
|
* <p>说明: 天翼云短信差异配置
|
||||||
*
|
*
|
||||||
* @author :bleachhtred
|
* @author :bleachtred
|
||||||
* 2023/5/12 15:06
|
* 2023/5/12 15:06
|
||||||
**/
|
**/
|
||||||
@Data
|
@Data
|
||||||
@ -24,7 +25,7 @@ public class CtyunConfig extends BaseConfig {
|
|||||||
/**
|
/**
|
||||||
* 请求地址
|
* 请求地址
|
||||||
*/
|
*/
|
||||||
private String requestUrl = "https://sms-global.ctapi.ctyun.cn/sms/api/v1";
|
private String requestUrl = Constant.HTTPS_PREFIX + "sms-global.ctapi.ctyun.cn/sms/api/v1";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接口名称
|
* 接口名称
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import org.dromara.sms4j.provider.factory.AbstractProviderFactory;
|
|||||||
* <p>类名: CtyunSmsConfig
|
* <p>类名: CtyunSmsConfig
|
||||||
* <p>说明: 天翼云 云通信短信配置器
|
* <p>说明: 天翼云 云通信短信配置器
|
||||||
*
|
*
|
||||||
* @author :bleachhtred
|
* @author :bleachtred
|
||||||
* 2023/5/12 15:06
|
* 2023/5/12 15:06
|
||||||
**/
|
**/
|
||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
@ -30,7 +30,7 @@ public class CtyunFactory extends AbstractProviderFactory<CtyunSmsImpl, CtyunCon
|
|||||||
* getCtyunSms
|
* getCtyunSms
|
||||||
* <p> 建造一个短信实现对像
|
* <p> 建造一个短信实现对像
|
||||||
*
|
*
|
||||||
* @author :bleachhtred
|
* @author :bleachtred
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public CtyunSmsImpl createSms(CtyunConfig ctyunConfig) {
|
public CtyunSmsImpl createSms(CtyunConfig ctyunConfig) {
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import java.util.concurrent.Executor;
|
|||||||
* <p>类名: CtyunSmsImpl
|
* <p>类名: CtyunSmsImpl
|
||||||
* <p>说明: 天翼云短信实现
|
* <p>说明: 天翼云短信实现
|
||||||
*
|
*
|
||||||
* @author :bleachhtred
|
* @author :bleachtred
|
||||||
* 2023/5/12 15:06
|
* 2023/5/12 15:06
|
||||||
**/
|
**/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -80,7 +80,7 @@ public class CtyunSmsImpl extends AbstractSmsBlend<CtyunConfig> {
|
|||||||
messages = new LinkedHashMap<>();
|
messages = new LinkedHashMap<>();
|
||||||
}
|
}
|
||||||
String messageStr = JSONUtil.toJsonStr(messages);
|
String messageStr = JSONUtil.toJsonStr(messages);
|
||||||
return getSmsResponse(SmsUtils.arrayToString(phones), messageStr, templateId);
|
return getSmsResponse(SmsUtils.addCodePrefixIfNot(phones), messageStr, templateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SmsResponse getSmsResponse(String phone, String message, String templateId) {
|
private SmsResponse getSmsResponse(String phone, String message, String templateId) {
|
||||||
@ -101,7 +101,7 @@ public class CtyunSmsImpl extends AbstractSmsBlend<CtyunConfig> {
|
|||||||
CtyunUtils.signHeader(paramStr, config.getAccessKeyId(), config.getAccessKeySecret()),
|
CtyunUtils.signHeader(paramStr, config.getAccessKeyId(), config.getAccessKeySecret()),
|
||||||
paramStr));
|
paramStr));
|
||||||
} catch (SmsBlendException e) {
|
} catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.message, config.getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == config.getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == config.getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
|
|||||||
@ -1,22 +1,18 @@
|
|||||||
package org.dromara.sms4j.ctyun.utils;
|
package org.dromara.sms4j.ctyun.utils;
|
||||||
|
|
||||||
import cn.hutool.core.codec.Base64;
|
import cn.hutool.core.codec.Base64;
|
||||||
import cn.hutool.crypto.digest.HMac;
|
import cn.hutool.crypto.SecureUtil;
|
||||||
import cn.hutool.crypto.digest.HmacAlgorithm;
|
import cn.hutool.crypto.digest.DigestUtil;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.dromara.sms4j.comm.constant.Constant;
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
import org.dromara.sms4j.comm.utils.SmsDateUtils;
|
||||||
import org.dromara.sms4j.ctyun.config.CtyunConfig;
|
import org.dromara.sms4j.ctyun.config.CtyunConfig;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@ -28,8 +24,7 @@ public class CtyunUtils {
|
|||||||
* 获取签名时间戳
|
* 获取签名时间戳
|
||||||
*/
|
*/
|
||||||
private static String signatureTime(){
|
private static String signatureTime(){
|
||||||
SimpleDateFormat timeFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
|
return SmsDateUtils.pureDateUtcGmt(new Date());
|
||||||
return timeFormat.format(new Date());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,9 +34,7 @@ public class CtyunUtils {
|
|||||||
Map<String, String> map = new ConcurrentHashMap<>(4);
|
Map<String, String> map = new ConcurrentHashMap<>(4);
|
||||||
|
|
||||||
// 构造时间戳
|
// 构造时间戳
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
|
String signatureDate = SmsDateUtils.pureDateGmt(new Date());
|
||||||
Date now = new Date();
|
|
||||||
String signatureDate = dateFormat.format(now);
|
|
||||||
String signatureTime = signatureTime();
|
String signatureTime = signatureTime();
|
||||||
// 构造请求流水号
|
// 构造请求流水号
|
||||||
String uuid = UUID.randomUUID().toString();
|
String uuid = UUID.randomUUID().toString();
|
||||||
@ -59,7 +52,7 @@ public class CtyunUtils {
|
|||||||
// 构造签名
|
// 构造签名
|
||||||
String signature = Base64.encode(hmacSHA256(signatureStr.getBytes(StandardCharsets.UTF_8), kDate));
|
String signature = Base64.encode(hmacSHA256(signatureStr.getBytes(StandardCharsets.UTF_8), kDate));
|
||||||
String signHeader = String.format("%s Headers=ctyun-eop-request-id;eop-date Signature=%s", key, signature);
|
String signHeader = String.format("%s Headers=ctyun-eop-request-id;eop-date Signature=%s", key, signature);
|
||||||
map.put("Content-Type", Constant.APPLICATION_JSON_UTF8);
|
map.put(Constant.CONTENT_TYPE, Constant.APPLICATION_JSON_UTF8);
|
||||||
map.put("ctyun-eop-request-id", uuid);
|
map.put("ctyun-eop-request-id", uuid);
|
||||||
map.put("Eop-date", signatureTime);
|
map.put("Eop-date", signatureTime);
|
||||||
map.put("Eop-Authorization", signHeader);
|
map.put("Eop-Authorization", signHeader);
|
||||||
@ -84,36 +77,11 @@ public class CtyunUtils {
|
|||||||
return JSONUtil.toJsonStr(paramMap);
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String toHex(byte[] data) {
|
|
||||||
StringBuilder sb = new StringBuilder(data.length * 2);
|
|
||||||
for (byte b : data) {
|
|
||||||
String hex = Integer.toHexString(b);
|
|
||||||
if (hex.length() == 1) {
|
|
||||||
sb.append("0");
|
|
||||||
} else if (hex.length() == 8) {
|
|
||||||
hex = hex.substring(6);
|
|
||||||
}
|
|
||||||
sb.append(hex);
|
|
||||||
}
|
|
||||||
return sb.toString().toLowerCase(Locale.getDefault());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getSHA256(String text) {
|
private static String getSHA256(String text) {
|
||||||
try {
|
return DigestUtil.sha256Hex(text);
|
||||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
|
||||||
md.update(text.getBytes(StandardCharsets.UTF_8));
|
|
||||||
return toHex(md.digest());
|
|
||||||
} catch (NoSuchAlgorithmException var3) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] hmacSHA256(byte[] data, byte[] key){
|
private static byte[] hmacSHA256(byte[] data, byte[] key){
|
||||||
try {
|
return SecureUtil.hmacSha256(key).digest(data);
|
||||||
HMac hMac = new HMac(HmacAlgorithm.HmacSHA256, key);
|
|
||||||
return hMac.digest(data);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new SmsBlendException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,44 @@
|
|||||||
|
package org.dromara.sms4j.danmi.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
|
import org.dromara.sms4j.provider.config.BaseConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>类名: DanMiConfig
|
||||||
|
* <p>说明: 旦米短信差异配置
|
||||||
|
*
|
||||||
|
* @author :bleachtred
|
||||||
|
* 2024/6/23 17:06
|
||||||
|
**/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class DanMiConfig extends BaseConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求地址
|
||||||
|
*/
|
||||||
|
private String host = Constant.HTTPS_PREFIX + "openapi.danmi.com/";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求方法
|
||||||
|
* 短信发送 distributor/sendSMS
|
||||||
|
* 短信余额查询 distributor/user/query
|
||||||
|
* 语音验证码发送 voice/voiceCode
|
||||||
|
* 语音通知文件发送 voice/voiceNotify
|
||||||
|
* 语音模板通知发送 voice/voiceTemplate
|
||||||
|
*/
|
||||||
|
private String action = "distributor/sendSMS";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取供应商
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getSupplier() {
|
||||||
|
return SupplierConstant.DAN_MI;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
package org.dromara.sms4j.danmi.config;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
|
import org.dromara.sms4j.danmi.service.DanMiSmsImpl;
|
||||||
|
import org.dromara.sms4j.provider.factory.AbstractProviderFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>类名: DanMiFactory
|
||||||
|
*
|
||||||
|
* @author :bleachtred
|
||||||
|
* 2024/6/23 17:06
|
||||||
|
**/
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class DanMiFactory extends AbstractProviderFactory<DanMiSmsImpl, DanMiConfig> {
|
||||||
|
|
||||||
|
private static final DanMiFactory INSTANCE = new DanMiFactory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取建造者实例
|
||||||
|
* @return 建造者实例
|
||||||
|
*/
|
||||||
|
public static DanMiFactory instance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* createSms
|
||||||
|
* <p> 建造一个短信实现对像
|
||||||
|
*
|
||||||
|
* @author :bleachtred
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DanMiSmsImpl createSms(DanMiConfig config) {
|
||||||
|
return new DanMiSmsImpl(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取供应商
|
||||||
|
* @return 供应商
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getSupplier() {
|
||||||
|
return SupplierConstant.DAN_MI;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,153 @@
|
|||||||
|
package org.dromara.sms4j.danmi.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.api.entity.SmsResponse;
|
||||||
|
import org.dromara.sms4j.api.utils.SmsRespUtils;
|
||||||
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
|
import org.dromara.sms4j.comm.delayedTime.DelayedTime;
|
||||||
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
|
import org.dromara.sms4j.comm.utils.SmsUtils;
|
||||||
|
import org.dromara.sms4j.danmi.config.DanMiConfig;
|
||||||
|
import org.dromara.sms4j.danmi.utils.DanMiUtils;
|
||||||
|
import org.dromara.sms4j.provider.service.AbstractSmsBlend;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>类名: DanMiSmsImpl
|
||||||
|
*
|
||||||
|
* @author :bleachtred
|
||||||
|
* 2024/6/23 17:06
|
||||||
|
**/
|
||||||
|
@Slf4j
|
||||||
|
public class DanMiSmsImpl extends AbstractSmsBlend<DanMiConfig> {
|
||||||
|
|
||||||
|
private int retry = 0;
|
||||||
|
|
||||||
|
public DanMiSmsImpl(DanMiConfig config, Executor pool, DelayedTime delayedTime) {
|
||||||
|
super(config, pool, delayedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DanMiSmsImpl(DanMiConfig config) {
|
||||||
|
super(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSupplier() {
|
||||||
|
return SupplierConstant.DAN_MI;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsResponse sendMessage(String phone, String message) {
|
||||||
|
if (StrUtil.isBlank(phone)){
|
||||||
|
log.error("手机号不能为空");
|
||||||
|
throw new SmsBlendException("手机号不能为空");
|
||||||
|
}
|
||||||
|
List<String> phones = phone.contains(StrUtil.COMMA) ? SmsUtils.splitTrimComma(phone) : Collections.singletonList(phone);
|
||||||
|
return massTexting(phones, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsResponse sendMessage(String phone, LinkedHashMap<String, String> messages) {
|
||||||
|
throw new SmsBlendException("不支持此方法");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
||||||
|
throw new SmsBlendException("不支持此方法");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsResponse massTexting(List<String> phones, String message) {
|
||||||
|
return getSmsResponse(phones, message, getConfig().getTemplateId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
||||||
|
throw new SmsBlendException("不支持此方法");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 短信余额查询
|
||||||
|
* 请设置action为 distributor/user/query
|
||||||
|
*
|
||||||
|
* @return SmsResponse
|
||||||
|
*/
|
||||||
|
public SmsResponse queryBalance() {
|
||||||
|
return getSmsResponse(null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音验证码发送
|
||||||
|
* 请设置action为 voice/voiceCode
|
||||||
|
*
|
||||||
|
* @param called 被叫号码
|
||||||
|
* @param verifyCode 验证码内容(1-8位数字)
|
||||||
|
* @return SmsResponse
|
||||||
|
*/
|
||||||
|
public SmsResponse voiceCode(String called, String verifyCode) {
|
||||||
|
return getSmsResponse(Collections.singletonList(called), verifyCode, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音通知文件发送
|
||||||
|
* 请设置action为 voice/voiceNotify
|
||||||
|
*
|
||||||
|
* @param called 被叫号码
|
||||||
|
* @param notifyFileId 语音文件ID
|
||||||
|
* @return SmsResponse
|
||||||
|
*/
|
||||||
|
public SmsResponse voiceNotify(String called, String notifyFileId) {
|
||||||
|
return getSmsResponse(Collections.singletonList(called), notifyFileId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音模板通知发送
|
||||||
|
* 请设置action为 voice/voiceTemplate
|
||||||
|
*
|
||||||
|
* @param called 被叫号码
|
||||||
|
* @param templateId 文字模板Id(用户中心创建后产生)
|
||||||
|
* @param param 模板变量替换的参数(多个变量按英文逗号分开)
|
||||||
|
* @return SmsResponse
|
||||||
|
*/
|
||||||
|
public SmsResponse voiceTemplate(String called, String templateId, String param) {
|
||||||
|
return getSmsResponse(Collections.singletonList(called), param, templateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SmsResponse getSmsResponse(List<String> phones, String message, String templateId) {
|
||||||
|
DanMiConfig config = getConfig();
|
||||||
|
SmsResponse smsResponse;
|
||||||
|
try {
|
||||||
|
String url = config.getHost() + config.getAction();
|
||||||
|
smsResponse = getResponse(http.postJson(url,
|
||||||
|
DanMiUtils.buildHeaders(),
|
||||||
|
DanMiUtils.buildBody(config, phones, message, templateId)));
|
||||||
|
} catch (SmsBlendException e) {
|
||||||
|
smsResponse = errorResp(e.message);
|
||||||
|
}
|
||||||
|
if (smsResponse.isSuccess() || retry == config.getMaxRetries()) {
|
||||||
|
retry = 0;
|
||||||
|
return smsResponse;
|
||||||
|
}
|
||||||
|
return requestRetry(phones, message, templateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SmsResponse requestRetry(List<String> phones, String message, String templateId) {
|
||||||
|
http.safeSleep(getConfig().getRetryInterval());
|
||||||
|
retry ++;
|
||||||
|
log.warn("短信第 {} 次重新发送", retry);
|
||||||
|
return getSmsResponse(phones, message, templateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SmsResponse getResponse(JSONObject resJson) {
|
||||||
|
return SmsRespUtils.resp(resJson, "00000".equals(resJson.getStr("respCode")), getConfigId());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,127 @@
|
|||||||
|
package org.dromara.sms4j.danmi.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.net.URLEncodeUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.crypto.digest.DigestUtil;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
|
import org.dromara.sms4j.comm.utils.SmsUtils;
|
||||||
|
import org.dromara.sms4j.danmi.config.DanMiConfig;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>类名: DanMiUtils
|
||||||
|
*
|
||||||
|
* @author :bleachtred
|
||||||
|
* 2024/6/23 17:06
|
||||||
|
**/
|
||||||
|
@Slf4j
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class DanMiUtils {
|
||||||
|
|
||||||
|
public static LinkedHashMap<String, String> buildHeaders(){
|
||||||
|
LinkedHashMap<String, String> headers = new LinkedHashMap<>(1);
|
||||||
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_JSON);
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成请求body参数
|
||||||
|
*
|
||||||
|
* @param config 配置数据
|
||||||
|
* @param phones 手机号
|
||||||
|
* @param message 短信内容 (or 验证码内容(1-8位数字) or 语音文件ID or 模板参数)
|
||||||
|
* @param templateId 模板id
|
||||||
|
*/
|
||||||
|
public static LinkedHashMap<String, Object> buildBody(DanMiConfig config, List<String> phones, String message, String templateId) {
|
||||||
|
LinkedHashMap<String, Object> body = new LinkedHashMap<>();
|
||||||
|
body.put("respDataType", "JSON");
|
||||||
|
body.put("accountSid", config.getAccessKeyId());
|
||||||
|
switch (config.getAction()){
|
||||||
|
case "distributor/sendSMS":
|
||||||
|
if (StrUtil.isAllBlank(message, templateId)){
|
||||||
|
log.error("message and templateId can not be empty at the same time");
|
||||||
|
throw new SmsBlendException("message and templateId can not be empty at the same time");
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(templateId)){
|
||||||
|
body.put("templateid", templateId);
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(message)){
|
||||||
|
body.put("smsContent", URLEncodeUtil.encode(message));
|
||||||
|
}
|
||||||
|
if (CollUtil.isEmpty(phones)){
|
||||||
|
log.error("phones can not be empty");
|
||||||
|
throw new SmsBlendException("phones can not be empty");
|
||||||
|
}
|
||||||
|
body.put("to", SmsUtils.addCodePrefixIfNot(phones));
|
||||||
|
break;
|
||||||
|
case "distributor/user/query":
|
||||||
|
break;
|
||||||
|
case "voice/voiceCode":
|
||||||
|
if (CollUtil.isEmpty(phones) || phones.size() != 1){
|
||||||
|
log.error("called can not be empty or phone must be only one");
|
||||||
|
throw new SmsBlendException("called can not be empty or phone must be only one");
|
||||||
|
}
|
||||||
|
body.put("called", SmsUtils.addCodePrefixIfNot(phones.get(0)));
|
||||||
|
if (StrUtil.isBlank(message)){
|
||||||
|
log.error("verifyCode can not be empty");
|
||||||
|
throw new SmsBlendException("verifyCode can not be empty");
|
||||||
|
}
|
||||||
|
body.put("verifyCode", message);
|
||||||
|
break;
|
||||||
|
case "voice/voiceNotify":
|
||||||
|
if (CollUtil.isEmpty(phones) || phones.size() != 1){
|
||||||
|
log.error("called can not be empty or phone must be only one");
|
||||||
|
throw new SmsBlendException("called can not be empty or phone must be only one");
|
||||||
|
}
|
||||||
|
body.put("called", SmsUtils.addCodePrefixIfNot(phones.get(0)));
|
||||||
|
if (StrUtil.isBlank(message)){
|
||||||
|
log.error("notifyFileId can not be empty");
|
||||||
|
throw new SmsBlendException("notifyFileId can not be empty");
|
||||||
|
}
|
||||||
|
body.put("notifyFileId", message);
|
||||||
|
break;
|
||||||
|
case "voice/voiceTemplate":
|
||||||
|
if (CollUtil.isEmpty(phones) || phones.size() != 1){
|
||||||
|
log.error("called can not be empty or phone must be only one");
|
||||||
|
throw new SmsBlendException("called can not be empty or phone must be only one");
|
||||||
|
}
|
||||||
|
body.put("called", SmsUtils.addCodePrefixIfNot(phones.get(0)));
|
||||||
|
if (StrUtil.isEmpty(templateId)){
|
||||||
|
log.error("templateId can not be empty");
|
||||||
|
throw new SmsBlendException("templateId can not be empty");
|
||||||
|
}
|
||||||
|
body.put("templateId", templateId);
|
||||||
|
if (StrUtil.isEmpty(message)){
|
||||||
|
log.error("param can not be empty");
|
||||||
|
throw new SmsBlendException("param can not be empty");
|
||||||
|
}
|
||||||
|
body.put("param", message);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log.error("action not found");
|
||||||
|
throw new SmsBlendException("action not found");
|
||||||
|
}
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
body.put("timestamp", timestamp);
|
||||||
|
body.put("sig", sign(config.getAccessKeyId(), config.getAccessKeySecret(), timestamp));
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 签名:MD5(ACCOUNT SID + AUTH TOKEN + timestamp)。共32位(小写)
|
||||||
|
* @param accessKeyId ACCOUNT SID
|
||||||
|
* @param accessKeySecret AUTH TOKEN
|
||||||
|
* @param timestamp timestamp
|
||||||
|
* @return 签名:MD5 共32位(小写)
|
||||||
|
*/
|
||||||
|
private static String sign(String accessKeyId, String accessKeySecret, long timestamp){
|
||||||
|
return DigestUtil.md5Hex(accessKeyId + accessKeySecret + timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -86,11 +86,11 @@ public class DingZhongSmsImpl extends AbstractSmsBlend<DingZhongConfig> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SmsResponse massTexting(List<String> phones, String message) {
|
public SmsResponse massTexting(List<String> phones, String message) {
|
||||||
return sendMessage(SmsUtils.arrayToString(phones), message);
|
return sendMessage(SmsUtils.addCodePrefixIfNot(phones), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
||||||
return sendMessage(SmsUtils.arrayToString(phones), templateId, messages);
|
return sendMessage(SmsUtils.addCodePrefixIfNot(phones), templateId, messages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34,8 +34,8 @@ public class DingZhongHelper {
|
|||||||
public SmsResponse smsResponse(Map<String, Object> paramMap) {
|
public SmsResponse smsResponse(Map<String, Object> paramMap) {
|
||||||
String url = String.format("%s/%s", config.getRequestUrl(), SmsUtils.isEmpty(paramMap.get("templateId"))?config.getBaseAction():config.getTemplateAction());
|
String url = String.format("%s/%s", config.getRequestUrl(), SmsUtils.isEmpty(paramMap.get("templateId"))?config.getBaseAction():config.getTemplateAction());
|
||||||
Map<String, String> headers = MapUtil.newHashMap(2, true);
|
Map<String, String> headers = MapUtil.newHashMap(2, true);
|
||||||
headers.put("Accept", Constant.ACCEPT);
|
headers.put(Constant.ACCEPT, Constant.APPLICATION_JSON);
|
||||||
headers.put("Content-Type", Constant.FROM_URLENCODED);
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_FROM_URLENCODED);
|
||||||
SmsResponse smsResponse;
|
SmsResponse smsResponse;
|
||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postFrom(url, headers, paramMap));
|
smsResponse = getResponse(http.postFrom(url, headers, paramMap));
|
||||||
|
|||||||
@ -50,12 +50,12 @@ public class EmaySmsImpl extends AbstractSmsBlend<EmayConfig> {
|
|||||||
Map<String, Object> params = EmayBuilder.buildRequestBody(config.getAccessKeyId(), config.getAccessKeySecret(), phone, message);
|
Map<String, Object> params = EmayBuilder.buildRequestBody(config.getAccessKeyId(), config.getAccessKeySecret(), phone, message);
|
||||||
|
|
||||||
Map<String, String> headers = MapUtil.newHashMap(1, true);
|
Map<String, String> headers = MapUtil.newHashMap(1, true);
|
||||||
headers.put("Content-Type", Constant.FROM_URLENCODED);
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_FROM_URLENCODED);
|
||||||
SmsResponse smsResponse;
|
SmsResponse smsResponse;
|
||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postUrl(url, headers, params));
|
smsResponse = getResponse(http.postUrl(url, headers, params));
|
||||||
} catch (SmsBlendException e) {
|
} catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.message, config.getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == config.getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == config.getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
@ -97,7 +97,7 @@ public class EmaySmsImpl extends AbstractSmsBlend<EmayConfig> {
|
|||||||
if (phones.size() > 500) {
|
if (phones.size() > 500) {
|
||||||
throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于500");
|
throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于500");
|
||||||
}
|
}
|
||||||
return sendMessage(SmsUtils.listToString(phones), message);
|
return sendMessage(SmsUtils.joinComma(phones), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -109,7 +109,7 @@ public class EmaySmsImpl extends AbstractSmsBlend<EmayConfig> {
|
|||||||
for (Map.Entry<String, String> entry : messages.entrySet()) {
|
for (Map.Entry<String, String> entry : messages.entrySet()) {
|
||||||
list.add(entry.getValue());
|
list.add(entry.getValue());
|
||||||
}
|
}
|
||||||
return sendMessage(SmsUtils.listToString(phones), EmayBuilder.listToString(list));
|
return sendMessage(SmsUtils.joinComma(phones), EmayBuilder.listToString(list));
|
||||||
}
|
}
|
||||||
|
|
||||||
private SmsResponse getResponse(JSONObject resJson) {
|
private SmsResponse getResponse(JSONObject resJson) {
|
||||||
|
|||||||
@ -71,14 +71,14 @@ public class HuaweiSmsImpl extends AbstractSmsBlend<HuaweiConfig> {
|
|||||||
String requestBody = HuaweiBuilder.buildRequestBody(getConfig().getSender(), phone, templateId, mess, getConfig().getStatusCallBack(), getConfig().getSignature());
|
String requestBody = HuaweiBuilder.buildRequestBody(getConfig().getSender(), phone, templateId, mess, getConfig().getStatusCallBack(), getConfig().getSignature());
|
||||||
|
|
||||||
Map<String, String> headers = MapUtil.newHashMap(3, true);
|
Map<String, String> headers = MapUtil.newHashMap(3, true);
|
||||||
headers.put("Authorization", Constant.HUAWEI_AUTH_HEADER_VALUE);
|
headers.put(Constant.AUTHORIZATION, Constant.HUAWEI_AUTH_HEADER_VALUE);
|
||||||
headers.put("X-WSSE", HuaweiBuilder.buildWsseHeader(getConfig().getAccessKeyId(), getConfig().getAccessKeySecret()));
|
headers.put("X-WSSE", HuaweiBuilder.buildWsseHeader(getConfig().getAccessKeyId(), getConfig().getAccessKeySecret()));
|
||||||
headers.put("Content-Type", Constant.FROM_URLENCODED);
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_FROM_URLENCODED);
|
||||||
SmsResponse smsResponse;
|
SmsResponse smsResponse;
|
||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postJson(url, headers, requestBody));
|
smsResponse = getResponse(http.postJson(url, headers, requestBody));
|
||||||
} catch (SmsBlendException e) {
|
} catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.getMessage(), getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
|
|||||||
@ -2,6 +2,11 @@ package org.dromara.sms4j.huawei.utils;
|
|||||||
|
|
||||||
import cn.hutool.core.codec.Base64;
|
import cn.hutool.core.codec.Base64;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.lang.UUID;
|
||||||
|
import cn.hutool.core.net.URLEncodeUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.crypto.digest.DigestUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.sms4j.comm.constant.Constant;
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
|
|
||||||
@ -9,17 +14,13 @@ import javax.net.ssl.HttpsURLConnection;
|
|||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
public class HuaweiBuilder {
|
public class HuaweiBuilder {
|
||||||
private HuaweiBuilder() {
|
private HuaweiBuilder() {
|
||||||
}
|
}
|
||||||
@ -32,22 +33,13 @@ public class HuaweiBuilder {
|
|||||||
*/
|
*/
|
||||||
public static String buildWsseHeader(String appKey, String appSecret) {
|
public static String buildWsseHeader(String appKey, String appSecret) {
|
||||||
if (null == appKey || null == appSecret || appKey.isEmpty() || appSecret.isEmpty()) {
|
if (null == appKey || null == appSecret || appKey.isEmpty() || appSecret.isEmpty()) {
|
||||||
System.out.println("buildWsseHeader(): appKey or appSecret is null.");
|
log.error("buildWsseHeader(): appKey or appSecret is null.");
|
||||||
return null;
|
throw new SmsBlendException("buildWsseHeader(): appKey or appSecret is null.");
|
||||||
}
|
}
|
||||||
String time = dateFormat(new Date());
|
String time = dateFormat(new Date());
|
||||||
// Nonce
|
// Nonce
|
||||||
String nonce = UUID.randomUUID().toString().replace("-", "");
|
String nonce = UUID.fastUUID().toString(true);
|
||||||
MessageDigest md;
|
byte[] passwordDigest = DigestUtil.sha256(nonce + time + appSecret);
|
||||||
byte[] passwordDigest;
|
|
||||||
|
|
||||||
try {
|
|
||||||
md = MessageDigest.getInstance("SHA-256");
|
|
||||||
md.update((nonce + time + appSecret).getBytes());
|
|
||||||
passwordDigest = md.digest();
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new SmsBlendException(e);
|
|
||||||
}
|
|
||||||
// PasswordDigest
|
// PasswordDigest
|
||||||
String passwordDigestBase64Str = Base64.encode(passwordDigest);
|
String passwordDigestBase64Str = Base64.encode(passwordDigest);
|
||||||
//若passwordDigestBase64Str中包含换行符,请执行如下代码进行修正
|
//若passwordDigestBase64Str中包含换行符,请执行如下代码进行修正
|
||||||
@ -91,12 +83,11 @@ public class HuaweiBuilder {
|
|||||||
*/
|
*/
|
||||||
public static String buildRequestBody(String sender, String receiver, String templateId, String templateParas,
|
public static String buildRequestBody(String sender, String receiver, String templateId, String templateParas,
|
||||||
String statusCallBack, String signature) {
|
String statusCallBack, String signature) {
|
||||||
if (null == sender || null == receiver || null == templateId || sender.isEmpty() || receiver.isEmpty()
|
if (StrUtil.hasBlank(sender, receiver, templateId)) {
|
||||||
|| templateId.isEmpty()) {
|
log.error("buildRequestBody(): sender, receiver or templateId is null.");
|
||||||
System.out.println("buildRequestBody(): sender, receiver or templateId is null.");
|
throw new SmsBlendException("buildRequestBody(): sender, receiver or templateId is null.");
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
Map<String, String> map = new HashMap<>();
|
Map<String, String> map = new HashMap<>(3);
|
||||||
|
|
||||||
map.put("from", sender);
|
map.put("from", sender);
|
||||||
map.put("to", receiver);
|
map.put("to", receiver);
|
||||||
@ -112,17 +103,7 @@ public class HuaweiBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
String temp;
|
map.keySet().forEach(s -> sb.append(s).append("=").append(URLEncodeUtil.encode(map.get(s))).append("&"));
|
||||||
|
|
||||||
for (String s : map.keySet()) {
|
|
||||||
try {
|
|
||||||
temp = URLEncoder.encode(map.get(s), "UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
throw new SmsBlendException(e);
|
|
||||||
}
|
|
||||||
sb.append(s).append("=").append(temp).append("&");
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.deleteCharAt(sb.length() - 1).toString();
|
return sb.deleteCharAt(sb.length() - 1).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -97,7 +97,7 @@ public class JdCloudSmsImpl extends AbstractSmsBlend<JdCloudConfig> {
|
|||||||
try {
|
try {
|
||||||
smsResponse = getSmsResponse(result);
|
smsResponse = getSmsResponse(result);
|
||||||
} catch (SmsBlendException e) {
|
} catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.getMessage(), getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package org.dromara.sms4j.jg.config;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
import org.dromara.sms4j.provider.config.BaseConfig;
|
import org.dromara.sms4j.provider.config.BaseConfig;
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ public class JgConfig extends BaseConfig {
|
|||||||
/**
|
/**
|
||||||
* 调用地址
|
* 调用地址
|
||||||
*/
|
*/
|
||||||
private String requestUrl = "https://api.sms.jpush.cn/v1/";
|
private String requestUrl = Constant.HTTPS_PREFIX + "api.sms.jpush.cn/v1/";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 默认请求方法 messages
|
* 默认请求方法 messages
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import org.dromara.sms4j.comm.delayedTime.DelayedTime;
|
|||||||
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
import org.dromara.sms4j.comm.utils.SmsUtils;
|
import org.dromara.sms4j.comm.utils.SmsUtils;
|
||||||
import org.dromara.sms4j.jg.config.JgConfig;
|
import org.dromara.sms4j.jg.config.JgConfig;
|
||||||
import org.dromara.sms4j.jg.util.JgHelper;
|
import org.dromara.sms4j.jg.util.JgUtils;
|
||||||
import org.dromara.sms4j.provider.service.AbstractSmsBlend;
|
import org.dromara.sms4j.provider.service.AbstractSmsBlend;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@ -82,7 +82,7 @@ public class JgSmsImpl extends AbstractSmsBlend<JgConfig> {
|
|||||||
if (SmsUtils.isEmpty(messages)){
|
if (SmsUtils.isEmpty(messages)){
|
||||||
messages = new LinkedHashMap<>();
|
messages = new LinkedHashMap<>();
|
||||||
}
|
}
|
||||||
return getSmsResponse(SmsUtils.arrayToString(phones), messages, templateId, null, null);
|
return getSmsResponse(SmsUtils.addCodePrefixIfNot(phones), messages, templateId, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -109,14 +109,14 @@ public class JgSmsImpl extends AbstractSmsBlend<JgConfig> {
|
|||||||
String templateId, String code, String msgId) {
|
String templateId, String code, String msgId) {
|
||||||
SmsResponse smsResponse;
|
SmsResponse smsResponse;
|
||||||
JgConfig config = getConfig();
|
JgConfig config = getConfig();
|
||||||
String url = JgHelper.buildUrl(config.getRequestUrl(), config.getAction(), msgId);
|
String url = JgUtils.buildUrl(config.getRequestUrl(), config.getAction(), msgId);
|
||||||
Map<String, String> headers = JgHelper.buildHeaders(config.getAccessKeyId(), config.getAccessKeySecret());
|
Map<String, String> headers = JgUtils.buildHeaders(config.getAccessKeyId(), config.getAccessKeySecret());
|
||||||
Map<String, Object> body= JgHelper.buildBody(phone, messages, templateId, config, code);
|
Map<String, Object> body= JgUtils.buildBody(phone, messages, templateId, config, code);
|
||||||
String jsonKey = JgHelper.buildJsonKey(config.getAction());
|
String jsonKey = JgUtils.buildJsonKey(config.getAction());
|
||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postJson(url, headers, body), jsonKey);
|
smsResponse = getResponse(http.postJson(url, headers, body), jsonKey);
|
||||||
} catch (SmsBlendException e) {
|
} catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.message, config.getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import java.util.stream.Collectors;
|
|||||||
* 2024/3/15
|
* 2024/3/15
|
||||||
**/
|
**/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class JgHelper {
|
public class JgUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造请求地址
|
* 构造请求地址
|
||||||
@ -48,9 +48,9 @@ public class JgHelper {
|
|||||||
check(accessKeyId);
|
check(accessKeyId);
|
||||||
check(accessKeySecret);
|
check(accessKeySecret);
|
||||||
Map<String, String> headers = new LinkedHashMap<>(3);
|
Map<String, String> headers = new LinkedHashMap<>(3);
|
||||||
headers.put("Accept", Constant.ACCEPT);
|
headers.put(Constant.ACCEPT, Constant.APPLICATION_JSON);
|
||||||
headers.put("Content-Type", Constant.APPLICATION_JSON_UTF8);
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_JSON_UTF8);
|
||||||
headers.put("Authorization", "Basic " + Base64.encode(accessKeyId + ":" + accessKeySecret, StandardCharsets.UTF_8));
|
headers.put(Constant.AUTHORIZATION, "Basic " + Base64.encode(accessKeyId + ":" + accessKeySecret, StandardCharsets.UTF_8));
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,6 +208,7 @@ public class JgHelper {
|
|||||||
List<Map<String, Object>> recipients = new ArrayList<>(phones.size());
|
List<Map<String, Object>> recipients = new ArrayList<>(phones.size());
|
||||||
phones.forEach(mobile -> {
|
phones.forEach(mobile -> {
|
||||||
Map<String, Object> params = new LinkedHashMap<>(1);
|
Map<String, Object> params = new LinkedHashMap<>(1);
|
||||||
|
params.put("mobile", StrUtil.addPrefixIfNot(mobile, "+86"));
|
||||||
params.put("temp_para", messages);
|
params.put("temp_para", messages);
|
||||||
recipients.add(params);
|
recipients.add(params);
|
||||||
});
|
});
|
||||||
@ -3,6 +3,7 @@ package org.dromara.sms4j.lianlu.config;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
import org.dromara.sms4j.lianlu.req.LianLuRequest;
|
import org.dromara.sms4j.lianlu.req.LianLuRequest;
|
||||||
import org.dromara.sms4j.lianlu.utils.LianLuUtils;
|
import org.dromara.sms4j.lianlu.utils.LianLuUtils;
|
||||||
@ -10,7 +11,7 @@ import org.dromara.sms4j.provider.config.BaseConfig;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 联麓短信:
|
* 联麓短信:
|
||||||
* <a href="https://console.shlianlu.com/#/document/smsDoc">官方文档</a>
|
* <a href=Constant.HTTPS_PREFIX + "console.shlianlu.com/#/document/smsDoc">官方文档</a>
|
||||||
*
|
*
|
||||||
* @author lym
|
* @author lym
|
||||||
*/
|
*/
|
||||||
@ -35,7 +36,7 @@ public class LianLuConfig extends BaseConfig {
|
|||||||
*/
|
*/
|
||||||
private String signType = LianLuUtils.SIGN_TYPE_MD5;
|
private String signType = LianLuUtils.SIGN_TYPE_MD5;
|
||||||
|
|
||||||
private String requestUrl = "https://apis.shlianlu.com/sms/trade";
|
private String requestUrl = Constant.HTTPS_PREFIX + "apis.shlianlu.com/sms/trade";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSupplier() {
|
public String getSupplier() {
|
||||||
|
|||||||
@ -179,8 +179,8 @@ public class LianLuSmsImpl extends AbstractSmsBlend<LianLuConfig> {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Map<String, String> headers = new HashMap<>(2);
|
Map<String, String> headers = new HashMap<>(2);
|
||||||
headers.put("Content-Type", Constant.APPLICATION_JSON_UTF8);
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_JSON_UTF8);
|
||||||
headers.put("Accept", Constant.ACCEPT);
|
headers.put(Constant.ACCEPT, Constant.APPLICATION_JSON);
|
||||||
SmsResponse smsResponse = this.getResponse(this.http.postJson(reqUrl, headers, requestBody));
|
SmsResponse smsResponse = this.getResponse(this.http.postJson(reqUrl, headers, requestBody));
|
||||||
if (!smsResponse.isSuccess() && this.retry != this.getConfig().getMaxRetries()) {
|
if (!smsResponse.isSuccess() && this.retry != this.getConfig().getMaxRetries()) {
|
||||||
return this.requestRetry(req);
|
return this.requestRetry(req);
|
||||||
|
|||||||
@ -0,0 +1,42 @@
|
|||||||
|
package org.dromara.sms4j.luosimao.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
|
import org.dromara.sms4j.provider.config.BaseConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>类名: LuoSiMaoConfig
|
||||||
|
* <p>说明: 螺丝帽短信差异配置
|
||||||
|
*
|
||||||
|
* @author :bleachtred
|
||||||
|
* 2024/6/21 23:59
|
||||||
|
**/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class LuoSiMaoConfig extends BaseConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求地址
|
||||||
|
*/
|
||||||
|
private String host = Constant.HTTPS_PREFIX + "sms-api.luosimao.com/v1/";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接口名称
|
||||||
|
* 发送短信接口详细 send.json
|
||||||
|
* 批量发送接口详细 send_batch.json
|
||||||
|
* 查询账户余额 status.json
|
||||||
|
*/
|
||||||
|
private String action = "send.json";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取供应商
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getSupplier() {
|
||||||
|
return SupplierConstant.LUO_SI_MAO;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package org.dromara.sms4j.luosimao.config;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
|
import org.dromara.sms4j.luosimao.service.LuoSiMaoSmsImpl;
|
||||||
|
import org.dromara.sms4j.provider.factory.AbstractProviderFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>类名: LuoSiMaoFactory
|
||||||
|
*
|
||||||
|
* @author :bleachtred
|
||||||
|
* 2024/6/21 23:59
|
||||||
|
**/
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class LuoSiMaoFactory extends AbstractProviderFactory<LuoSiMaoSmsImpl, LuoSiMaoConfig> {
|
||||||
|
|
||||||
|
private static final LuoSiMaoFactory INSTANCE = new LuoSiMaoFactory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取建造者实例
|
||||||
|
* @return 建造者实例
|
||||||
|
*/
|
||||||
|
public static LuoSiMaoFactory instance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p> 建造一个短信实现对像
|
||||||
|
*
|
||||||
|
* @author :bleachtred
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public LuoSiMaoSmsImpl createSms(LuoSiMaoConfig config) {
|
||||||
|
return new LuoSiMaoSmsImpl(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取供应商
|
||||||
|
* @return 供应商
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getSupplier() {
|
||||||
|
return SupplierConstant.LUO_SI_MAO;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,141 @@
|
|||||||
|
package org.dromara.sms4j.luosimao.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.api.entity.SmsResponse;
|
||||||
|
import org.dromara.sms4j.api.utils.SmsRespUtils;
|
||||||
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
|
import org.dromara.sms4j.comm.delayedTime.DelayedTime;
|
||||||
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
|
import org.dromara.sms4j.luosimao.config.LuoSiMaoConfig;
|
||||||
|
import org.dromara.sms4j.luosimao.utils.LuoSiMaoUtils;
|
||||||
|
import org.dromara.sms4j.provider.service.AbstractSmsBlend;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>类名: LuoSiMaoSmsImpl
|
||||||
|
* <p>说明: 螺丝帽短信差异配置
|
||||||
|
*
|
||||||
|
* @author :bleachtred
|
||||||
|
* 2024/6/21 23:59
|
||||||
|
**/
|
||||||
|
@Slf4j
|
||||||
|
public class LuoSiMaoSmsImpl extends AbstractSmsBlend<LuoSiMaoConfig> {
|
||||||
|
|
||||||
|
private int retry = 0;
|
||||||
|
|
||||||
|
public LuoSiMaoSmsImpl(LuoSiMaoConfig config, Executor pool, DelayedTime delayedTime) {
|
||||||
|
super(config, pool, delayedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LuoSiMaoSmsImpl(LuoSiMaoConfig config) {
|
||||||
|
super(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSupplier() {
|
||||||
|
return SupplierConstant.LUO_SI_MAO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsResponse sendMessage(String phone, String message) {
|
||||||
|
return getSmsResponse(Collections.singletonList(phone), message, null, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsResponse sendMessage(String phone, LinkedHashMap<String, String> messages) {
|
||||||
|
throw new SmsBlendException("不支持此方法");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
||||||
|
throw new SmsBlendException("不支持此方法");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsResponse massTexting(List<String> phones, String message) {
|
||||||
|
return getSmsResponse(phones, message, null, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
||||||
|
throw new SmsBlendException("不支持此方法");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时批量发送
|
||||||
|
* @param phones 手机号
|
||||||
|
* @param message 信息
|
||||||
|
* @param date 时间
|
||||||
|
* @return SmsResponse
|
||||||
|
*/
|
||||||
|
public SmsResponse massTextingOnTime(List<String> phones, String message, Date date) {
|
||||||
|
return getSmsResponse(phones, message, date, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询账户余额 请将接口设置为 status.json
|
||||||
|
*
|
||||||
|
* @return SmsResponse
|
||||||
|
*/
|
||||||
|
public SmsResponse queryAccountBalance() {
|
||||||
|
return getSmsResponse(null, null, null, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SmsResponse getSmsResponse(List<String> phones, String message, Date date, boolean batch, boolean status) {
|
||||||
|
LuoSiMaoConfig config = getConfig();
|
||||||
|
SmsResponse smsResponse;
|
||||||
|
try {
|
||||||
|
String url = config.getHost() + config.getAction();
|
||||||
|
LinkedHashMap<String, Object> body;
|
||||||
|
if (status){
|
||||||
|
if ("status.json".equals(config.getAction())){
|
||||||
|
log.error("please set the request interface method to status.json");
|
||||||
|
throw new SmsBlendException("please set the request interface method to status.json");
|
||||||
|
}
|
||||||
|
smsResponse = getResponse(http.getBasic(url, "api", "key-" + config.getAccessKeyId()));
|
||||||
|
} else {
|
||||||
|
if (CollUtil.isEmpty(phones)){
|
||||||
|
log.error("mobile number is required");
|
||||||
|
throw new SmsBlendException("mobile number is required");
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(message)){
|
||||||
|
log.error("message number is required");
|
||||||
|
throw new SmsBlendException("message number is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (batch){
|
||||||
|
body = LuoSiMaoUtils.buildBody(phones, message, date);
|
||||||
|
}else {
|
||||||
|
body = LuoSiMaoUtils.buildBody(phones.get(0), message);
|
||||||
|
}
|
||||||
|
smsResponse = getResponse(http.postBasicFrom(url, LuoSiMaoUtils.buildHeaders(), "api", "key-" + config.getAccessKeyId(), body));
|
||||||
|
}
|
||||||
|
log.debug("短信发送结果:{}", smsResponse);
|
||||||
|
} catch (SmsBlendException e) {
|
||||||
|
log.error(e.message, e);
|
||||||
|
smsResponse = errorResp(e.message);
|
||||||
|
}
|
||||||
|
if (smsResponse.isSuccess() || retry == config.getMaxRetries()) {
|
||||||
|
retry = 0;
|
||||||
|
return smsResponse;
|
||||||
|
}
|
||||||
|
return requestRetry(phones, message, date, batch, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SmsResponse requestRetry(List<String> phones, String message, Date date, boolean batch, boolean status) {
|
||||||
|
http.safeSleep(getConfig().getRetryInterval());
|
||||||
|
retry ++;
|
||||||
|
log.warn("短信第 {} 次重新发送", retry);
|
||||||
|
return getSmsResponse(phones, message, date, batch, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SmsResponse getResponse(JSONObject resJson) {
|
||||||
|
return SmsRespUtils.resp(resJson, Objects.equals(0, resJson.getInt("error")), getConfigId());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
package org.dromara.sms4j.luosimao.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
|
import org.dromara.sms4j.comm.utils.SmsDateUtils;
|
||||||
|
import org.dromara.sms4j.comm.utils.SmsUtils;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class LuoSiMaoUtils {
|
||||||
|
|
||||||
|
public static LinkedHashMap<String, String> buildHeaders(){
|
||||||
|
LinkedHashMap<String, String> headers = new LinkedHashMap<>(1);
|
||||||
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_FROM_URLENCODED);
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LinkedHashMap<String, Object> buildBody(String phone, String message){
|
||||||
|
LinkedHashMap<String, Object> body = new LinkedHashMap<>(2);
|
||||||
|
body.put("mobile", StrUtil.addPrefixIfNot(phone, "+86"));
|
||||||
|
body.put("message", message);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LinkedHashMap<String, Object> buildBody(List<String> phones, String message, Date date){
|
||||||
|
LinkedHashMap<String, Object> body = new LinkedHashMap<>(2);
|
||||||
|
body.put("mobile", SmsUtils.addCodePrefixIfNot(phones));
|
||||||
|
body.put("message", message);
|
||||||
|
if (date != null){
|
||||||
|
body.put("time", SmsDateUtils.normDatetimeGmt8(date));
|
||||||
|
}
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,7 +9,7 @@ import org.dromara.sms4j.provider.config.BaseConfig;
|
|||||||
* <p>类名: MasConfig
|
* <p>类名: MasConfig
|
||||||
* <p>说明:中国移动 云MAS
|
* <p>说明:中国移动 云MAS
|
||||||
*
|
*
|
||||||
* @author :bleachhtred
|
* @author :bleachtred
|
||||||
* 2024/4/22 13:40
|
* 2024/4/22 13:40
|
||||||
**/
|
**/
|
||||||
@Data
|
@Data
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import org.dromara.sms4j.provider.factory.AbstractProviderFactory;
|
|||||||
* <p>类名: MasFactory
|
* <p>类名: MasFactory
|
||||||
* <p>说明:中国移动 云MAS短信配置器
|
* <p>说明:中国移动 云MAS短信配置器
|
||||||
*
|
*
|
||||||
* @author :bleachhtred
|
* @author :bleachtred
|
||||||
* 2024/4/22 13:40
|
* 2024/4/22 13:40
|
||||||
**/
|
**/
|
||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
@ -30,7 +30,7 @@ public class MasFactory extends AbstractProviderFactory<MasSmsImpl, MasConfig> {
|
|||||||
* createSms
|
* createSms
|
||||||
* <p> 建造一个短信实现对像
|
* <p> 建造一个短信实现对像
|
||||||
*
|
*
|
||||||
* @author :bleachhtred
|
* @author :bleachtred
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MasSmsImpl createSms(MasConfig masConfig) {
|
public MasSmsImpl createSms(MasConfig masConfig) {
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import java.util.concurrent.Executor;
|
|||||||
* <p>类名: MasSmsImpl
|
* <p>类名: MasSmsImpl
|
||||||
* <p>说明:中国移动 云MAS短信实现
|
* <p>说明:中国移动 云MAS短信实现
|
||||||
*
|
*
|
||||||
* @author :bleachhtred
|
* @author :bleachtred
|
||||||
* 2024/4/22 13:40
|
* 2024/4/22 13:40
|
||||||
**/
|
**/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -67,7 +67,7 @@ public class MasSmsImpl extends AbstractSmsBlend<MasConfig> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SmsResponse massTexting(List<String> phones, String message) {
|
public SmsResponse massTexting(List<String> phones, String message) {
|
||||||
return getSmsResponse(SmsUtils.arrayToString(phones), message, getConfig().getTemplateId());
|
return getSmsResponse(SmsUtils.addCodePrefixIfNot(phones), message, getConfig().getTemplateId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -76,7 +76,7 @@ public class MasSmsImpl extends AbstractSmsBlend<MasConfig> {
|
|||||||
messages = new LinkedHashMap<>();
|
messages = new LinkedHashMap<>();
|
||||||
}
|
}
|
||||||
String messageStr = JSONUtil.toJsonStr(messages);
|
String messageStr = JSONUtil.toJsonStr(messages);
|
||||||
return getSmsResponse(SmsUtils.arrayToString(phones), messageStr, templateId);
|
return getSmsResponse(SmsUtils.addCodePrefixIfNot(phones), messageStr, templateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SmsResponse getSmsResponse(String phone, String message, String templateId) {
|
private SmsResponse getSmsResponse(String phone, String message, String templateId) {
|
||||||
@ -95,7 +95,7 @@ public class MasSmsImpl extends AbstractSmsBlend<MasConfig> {
|
|||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postJson(requestUrl, null, base64Code));
|
smsResponse = getResponse(http.postJson(requestUrl, null, base64Code));
|
||||||
} catch (SmsBlendException e) {
|
} catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.getMessage(), getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package org.dromara.sms4j.netease.config;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
import org.dromara.sms4j.provider.config.BaseConfig;
|
import org.dromara.sms4j.provider.config.BaseConfig;
|
||||||
|
|
||||||
@ -21,18 +22,17 @@ public class NeteaseConfig extends BaseConfig {
|
|||||||
/**
|
/**
|
||||||
* 模板短信请求地址
|
* 模板短信请求地址
|
||||||
*/
|
*/
|
||||||
private String templateUrl = "https://api.netease.im/sms/sendtemplate.action";
|
private String templateUrl = Constant.HTTPS_PREFIX + "api.netease.im/sms/sendtemplate.action";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证码短信请求地址
|
* 验证码短信请求地址
|
||||||
*/
|
*/
|
||||||
private String codeUrl = "https://api.netease.im/sms/sendcode.action";
|
private String codeUrl = Constant.HTTPS_PREFIX + "api.netease.im/sms/sendcode.action";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证码验证请求地址
|
* 验证码验证请求地址
|
||||||
*/
|
*/
|
||||||
private String verifyUrl = "https://api.netease.im/sms/verifycode.action";
|
private String verifyUrl = Constant.HTTPS_PREFIX + "api.netease.im/sms/verifycode.action";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否需要支持短信上行。true:需要,false:不需要
|
* 是否需要支持短信上行。true:需要,false:不需要
|
||||||
|
|||||||
@ -134,7 +134,7 @@ public class NeteaseSmsImpl extends AbstractSmsBlend<NeteaseConfig> {
|
|||||||
body.put("needUp", getConfig().getNeedUp());
|
body.put("needUp", getConfig().getNeedUp());
|
||||||
|
|
||||||
Map<String, String> headers = MapUtil.newHashMap(5, true);
|
Map<String, String> headers = MapUtil.newHashMap(5, true);
|
||||||
headers.put("Content-Type", Constant.FROM_URLENCODED);
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_FROM_URLENCODED);
|
||||||
headers.put("AppKey", getConfig().getAccessKeyId());
|
headers.put("AppKey", getConfig().getAccessKeyId());
|
||||||
headers.put("Nonce", nonce);
|
headers.put("Nonce", nonce);
|
||||||
headers.put("CurTime", curTime);
|
headers.put("CurTime", curTime);
|
||||||
@ -143,7 +143,7 @@ public class NeteaseSmsImpl extends AbstractSmsBlend<NeteaseConfig> {
|
|||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postFrom(requestUrl, headers, body));
|
smsResponse = getResponse(http.postFrom(requestUrl, headers, body));
|
||||||
} catch (SmsBlendException e) {
|
} catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.getMessage(), getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
|
|||||||
@ -22,6 +22,7 @@ public abstract class BaseConfig implements SupplierConfig {
|
|||||||
* Access Key
|
* Access Key
|
||||||
*/
|
*/
|
||||||
private String accessKeyId;
|
private String accessKeyId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sdk App Id
|
* Sdk App Id
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -2,7 +2,7 @@ package org.dromara.sms4j.provider.config;
|
|||||||
|
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.dromara.sms4j.comm.enumerate.ConfigType;
|
import org.dromara.sms4j.comm.enums.ConfigType;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import org.dromara.sms4j.api.SmsBlend;
|
|||||||
import org.dromara.sms4j.api.callback.CallBack;
|
import org.dromara.sms4j.api.callback.CallBack;
|
||||||
import org.dromara.sms4j.api.entity.SmsResponse;
|
import org.dromara.sms4j.api.entity.SmsResponse;
|
||||||
import org.dromara.sms4j.api.universal.SupplierConfig;
|
import org.dromara.sms4j.api.universal.SupplierConfig;
|
||||||
|
import org.dromara.sms4j.api.utils.SmsRespUtils;
|
||||||
import org.dromara.sms4j.comm.delayedTime.DelayedTime;
|
import org.dromara.sms4j.comm.delayedTime.DelayedTime;
|
||||||
import org.dromara.sms4j.comm.utils.SmsHttpUtils;
|
import org.dromara.sms4j.comm.utils.SmsHttpUtils;
|
||||||
import org.dromara.sms4j.provider.factory.BeanFactory;
|
import org.dromara.sms4j.provider.factory.BeanFactory;
|
||||||
@ -62,7 +63,6 @@ public abstract class AbstractSmsBlend<C extends SupplierConfig> implements SmsB
|
|||||||
* message 消息内容
|
* message 消息内容
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract SmsResponse sendMessage(String phone, String message);
|
public abstract SmsResponse sendMessage(String phone, String message);
|
||||||
|
|
||||||
@ -84,7 +84,6 @@ public abstract class AbstractSmsBlend<C extends SupplierConfig> implements SmsB
|
|||||||
* @param messages key为模板变量名称 value为模板变量值
|
* @param messages key为模板变量名称 value为模板变量值
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages);
|
public abstract SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages);
|
||||||
|
|
||||||
@ -94,7 +93,6 @@ public abstract class AbstractSmsBlend<C extends SupplierConfig> implements SmsB
|
|||||||
*
|
*
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract SmsResponse massTexting(List<String> phones, String message);
|
public abstract SmsResponse massTexting(List<String> phones, String message);
|
||||||
|
|
||||||
@ -104,7 +102,6 @@ public abstract class AbstractSmsBlend<C extends SupplierConfig> implements SmsB
|
|||||||
*
|
*
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages);
|
public abstract SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages);
|
||||||
|
|
||||||
@ -145,7 +142,6 @@ public abstract class AbstractSmsBlend<C extends SupplierConfig> implements SmsB
|
|||||||
* @param callBack 回调
|
* @param callBack 回调
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack){
|
public final void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack){
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone,templateId, messages), pool);
|
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone,templateId, messages), pool);
|
||||||
@ -240,4 +236,13 @@ public abstract class AbstractSmsBlend<C extends SupplierConfig> implements SmsB
|
|||||||
}
|
}
|
||||||
}, delayedTime);
|
}, delayedTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回异常
|
||||||
|
* @param errorMsg 异常信息
|
||||||
|
* @return SmsResponse
|
||||||
|
*/
|
||||||
|
public SmsResponse errorResp(String errorMsg){
|
||||||
|
return SmsRespUtils.error(errorMsg, config.getConfigId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package org.dromara.sms4j.qiniu.config;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
import org.dromara.sms4j.provider.config.BaseConfig;
|
import org.dromara.sms4j.provider.config.BaseConfig;
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ public class QiNiuConfig extends BaseConfig {
|
|||||||
/**
|
/**
|
||||||
* 请求地址
|
* 请求地址
|
||||||
*/
|
*/
|
||||||
private String baseUrl = "https://sms.qiniuapi.com";
|
private String baseUrl = Constant.HTTPS_PREFIX + "sms.qiniuapi.com";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模板变量名称
|
* 模板变量名称
|
||||||
|
|||||||
@ -86,7 +86,7 @@ public class QiNiuSmsImpl extends AbstractSmsBlend<QiNiuConfig> {
|
|||||||
jsonObject = http.postJson(url, QiNiuUtils.getHeaderAndSign(url, params, getConfig()), params);
|
jsonObject = http.postJson(url, QiNiuUtils.getHeaderAndSign(url, params, getConfig()), params);
|
||||||
smsResponse = SmsRespUtils.resp(jsonObject, SmsUtils.isEmpty(jsonObject.getStr("error")), getConfigId());
|
smsResponse = SmsRespUtils.resp(jsonObject, SmsUtils.isEmpty(jsonObject.getStr("error")), getConfigId());
|
||||||
}catch (SmsBlendException e){
|
}catch (SmsBlendException e){
|
||||||
smsResponse = SmsRespUtils.error(e.getMessage(), getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
|
|||||||
@ -8,16 +8,15 @@ import lombok.Data;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.sms4j.comm.constant.Constant;
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
|
import org.dromara.sms4j.comm.utils.SmsDateUtils;
|
||||||
import org.dromara.sms4j.qiniu.config.QiNiuConfig;
|
import org.dromara.sms4j.qiniu.config.QiNiuConfig;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TimeZone;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author YYM
|
* @author YYM
|
||||||
@ -35,7 +34,7 @@ public class QiNiuUtils {
|
|||||||
StringBuilder dataToSign = new StringBuilder();
|
StringBuilder dataToSign = new StringBuilder();
|
||||||
dataToSign.append(method.toUpperCase()).append(" ").append(reqUrl.getPath());
|
dataToSign.append(method.toUpperCase()).append(" ").append(reqUrl.getPath());
|
||||||
dataToSign.append("\nHost: ").append(reqUrl.getHost());
|
dataToSign.append("\nHost: ").append(reqUrl.getHost());
|
||||||
dataToSign.append("\n").append("Content-Type").append(": ").append(Constant.ACCEPT);
|
dataToSign.append("\n").append(Constant.CONTENT_TYPE).append(": ").append(Constant.APPLICATION_JSON);
|
||||||
dataToSign.append("\n").append("X-Qiniu-Date").append(": ").append(signDate);
|
dataToSign.append("\n").append("X-Qiniu-Date").append(": ").append(signDate);
|
||||||
dataToSign.append("\n\n");
|
dataToSign.append("\n\n");
|
||||||
if (ObjectUtil.isNotEmpty(body)) {
|
if (ObjectUtil.isNotEmpty(body)) {
|
||||||
@ -50,9 +49,7 @@ public class QiNiuUtils {
|
|||||||
|
|
||||||
public static Map<String, String> getHeaderAndSign(String url, HashMap<String, Object> hashMap, QiNiuConfig qiNiuConfig) {
|
public static Map<String, String> getHeaderAndSign(String url, HashMap<String, Object> hashMap, QiNiuConfig qiNiuConfig) {
|
||||||
String signature;
|
String signature;
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
|
String signDate = SmsDateUtils.pureDateUtcGmt(new Date());
|
||||||
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
|
||||||
String signDate = dateFormat.format(new Date());
|
|
||||||
try {
|
try {
|
||||||
signature = getSignature("POST", url, qiNiuConfig, JSONUtil.toJsonStr(hashMap), signDate);
|
signature = getSignature("POST", url, qiNiuConfig, JSONUtil.toJsonStr(hashMap), signDate);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -62,9 +59,9 @@ public class QiNiuUtils {
|
|||||||
|
|
||||||
//请求头
|
//请求头
|
||||||
Map<String, String> header = new HashMap<>(3);
|
Map<String, String> header = new HashMap<>(3);
|
||||||
header.put("Authorization", signature);
|
header.put(Constant.AUTHORIZATION, signature);
|
||||||
header.put("X-Qiniu-Date", signDate);
|
header.put("X-Qiniu-Date", signDate);
|
||||||
header.put("Content-Type", "application/json");
|
header.put(Constant.CONTENT_TYPE, "application/json");
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,56 @@
|
|||||||
|
package org.dromara.sms4j.submail.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
|
import org.dromara.sms4j.provider.config.BaseConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>类名: SubMailConfig
|
||||||
|
* <p>说明: SUBMAIL短信差异配置
|
||||||
|
*
|
||||||
|
* @author :bleachtred
|
||||||
|
* 2024/6/22 13:59
|
||||||
|
**/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class SubMailConfig extends BaseConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求地址
|
||||||
|
*/
|
||||||
|
private String host = Constant.HTTPS_PREFIX + "api-v4.mysubmail.com/sms/";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接口名称
|
||||||
|
* 短信发送 send.json
|
||||||
|
* 短信模板发送 xsend.json
|
||||||
|
* 短信一对多发送 multisend.json
|
||||||
|
* 短信模板一对多发送 multixsend.json
|
||||||
|
* 短信批量群发 batchsend.json
|
||||||
|
* 短信批量模板群发 batchxsend.json
|
||||||
|
*/
|
||||||
|
private String action = "send.json";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MD5 或 SHA-1 默认MD5 填写任意值,不为即为 密匙明文验证模式
|
||||||
|
*/
|
||||||
|
private String signType = "MD5";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* signature加密计算方式
|
||||||
|
* (当sign_version传2时,会忽略某些字段)
|
||||||
|
*/
|
||||||
|
private String signVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取供应商
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getSupplier() {
|
||||||
|
return SupplierConstant.MY_SUBMAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package org.dromara.sms4j.submail.config;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
|
import org.dromara.sms4j.provider.factory.AbstractProviderFactory;
|
||||||
|
import org.dromara.sms4j.submail.service.SubMailSmsImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>类名: SubMailFactory
|
||||||
|
*
|
||||||
|
* @author :bleachtred
|
||||||
|
* 2024/6/22 13:59
|
||||||
|
**/
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class SubMailFactory extends AbstractProviderFactory<SubMailSmsImpl, SubMailConfig> {
|
||||||
|
|
||||||
|
private static final SubMailFactory INSTANCE = new SubMailFactory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取建造者实例
|
||||||
|
* @return 建造者实例
|
||||||
|
*/
|
||||||
|
public static SubMailFactory instance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p> 建造一个短信实现对像
|
||||||
|
*
|
||||||
|
* @author :bleachtred
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public SubMailSmsImpl createSms(SubMailConfig config) {
|
||||||
|
return new SubMailSmsImpl(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取供应商
|
||||||
|
* @return 供应商
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getSupplier() {
|
||||||
|
return SupplierConstant.MY_SUBMAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,365 @@
|
|||||||
|
package org.dromara.sms4j.submail.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.api.entity.SmsResponse;
|
||||||
|
import org.dromara.sms4j.api.utils.SmsRespUtils;
|
||||||
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
|
import org.dromara.sms4j.comm.delayedTime.DelayedTime;
|
||||||
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
|
import org.dromara.sms4j.comm.utils.SmsUtils;
|
||||||
|
import org.dromara.sms4j.provider.service.AbstractSmsBlend;
|
||||||
|
import org.dromara.sms4j.submail.config.SubMailConfig;
|
||||||
|
import org.dromara.sms4j.submail.utils.SubMailUtils;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>类名: SubMailSmsImpl
|
||||||
|
*
|
||||||
|
* @author :bleachtred
|
||||||
|
* 2023/5/12 15:06
|
||||||
|
**/
|
||||||
|
@Slf4j
|
||||||
|
public class SubMailSmsImpl extends AbstractSmsBlend<SubMailConfig> {
|
||||||
|
|
||||||
|
private int retry = 0;
|
||||||
|
|
||||||
|
public SubMailSmsImpl(SubMailConfig config, Executor pool, DelayedTime delayedTime) {
|
||||||
|
super(config, pool, delayedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubMailSmsImpl(SubMailConfig config) {
|
||||||
|
super(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSupplier() {
|
||||||
|
return SupplierConstant.MY_SUBMAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsResponse sendMessage(String phone, String content) {
|
||||||
|
return getSmsResponse(Collections.singletonList(phone), content, getConfig().getTemplateId(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsResponse sendMessage(String phone, LinkedHashMap<String, String> vars) {
|
||||||
|
if (MapUtil.isEmpty(vars)){
|
||||||
|
log.error("vars or content must be not null");
|
||||||
|
throw new SmsBlendException("vars or content must be not null");
|
||||||
|
}
|
||||||
|
String content = vars.get("content");
|
||||||
|
vars.remove("content");
|
||||||
|
return getSmsResponse(Collections.singletonList(phone), content, getConfig().getTemplateId(), vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> vars) {
|
||||||
|
if (MapUtil.isEmpty(vars)){
|
||||||
|
log.error("vars or content must be not null");
|
||||||
|
throw new SmsBlendException("vars or content must be not null");
|
||||||
|
}
|
||||||
|
String content = vars.get("content");
|
||||||
|
vars.remove("content");
|
||||||
|
return getSmsResponse(Collections.singletonList(phone), content, templateId, vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public SmsResponse massTexting(List<String> phones, String content) {
|
||||||
|
if (StrUtil.isBlank(content)){
|
||||||
|
log.error("vars or content must be not null");
|
||||||
|
throw new SmsBlendException("vars or content must be not null");
|
||||||
|
}
|
||||||
|
return massTexting(phones, getConfig().getTemplateId(), BeanUtil.copyProperties(content, LinkedHashMap.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> vars) {
|
||||||
|
if (MapUtil.isEmpty(vars)){
|
||||||
|
log.error("vars or content must be not null");
|
||||||
|
throw new SmsBlendException("vars or content must be not null");
|
||||||
|
}
|
||||||
|
String content = vars.get("content");
|
||||||
|
vars.remove("content");
|
||||||
|
return getSmsResponse(phones, content, templateId, vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SmsResponse getSmsResponse(List<String> phones, String content, String templateId, LinkedHashMap<String, String> vars) {
|
||||||
|
if (CollUtil.isEmpty(phones)){
|
||||||
|
log.error("phones must be not null");
|
||||||
|
throw new SmsBlendException("phones must be not null");
|
||||||
|
}
|
||||||
|
SubMailConfig config = getConfig();
|
||||||
|
SmsResponse smsResponse;
|
||||||
|
String url = config.getHost() + config.getAction();
|
||||||
|
LinkedHashMap<String, Object> body;
|
||||||
|
switch (config.getAction()){
|
||||||
|
case "send.json":
|
||||||
|
if (StrUtil.isBlank(content)){
|
||||||
|
log.error("content must be not null");
|
||||||
|
throw new SmsBlendException("content must be not null");
|
||||||
|
}
|
||||||
|
body = buildSend(phones.get(0), content);
|
||||||
|
break;
|
||||||
|
case "xsend.json":
|
||||||
|
body = buildXSend(phones.get(0), templateId, vars);
|
||||||
|
break;
|
||||||
|
case "multisend.json":
|
||||||
|
if (StrUtil.isBlank(content)){
|
||||||
|
log.error("content must be not null");
|
||||||
|
throw new SmsBlendException("content must be not null");
|
||||||
|
}
|
||||||
|
if (MapUtil.isEmpty(vars)){
|
||||||
|
log.error("vars be not null");
|
||||||
|
throw new SmsBlendException("vars must be not null");
|
||||||
|
}
|
||||||
|
body = buildMultiSend(phones, content, vars);
|
||||||
|
break;
|
||||||
|
case "multixsend.json":
|
||||||
|
if (MapUtil.isEmpty(vars)){
|
||||||
|
log.error("vars be not null");
|
||||||
|
throw new SmsBlendException("vars must be not null");
|
||||||
|
}
|
||||||
|
body = buildMultiXSend(phones, templateId, vars);
|
||||||
|
break;
|
||||||
|
case "batchsend.json":
|
||||||
|
if (StrUtil.isBlank(content)){
|
||||||
|
log.error("vars or content must be not null");
|
||||||
|
throw new SmsBlendException("vars or content must be not null");
|
||||||
|
}
|
||||||
|
body = buildBatchSend(phones, content);
|
||||||
|
break;
|
||||||
|
case "batchxsend.json":
|
||||||
|
if (MapUtil.isEmpty(vars)){
|
||||||
|
log.error("vars be not null");
|
||||||
|
throw new SmsBlendException("vars must be not null");
|
||||||
|
}
|
||||||
|
body = buildBatchXSend(phones, templateId, vars);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log.error("不支持的短信发送类型");
|
||||||
|
throw new SmsBlendException("不支持的短信发送类型");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
smsResponse = getResponse(http.postJson(url, SubMailUtils.buildHeaders(), body));
|
||||||
|
log.debug("短信发送结果: {}", JSONUtil.toJsonStr(smsResponse));
|
||||||
|
} catch (SmsBlendException e) {
|
||||||
|
log.error(e.message, e);
|
||||||
|
smsResponse = errorResp(e.message);
|
||||||
|
}
|
||||||
|
if (smsResponse.isSuccess() || retry == config.getMaxRetries()) {
|
||||||
|
retry = 0;
|
||||||
|
return smsResponse;
|
||||||
|
}
|
||||||
|
return requestRetry(phones, content, templateId, vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SmsResponse requestRetry(List<String> phones, String content, String templateId, LinkedHashMap<String, String> vars) {
|
||||||
|
http.safeSleep(getConfig().getRetryInterval());
|
||||||
|
retry ++;
|
||||||
|
log.warn("短信第 {} 次重新发送", retry);
|
||||||
|
return getSmsResponse(phones, content, templateId, vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SmsResponse getResponse(JSONObject resJson) {
|
||||||
|
return SmsRespUtils.resp(resJson, "success".equals(resJson.getStr("status")), getConfigId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SMS/Send - 短信发送
|
||||||
|
* @param phone 单个手机号
|
||||||
|
* @param content 短信内容
|
||||||
|
* @return 参数组装
|
||||||
|
*/
|
||||||
|
private LinkedHashMap<String, Object> buildSend(String phone, String content){
|
||||||
|
SubMailConfig config = getConfig();
|
||||||
|
LinkedHashMap<String, Object> body = new LinkedHashMap<>();
|
||||||
|
body.put("appid", config.getAccessKeyId());
|
||||||
|
body.put("to", StrUtil.addPrefixIfNot(phone, "+86"));
|
||||||
|
if (StrUtil.isNotBlank(config.getSignature())){
|
||||||
|
content = StrUtil.addPrefixIfNot(content, "【 " + config.getSignature() + "】") + StrUtil.sub(content, 0, 1000);
|
||||||
|
}else {
|
||||||
|
content = StrUtil.sub(content, 0, 1000);
|
||||||
|
}
|
||||||
|
body.put("content", content);
|
||||||
|
body.put("timestamp", timestamp());
|
||||||
|
body.put("sign_type", config.getSignType());
|
||||||
|
if (StrUtil.isNotBlank(config.getSignVersion())){
|
||||||
|
body.put("sign_version", config.getSignVersion());
|
||||||
|
}
|
||||||
|
body.put("sign_type", config.getSignType());
|
||||||
|
String signature = SubMailUtils.signature(body, config.getSignType(), config.getAccessKeyId(), config.getAccessKeySecret(), "content");
|
||||||
|
body.put("signature", signature);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SMS/XSend - 短信模板发送
|
||||||
|
* @param phone 单个手机号
|
||||||
|
* @param templateId 短信模板ID
|
||||||
|
* @param vars 使用文本变量动态控制短信中的文本
|
||||||
|
* @return 参数组装
|
||||||
|
*/
|
||||||
|
private LinkedHashMap<String, Object> buildXSend(String phone, String templateId, LinkedHashMap<String, String> vars){
|
||||||
|
SubMailConfig config = getConfig();
|
||||||
|
LinkedHashMap<String, Object> body = new LinkedHashMap<>();
|
||||||
|
body.put("appid", config.getAccessKeyId());
|
||||||
|
body.put("to", StrUtil.addPrefixIfNot(phone, "+86"));
|
||||||
|
body.put("project", templateId);
|
||||||
|
if (MapUtil.isNotEmpty(vars)){
|
||||||
|
body.put("vars", JSONUtil.toJsonStr(vars));
|
||||||
|
}
|
||||||
|
body.put("timestamp", timestamp());
|
||||||
|
body.put("sign_type", config.getSignType());
|
||||||
|
if (StrUtil.isNotBlank(config.getSignVersion())){
|
||||||
|
body.put("sign_version", config.getSignVersion());
|
||||||
|
}
|
||||||
|
body.put("sign_type", config.getSignType());
|
||||||
|
String signature = SubMailUtils.signature(body, config.getSignType(), config.getAccessKeyId(), config.getAccessKeySecret(), "vars");
|
||||||
|
body.put("signature", signature);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SMS/MultiSend - 短信一对多发送
|
||||||
|
* 建议:单线程提交数量控制在50个联系人, 可以开多个线程同时发送
|
||||||
|
* @param phones N手机号
|
||||||
|
* @param content 短信内容
|
||||||
|
* @param vars 使用文本变量动态控制短信中的文本
|
||||||
|
* @return 参数组装
|
||||||
|
*/
|
||||||
|
private LinkedHashMap<String, Object> buildMultiSend(List<String> phones, String content, LinkedHashMap<String, String> vars){
|
||||||
|
SubMailConfig config = getConfig();
|
||||||
|
LinkedHashMap<String, Object> body = new LinkedHashMap<>();
|
||||||
|
body.put("appid", config.getAccessKeyId());
|
||||||
|
if (StrUtil.isNotBlank(config.getSignature())){
|
||||||
|
content = StrUtil.addPrefixIfNot(content, "【 " + config.getSignature() + "】") + StrUtil.sub(content, 0, 1000);
|
||||||
|
}else {
|
||||||
|
content = StrUtil.sub(content, 0, 1000);
|
||||||
|
}
|
||||||
|
body.put("content", content);
|
||||||
|
phones = CollUtil.sub(phones, 0, 50);
|
||||||
|
List<LinkedHashMap<String, Object>> multi = new ArrayList<>(phones.size());
|
||||||
|
phones.forEach(phone -> {
|
||||||
|
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
|
||||||
|
map.put("to", StrUtil.addPrefixIfNot(phone, "+86"));
|
||||||
|
map.put("vars", vars);
|
||||||
|
multi.add(map);
|
||||||
|
});
|
||||||
|
body.put("multi", JSONUtil.toJsonStr(multi));
|
||||||
|
body.put("timestamp", timestamp());
|
||||||
|
body.put("sign_type", config.getSignType());
|
||||||
|
if (StrUtil.isNotBlank(config.getSignVersion())){
|
||||||
|
body.put("sign_version", config.getSignVersion());
|
||||||
|
}
|
||||||
|
body.put("sign_type", config.getSignType());
|
||||||
|
String signature = SubMailUtils.signature(body, config.getSignType(), config.getAccessKeyId(), config.getAccessKeySecret(), "multi", "content");
|
||||||
|
body.put("signature", signature);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SMS/MultiXSend - 短信模板一对多发送
|
||||||
|
* 建议: 单线程提交数量控制在50—200个联系人, 可以开多个线程同时发送
|
||||||
|
* @param phones N手机号
|
||||||
|
* @param templateId 短信模板ID
|
||||||
|
* @param vars 使用文本变量动态控制短信中的文本
|
||||||
|
* @return 参数组装
|
||||||
|
*/
|
||||||
|
private LinkedHashMap<String, Object> buildMultiXSend(List<String> phones, String templateId, LinkedHashMap<String, String> vars){
|
||||||
|
SubMailConfig config = getConfig();
|
||||||
|
LinkedHashMap<String, Object> body = new LinkedHashMap<>();
|
||||||
|
body.put("appid", config.getAccessKeyId());
|
||||||
|
body.put("project", templateId);
|
||||||
|
phones = CollUtil.sub(phones, 0, 200);
|
||||||
|
List<LinkedHashMap<String, Object>> multi = new ArrayList<>(phones.size());
|
||||||
|
phones.forEach(phone -> {
|
||||||
|
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
|
||||||
|
map.put("to", StrUtil.addPrefixIfNot(phone, "+86"));
|
||||||
|
map.put("vars", vars);
|
||||||
|
multi.add(map);
|
||||||
|
});
|
||||||
|
body.put("multi", JSONUtil.toJsonStr(multi));
|
||||||
|
body.put("timestamp", timestamp());
|
||||||
|
body.put("sign_type", config.getSignType());
|
||||||
|
if (StrUtil.isNotBlank(config.getSignVersion())){
|
||||||
|
body.put("sign_version", config.getSignVersion());
|
||||||
|
}
|
||||||
|
body.put("sign_type", config.getSignType());
|
||||||
|
String signature = SubMailUtils.signature(body, config.getSignType(), config.getAccessKeyId(), config.getAccessKeySecret(), "multi", "content");
|
||||||
|
body.put("signature", signature);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SMS/BatchSend - 短信批量群发
|
||||||
|
* 单次请求最大支持 10000 个
|
||||||
|
* @param phones N手机号
|
||||||
|
* @param content 短信内容
|
||||||
|
* @return 参数组装
|
||||||
|
*/
|
||||||
|
private LinkedHashMap<String, Object> buildBatchSend(List<String> phones, String content){
|
||||||
|
SubMailConfig config = getConfig();
|
||||||
|
LinkedHashMap<String, Object> body = new LinkedHashMap<>();
|
||||||
|
body.put("appid", config.getAccessKeyId());
|
||||||
|
phones = CollUtil.sub(phones, 0, 10000);
|
||||||
|
body.put("to", SmsUtils.addCodePrefixIfNot(phones));
|
||||||
|
if (StrUtil.isNotBlank(config.getSignature())){
|
||||||
|
content = StrUtil.addPrefixIfNot(content, "【 " + config.getSignature() + "】") + StrUtil.sub(content, 0, 1000);
|
||||||
|
}else {
|
||||||
|
content = StrUtil.sub(content, 0, 1000);
|
||||||
|
}
|
||||||
|
body.put("content", content);
|
||||||
|
body.put("timestamp", timestamp());
|
||||||
|
body.put("sign_type", config.getSignType());
|
||||||
|
if (StrUtil.isNotBlank(config.getSignVersion())){
|
||||||
|
body.put("sign_version", config.getSignVersion());
|
||||||
|
}
|
||||||
|
body.put("sign_type", config.getSignType());
|
||||||
|
String signature = SubMailUtils.signature(body, config.getSignType(), config.getAccessKeyId(), config.getAccessKeySecret(), "content");
|
||||||
|
body.put("signature", signature);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SMS/BatchXSend - 短信批量模板群发
|
||||||
|
* 单次请求最大支持 10000 个
|
||||||
|
* @param phones N手机号
|
||||||
|
* @param templateId 短信模板ID
|
||||||
|
* @param vars 使用文本变量动态控制短信中的文本
|
||||||
|
* @return 参数组装
|
||||||
|
*/
|
||||||
|
private LinkedHashMap<String, Object> buildBatchXSend(List<String> phones, String templateId, LinkedHashMap<String, String> vars){
|
||||||
|
SubMailConfig config = getConfig();
|
||||||
|
LinkedHashMap<String, Object> body = new LinkedHashMap<>();
|
||||||
|
body.put("appid", config.getAccessKeyId());
|
||||||
|
phones = CollUtil.sub(phones, 0, 10000);
|
||||||
|
body.put("to", SmsUtils.addCodePrefixIfNot(phones));
|
||||||
|
body.put("project", templateId);
|
||||||
|
if (MapUtil.isNotEmpty(vars)){
|
||||||
|
body.put("vars", JSONUtil.toJsonStr(vars));
|
||||||
|
}
|
||||||
|
body.put("timestamp", timestamp());
|
||||||
|
body.put("sign_type", config.getSignType());
|
||||||
|
if (StrUtil.isNotBlank(config.getSignVersion())){
|
||||||
|
body.put("sign_version", config.getSignVersion());
|
||||||
|
}
|
||||||
|
body.put("sign_type", config.getSignType());
|
||||||
|
String signature = SubMailUtils.signature(body, config.getSignType(), config.getAccessKeyId(), config.getAccessKeySecret(), "vars");
|
||||||
|
body.put("signature", signature);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String timestamp(){
|
||||||
|
JSONObject resp = http.getUrl("https://api-v4.mysubmail.com/service/timestamp");
|
||||||
|
return resp.getStr("resp");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
package org.dromara.sms4j.submail.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.crypto.digest.DigestAlgorithm;
|
||||||
|
import cn.hutool.crypto.digest.DigestUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
|
import org.dromara.sms4j.comm.utils.SmsUtils;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>类名: SubMailUtils
|
||||||
|
*
|
||||||
|
* @author :bleachtred
|
||||||
|
* 2024/6/22 13:59
|
||||||
|
**/
|
||||||
|
@Slf4j
|
||||||
|
public class SubMailUtils {
|
||||||
|
|
||||||
|
public static LinkedHashMap<String, String> buildHeaders(){
|
||||||
|
LinkedHashMap<String, String> headers = new LinkedHashMap<>(1);
|
||||||
|
headers.put(Constant.ACCEPT, Constant.APPLICATION_JSON);
|
||||||
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_JSON);
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String signature(LinkedHashMap<String, Object> body, String signType, String accessKeyId, String accessKeySecret, String... excludes){
|
||||||
|
if (StrUtil.containsAnyIgnoreCase(signType, DigestAlgorithm.MD5.getValue(), DigestAlgorithm.SHA1.getValue())){
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(accessKeyId).append(accessKeySecret);
|
||||||
|
if ("2".equals(Convert.toStr(body.get("sign_version")))){
|
||||||
|
sb.append(SmsUtils.sortedParamsAsc(body, excludes));
|
||||||
|
}else {
|
||||||
|
sb.append(SmsUtils.sortedParamsAsc(body));
|
||||||
|
}
|
||||||
|
sb.append(accessKeyId).append(accessKeySecret);
|
||||||
|
if (signType.equalsIgnoreCase(DigestAlgorithm.MD5.getValue())){
|
||||||
|
return DigestUtil.md5Hex(sb.toString());
|
||||||
|
}else {
|
||||||
|
return DigestUtil.sha1Hex(sb.toString());
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
return accessKeySecret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -53,7 +53,7 @@ public class TencentSmsImpl extends AbstractSmsBlend<TencentConfig> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
||||||
return getSmsResponse(new String[]{StrUtil.addPrefixIfNot(phone, "+86")}, toArray(messages), templateId);
|
return getSmsResponse(new String[]{StrUtil.addPrefixIfNot(phone, "+86")}, SmsUtils.toArray(messages), templateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -63,11 +63,7 @@ public class TencentSmsImpl extends AbstractSmsBlend<TencentConfig> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
||||||
return getSmsResponse(SmsUtils.listToArray(phones), toArray(messages), templateId);
|
return getSmsResponse(SmsUtils.addCodePrefixIfNotToArray(phones), SmsUtils.toArray(messages), templateId);
|
||||||
}
|
|
||||||
|
|
||||||
private String[] toArray(LinkedHashMap<String, String> messages){
|
|
||||||
return SmsUtils.toArray(messages.values(), SmsUtils::isNotEmpty, s -> s, new String[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SmsResponse getSmsResponse(String[] phones, String[] messages, String templateId) {
|
private SmsResponse getSmsResponse(String[] phones, String[] messages, String templateId) {
|
||||||
@ -89,7 +85,7 @@ public class TencentSmsImpl extends AbstractSmsBlend<TencentConfig> {
|
|||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postJson(url, headsMap, requestBody));
|
smsResponse = getResponse(http.postJson(url, headsMap, requestBody));
|
||||||
} catch (SmsBlendException e) {
|
} catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.getMessage(), getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
|
|||||||
@ -1,20 +1,19 @@
|
|||||||
package org.dromara.sms4j.tencent.utils;
|
package org.dromara.sms4j.tencent.utils;
|
||||||
|
|
||||||
|
import cn.hutool.crypto.digest.DigestUtil;
|
||||||
import cn.hutool.crypto.digest.HMac;
|
import cn.hutool.crypto.digest.HMac;
|
||||||
import cn.hutool.crypto.digest.HmacAlgorithm;
|
import cn.hutool.crypto.digest.HmacAlgorithm;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
|
import org.dromara.sms4j.comm.utils.SmsDateUtils;
|
||||||
import org.dromara.sms4j.tencent.config.TencentConfig;
|
import org.dromara.sms4j.tencent.config.TencentConfig;
|
||||||
|
|
||||||
import javax.xml.bind.DatatypeConverter;
|
import javax.xml.bind.DatatypeConverter;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TimeZone;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Richard
|
* @author Richard
|
||||||
@ -31,18 +30,14 @@ public class TencentUtils {
|
|||||||
*/
|
*/
|
||||||
private static final String HTTP_REQUEST_METHOD = "POST";
|
private static final String HTTP_REQUEST_METHOD = "POST";
|
||||||
|
|
||||||
private static final String CT_JSON = "application/json; charset=utf-8";
|
|
||||||
|
|
||||||
|
|
||||||
private static byte[] hmac256(byte[] key, String msg) {
|
private static byte[] hmac256(byte[] key, String msg) {
|
||||||
HMac hMac = new HMac(HmacAlgorithm.HmacSHA256, key);
|
HMac hMac = new HMac(HmacAlgorithm.HmacSHA256, key);
|
||||||
return hMac.digest(msg.getBytes(StandardCharsets.UTF_8));
|
return hMac.digest(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String sha256Hex(String s) throws Exception {
|
private static String sha256Hex(String s) throws Exception {
|
||||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
return DatatypeConverter.printHexBinary(DigestUtil.sha256(s)).toLowerCase();
|
||||||
byte[] d = md.digest(s.getBytes(StandardCharsets.UTF_8));
|
|
||||||
return DatatypeConverter.printHexBinary(d).toLowerCase();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,13 +47,11 @@ public class TencentUtils {
|
|||||||
* @param messages 短信内容
|
* @param messages 短信内容
|
||||||
* @param phones 手机号
|
* @param phones 手机号
|
||||||
* @param timestamp 时间戳
|
* @param timestamp 时间戳
|
||||||
* @throws Exception
|
* @throws Exception Exception
|
||||||
*/
|
*/
|
||||||
public static String generateSignature(TencentConfig tencentConfig, String templateId, String[] messages, String[] phones,
|
public static String generateSignature(TencentConfig tencentConfig, String templateId, String[] messages, String[] phones,
|
||||||
String timestamp) throws Exception {
|
String timestamp) throws Exception {
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
String date = SmsDateUtils.normDateGmt(new Date(Long.parseLong(timestamp + "000")));
|
||||||
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
|
|
||||||
String date = sdf.format(new Date(Long.parseLong(timestamp + "000")));
|
|
||||||
String canonicalUri = "/";
|
String canonicalUri = "/";
|
||||||
String canonicalQueryString = "";
|
String canonicalQueryString = "";
|
||||||
String canonicalHeaders = "content-type:application/json; charset=utf-8\nhost:" + tencentConfig.getRequestUrl() + "\n";
|
String canonicalHeaders = "content-type:application/json; charset=utf-8\nhost:" + tencentConfig.getRequestUrl() + "\n";
|
||||||
@ -95,8 +88,8 @@ public class TencentUtils {
|
|||||||
public static Map<String, String> generateHeadsMap(String authorization, String timestamp, String action,
|
public static Map<String, String> generateHeadsMap(String authorization, String timestamp, String action,
|
||||||
String version, String territory, String requestUrl) {
|
String version, String territory, String requestUrl) {
|
||||||
Map<String, String> headers = new HashMap<>();
|
Map<String, String> headers = new HashMap<>();
|
||||||
headers.put("Authorization", authorization);
|
headers.put(Constant.AUTHORIZATION, authorization);
|
||||||
headers.put("Content-Type", CT_JSON);
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_JSON_UTF8);
|
||||||
headers.put("Host", requestUrl);
|
headers.put("Host", requestUrl);
|
||||||
headers.put("X-TC-Action", action);
|
headers.put("X-TC-Action", action);
|
||||||
headers.put("X-TC-Timestamp", timestamp);
|
headers.put("X-TC-Timestamp", timestamp);
|
||||||
@ -113,7 +106,7 @@ public class TencentUtils {
|
|||||||
* @param signatureName 短信签名
|
* @param signatureName 短信签名
|
||||||
* @param templateId 模板id
|
* @param templateId 模板id
|
||||||
* @param templateParamSet 模板参数
|
* @param templateParamSet 模板参数
|
||||||
* @return
|
* @return Map
|
||||||
*/
|
*/
|
||||||
public static Map<String, Object> generateRequestBody(String[] phones, String sdkAppId, String signatureName,
|
public static Map<String, Object> generateRequestBody(String[] phones, String sdkAppId, String signatureName,
|
||||||
String templateId, String[] templateParamSet) {
|
String templateId, String[] templateParamSet) {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package org.dromara.sms4j.unisms.core;
|
package org.dromara.sms4j.unisms.core;
|
||||||
|
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化统一环境的单例类.
|
* 初始化统一环境的单例类.
|
||||||
@ -9,7 +10,7 @@ public class Uni {
|
|||||||
public static final String VERSION = "0.0.4";
|
public static final String VERSION = "0.0.4";
|
||||||
|
|
||||||
public static final String SIGNING_ALGORITHM = "hmac-sha256";
|
public static final String SIGNING_ALGORITHM = "hmac-sha256";
|
||||||
public static String endpoint = System.getenv().getOrDefault("UNI_ENDPOINT", "https://uni.apistd.com");
|
public static String endpoint = System.getenv().getOrDefault("UNI_ENDPOINT", Constant.HTTPS_PREFIX + "uni.apistd.com");
|
||||||
public static String accessKeyId = System.getenv("UNI_ACCESS_KEY_ID");
|
public static String accessKeyId = System.getenv("UNI_ACCESS_KEY_ID");
|
||||||
|
|
||||||
private static String accessKeySecret = System.getenv("UNI_ACCESS_KEY_SECRET");
|
private static String accessKeySecret = System.getenv("UNI_ACCESS_KEY_SECRET");
|
||||||
|
|||||||
@ -85,8 +85,8 @@ public class UniClient {
|
|||||||
public UniResponse request(final String action, final Map<String, Object> data) throws SmsBlendException {
|
public UniResponse request(final String action, final Map<String, Object> data) throws SmsBlendException {
|
||||||
Map<String, String> headers = new HashMap<>();
|
Map<String, String> headers = new HashMap<>();
|
||||||
headers.put("User-Agent", USER_AGENT);
|
headers.put("User-Agent", USER_AGENT);
|
||||||
headers.put("Content-Type", Constant.APPLICATION_JSON_UTF8);
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_JSON_UTF8);
|
||||||
headers.put("Accept", Constant.ACCEPT);
|
headers.put(Constant.ACCEPT, Constant.APPLICATION_JSON);
|
||||||
String url;
|
String url;
|
||||||
if (this.isSimple) {
|
if (this.isSimple) {
|
||||||
url = this.endpoint + "?action=" + action + "&accessKeyId=" + this.accessKeyId;
|
url = this.endpoint + "?action=" + action + "&accessKeyId=" + this.accessKeyId;
|
||||||
|
|||||||
@ -101,7 +101,7 @@ public class UniSmsImpl extends AbstractSmsBlend<UniConfig> {
|
|||||||
UniResponse send = Uni.getClient(getConfig().getRetryInterval(), getConfig().getMaxRetries()).request("sms.message.send", data);
|
UniResponse send = Uni.getClient(getConfig().getRetryInterval(), getConfig().getMaxRetries()).request("sms.message.send", data);
|
||||||
return SmsRespUtils.resp(send, "0".equals(send.code), getConfigId());
|
return SmsRespUtils.resp(send, "0".equals(send.code), getConfigId());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return SmsRespUtils.error(e.getMessage(), getConfigId());
|
return errorResp(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -56,7 +56,7 @@ public class YunPianSmsImpl extends AbstractSmsBlend<YunpianConfig> {
|
|||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postFrom(Constant.YUNPIAN_URL + "/sms/tpl_single_send.json", headers, body));
|
smsResponse = getResponse(http.postFrom(Constant.YUNPIAN_URL + "/sms/tpl_single_send.json", headers, body));
|
||||||
} catch (SmsBlendException e) {
|
} catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.getMessage(), getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
@ -113,7 +113,7 @@ public class YunPianSmsImpl extends AbstractSmsBlend<YunpianConfig> {
|
|||||||
if (phones.size() > 1000) {
|
if (phones.size() > 1000) {
|
||||||
throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于1000");
|
throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于1000");
|
||||||
}
|
}
|
||||||
return sendMessage(SmsUtils.listToString(phones), message);
|
return sendMessage(SmsUtils.joinComma(phones), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -124,7 +124,7 @@ public class YunPianSmsImpl extends AbstractSmsBlend<YunpianConfig> {
|
|||||||
if (phones.size() > 1000) {
|
if (phones.size() > 1000) {
|
||||||
throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于1000");
|
throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于1000");
|
||||||
}
|
}
|
||||||
return sendMessage(SmsUtils.listToString(phones), templateId, messages);
|
return sendMessage(SmsUtils.joinComma(phones), templateId, messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formattingMap(Map<String, String> messages) {
|
private String formattingMap(Map<String, String> messages) {
|
||||||
@ -164,8 +164,8 @@ public class YunPianSmsImpl extends AbstractSmsBlend<YunpianConfig> {
|
|||||||
|
|
||||||
private Map<String, String> getHeaders() {
|
private Map<String, String> getHeaders() {
|
||||||
Map<String, String> headers = new HashMap<>();
|
Map<String, String> headers = new HashMap<>();
|
||||||
headers.put("Accept", Constant.APPLICATION_JSON_UTF8);
|
headers.put(Constant.ACCEPT, Constant.APPLICATION_JSON_UTF8);
|
||||||
headers.put("Content-Type", Constant.FROM_URLENCODED);
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_FROM_URLENCODED);
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package org.dromara.sms4j.zhutong.config;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
import org.dromara.sms4j.provider.config.BaseConfig;
|
import org.dromara.sms4j.provider.config.BaseConfig;
|
||||||
|
|
||||||
@ -20,15 +21,15 @@ import org.dromara.sms4j.provider.config.BaseConfig;
|
|||||||
public class ZhutongConfig extends BaseConfig {
|
public class ZhutongConfig extends BaseConfig {
|
||||||
/**
|
/**
|
||||||
* 模板变量名称
|
* 模板变量名称
|
||||||
* 查看地址:https://mix2.zthysms.com/index.html#/TemplateManagement
|
* 查看地址:Constant.HTTPS_PREFIX + mix2.zthysms.com/index.html#/TemplateManagement
|
||||||
* 允许为空,为空,使用无模板形式,发送短信
|
* 允许为空,为空,使用无模板形式,发送短信
|
||||||
*/
|
*/
|
||||||
private String templateName;
|
private String templateName;
|
||||||
/**
|
/**
|
||||||
* 默认请求地址
|
* 默认请求地址
|
||||||
* 不同区域,可切换请求地址,也可以不修改,请参考官方文档:https://doc.zthysms.com/web/#/1/236
|
* 不同区域,可切换请求地址,也可以不修改,请参考官方文档:Constant.HTTPS_PREFIX + doc.zthysms.com/web/#/1/236
|
||||||
*/
|
*/
|
||||||
private String requestUrl = "https://api.mix2.zthysms.com/";
|
private String requestUrl = Constant.HTTPS_PREFIX + "api.mix2.zthysms.com/";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取供应商
|
* 获取供应商
|
||||||
|
|||||||
@ -148,12 +148,12 @@ public class ZhutongSmsImpl extends AbstractSmsBlend<ZhutongConfig> {
|
|||||||
json.put("content", content);
|
json.put("content", content);
|
||||||
|
|
||||||
Map<String, String> headers = MapUtil.newHashMap(1, true);
|
Map<String, String> headers = MapUtil.newHashMap(1, true);
|
||||||
headers.put("Content-Type", Constant.APPLICATION_JSON_UTF8);
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_JSON_UTF8);
|
||||||
SmsResponse smsResponse;
|
SmsResponse smsResponse;
|
||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postJson(url, headers, json));
|
smsResponse = getResponse(http.postJson(url, headers, json));
|
||||||
} catch (SmsBlendException e) {
|
} catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.getMessage(), getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
@ -234,12 +234,12 @@ public class ZhutongSmsImpl extends AbstractSmsBlend<ZhutongConfig> {
|
|||||||
requestJson.set("records", records);
|
requestJson.set("records", records);
|
||||||
|
|
||||||
Map<String, String> headers = MapUtil.newHashMap(1, true);
|
Map<String, String> headers = MapUtil.newHashMap(1, true);
|
||||||
headers.put("Content-Type", Constant.APPLICATION_JSON_UTF8);
|
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_JSON_UTF8);
|
||||||
SmsResponse smsResponse;
|
SmsResponse smsResponse;
|
||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postJson(url, headers, requestJson.toString()));
|
smsResponse = getResponse(http.postJson(url, headers, requestJson.toString()));
|
||||||
} catch (SmsBlendException e) {
|
} catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.getMessage(), getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
|
|||||||
@ -82,7 +82,7 @@ public class ZhangJunSmsImpl extends AbstractSmsBlend<ZhangJunConfig> {
|
|||||||
@Override
|
@Override
|
||||||
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
||||||
String messageStr = JSONUtil.toJsonStr(messages);
|
String messageStr = JSONUtil.toJsonStr(messages);
|
||||||
return getSmsResponse(SmsUtils.arrayToString(phones), messageStr, templateId);
|
return getSmsResponse(SmsUtils.addCodePrefixIfNot(phones), messageStr, templateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SmsResponse getSmsResponse(String phone, String message, String templateId) {
|
private SmsResponse getSmsResponse(String phone, String message, String templateId) {
|
||||||
|
|||||||
@ -112,17 +112,49 @@ sms:
|
|||||||
template-id:
|
template-id:
|
||||||
# 可为空 不为空时请遵守中国移动云MAS开发文档中的描述[服务代码加扩展码总长度不能超过20位。]
|
# 可为空 不为空时请遵守中国移动云MAS开发文档中的描述[服务代码加扩展码总长度不能超过20位。]
|
||||||
add-serial:
|
add-serial:
|
||||||
# 中百度智能云 sms
|
# 百度智能云 sms
|
||||||
baidu:
|
baidu:
|
||||||
access-key-id: 访问密钥ID
|
access-key-id: 访问密钥ID
|
||||||
access-key-secret: 用户密钥
|
access-key-secret: 用户密钥
|
||||||
ec-name: 企业名称
|
ec-name: 企业名称
|
||||||
signature: 签名编码
|
signature: 签名编码
|
||||||
template-id: 模板ID
|
template-id: 模板ID
|
||||||
# 模板变量名称
|
# 模板变量名称
|
||||||
template-name: code
|
template-name: code
|
||||||
custom: 用户自定义参数,格式为字符串,状态回调时会回传该值 可不传
|
custom: 用户自定义参数,格式为字符串,状态回调时会回传该值 可不传
|
||||||
user-ext-id: 通道自定义扩展码 可不传
|
user-ext-id: 通道自定义扩展码 可不传
|
||||||
|
# 创蓝
|
||||||
|
chuanglan:
|
||||||
|
access-key-id: 111111
|
||||||
|
access-key-secret: 111111
|
||||||
|
templateId: 【253云通讯】{$var}您的验证码是:{$var},{$var}分钟内有效
|
||||||
|
# 极光
|
||||||
|
jiguang:
|
||||||
|
supplier: jiguang
|
||||||
|
signId: 签名 ID,该字段为空则使用应用默认签名
|
||||||
|
action: 默认请求方法 messages
|
||||||
|
templateName: 模板变量名称
|
||||||
|
voice: action设置为voice_codes有效 语音验证码播报语言选择,0:中文播报,1:英文播报,2:中英混合播报
|
||||||
|
ttl: action设置为voice_codes有效 验证码有效期,默认为 60 秒
|
||||||
|
tag: action设置为messages/batch有效 标签
|
||||||
|
# 螺丝帽
|
||||||
|
luosimao:
|
||||||
|
accessKeyId: 后台提取的API key
|
||||||
|
action: 默认请求方法 send.json
|
||||||
|
# submail
|
||||||
|
submail:
|
||||||
|
accessKeyId: APPID
|
||||||
|
accessKeySecret: APPKEY
|
||||||
|
action: 默认请求方法 send.json
|
||||||
|
signType: MD5 或 SHA-1 默认MD5 填写任意值,不为即为 密匙明文验证模式
|
||||||
|
signVersion: signature加密计算方式 为2时会忽略某些字段
|
||||||
|
templateId: 模板ID
|
||||||
|
signature: 签名
|
||||||
|
# danmi
|
||||||
|
danmi:
|
||||||
|
accessKeyId: ACCOUNT SID
|
||||||
|
accessKeySecret: AUTH TOKEN
|
||||||
|
action: 默认请求方法 distributor/sendSMS
|
||||||
|
|
||||||
sms-oa:
|
sms-oa:
|
||||||
config-type: yaml
|
config-type: yaml
|
||||||
|
|||||||
@ -13,16 +13,16 @@ import org.dromara.sms4j.baidu.service.BaiduSmsImpl;
|
|||||||
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
import org.dromara.sms4j.comm.utils.SmsUtils;
|
import org.dromara.sms4j.comm.utils.SmsUtils;
|
||||||
import org.dromara.sms4j.core.factory.SmsFactory;
|
import org.dromara.sms4j.core.factory.SmsFactory;
|
||||||
|
import org.dromara.sms4j.danmi.service.DanMiSmsImpl;
|
||||||
|
import org.dromara.sms4j.jg.service.JgSmsImpl;
|
||||||
import org.dromara.sms4j.lianlu.service.LianLuSmsImpl;
|
import org.dromara.sms4j.lianlu.service.LianLuSmsImpl;
|
||||||
|
import org.dromara.sms4j.luosimao.service.LuoSiMaoSmsImpl;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.noear.solon.test.SolonJUnit5Extension;
|
import org.noear.solon.test.SolonJUnit5Extension;
|
||||||
import org.noear.solon.test.SolonTest;
|
import org.noear.solon.test.SolonTest;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ExtendWith(SolonJUnit5Extension.class)
|
@ExtendWith(SolonJUnit5Extension.class)
|
||||||
@ -281,7 +281,7 @@ public class Sms4jTest {
|
|||||||
SmsResponse smsResponse4 = dz.massTexting(phones, "" ,messages);
|
SmsResponse smsResponse4 = dz.massTexting(phones, "" ,messages);
|
||||||
log.info(JSONUtil.toJsonStr(smsResponse4));
|
log.info(JSONUtil.toJsonStr(smsResponse4));
|
||||||
Assert.isTrue(smsResponse4.isSuccess());
|
Assert.isTrue(smsResponse4.isSuccess());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -360,4 +360,172 @@ public class Sms4jTest {
|
|||||||
clientToken);
|
clientToken);
|
||||||
log.info(JSONUtil.toJsonStr(respWithClientToken));
|
log.info(JSONUtil.toJsonStr(respWithClientToken));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* 创蓝短信
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void chungLanTest() {
|
||||||
|
if (StrUtil.isBlank(PHONE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//测试群发【模板】
|
||||||
|
List<String> arrayList = new ArrayList<>();
|
||||||
|
arrayList.add(PHONE);
|
||||||
|
arrayList.add("135****000");
|
||||||
|
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||||
|
map.put("1", "1544");
|
||||||
|
map.put("2", "2222");
|
||||||
|
SmsResponse smsResponse2 = SmsFactory.getBySupplier(SupplierConstant.CHUANGLAN).massTexting(arrayList, "[test]你的验证码是{$val},{$val}", map);
|
||||||
|
log.info("smsResponse2:{}", smsResponse2);
|
||||||
|
|
||||||
|
//测试单条发送
|
||||||
|
SmsResponse smsResponse1 = SmsFactory.getBySupplier(SupplierConstant.CHUANGLAN).sendMessage(PHONE, "1544&2222");
|
||||||
|
log.info("smsResponse1:{}", smsResponse1);
|
||||||
|
|
||||||
|
//测试单条模板发送
|
||||||
|
LinkedHashMap<String, String> map3 = new LinkedHashMap<>();
|
||||||
|
map3.put("1", "1544");
|
||||||
|
map3.put("2", "2222");
|
||||||
|
SmsResponse smsResponse3 = SmsFactory.getBySupplier(SupplierConstant.CHUANGLAN).sendMessage(PHONE, "[test]你的验证码是{$val},{$val}", map3);
|
||||||
|
log.info("smsResponse3:{}", smsResponse3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 极光短信
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void jgSmsTest() {
|
||||||
|
// 极光 发送文本验证码短信 API 不需要传入具体验证码 返回 {"msg_id": "288193860302"}
|
||||||
|
SmsResponse smsResponse1 = SmsFactory.getBySupplier(SupplierConstant.JIGUANG).sendMessage(PHONE, "");
|
||||||
|
Assert.isTrue(smsResponse1.isSuccess());
|
||||||
|
|
||||||
|
// 极光 发送语音验证码短信 请确保action配置为voice_codes
|
||||||
|
JgSmsImpl voiceCode = (JgSmsImpl) SmsFactory.getBySupplier(SupplierConstant.JIGUANG);
|
||||||
|
SmsResponse voiceResp = voiceCode.sendVoiceCode(PHONE,
|
||||||
|
SmsUtils.getRandomInt(6));
|
||||||
|
Assert.isTrue(voiceResp.isSuccess());
|
||||||
|
|
||||||
|
// 验证验证码是否有效 请确保action配置为voice_codes
|
||||||
|
JgSmsImpl verify = (JgSmsImpl) SmsFactory.getBySupplier(SupplierConstant.JIGUANG);
|
||||||
|
SmsResponse verifyResp = verify.verifyCode("123456", "288193860302");
|
||||||
|
Assert.isTrue(verifyResp.isSuccess());
|
||||||
|
|
||||||
|
// 极光 发送单条模板短信 API 发送自定义验证码 sendTemplateSMS
|
||||||
|
LinkedHashMap<String, String> map1 = new LinkedHashMap<>();
|
||||||
|
map1.put("code", "123456");
|
||||||
|
SmsResponse smsResponse2 = SmsFactory.getBySupplier(SupplierConstant.JIGUANG).sendMessage(PHONE, map1);
|
||||||
|
Assert.isTrue(smsResponse2.isSuccess());
|
||||||
|
|
||||||
|
// 极光 发送单条模板短信 API 发送多参数自定义模板短信 sendTemplateSMS_with_multipleParameters
|
||||||
|
LinkedHashMap<String, String> map2 = new LinkedHashMap<>();
|
||||||
|
map2.put("name", "test");
|
||||||
|
map2.put("password", "test");
|
||||||
|
SmsResponse smsResponse3 = SmsFactory.getBySupplier(SupplierConstant.JIGUANG).sendMessage(PHONE, "226992", map2);
|
||||||
|
Assert.isTrue(smsResponse3.isSuccess());
|
||||||
|
|
||||||
|
// sendBatchTemplateSMS
|
||||||
|
LinkedHashMap<String, String> map3 = new LinkedHashMap<>();
|
||||||
|
map3.put("name", "test");
|
||||||
|
map3.put("password", "test");
|
||||||
|
List<String> phones = new ArrayList<>();
|
||||||
|
phones.add(PHONE);
|
||||||
|
phones.add("xxx");
|
||||||
|
SmsResponse smsResponse4 = SmsFactory.getBySupplier(SupplierConstant.JIGUANG).massTexting(phones, "226992", map3);
|
||||||
|
Assert.isTrue(smsResponse4.isSuccess());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 螺丝帽短信
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void luosimaoSmsTest() {
|
||||||
|
// 螺丝帽 发送短信接口详细 发送短信接口详细 send.json
|
||||||
|
SmsResponse smsResponse1 = SmsFactory.getBySupplier(SupplierConstant.LUO_SI_MAO).sendMessage(PHONE, "");
|
||||||
|
Assert.isTrue(smsResponse1.isSuccess());
|
||||||
|
|
||||||
|
// 螺丝帽 批量发送接口详细 send_batch.json
|
||||||
|
SmsResponse smsResponse2 = SmsFactory.getBySupplier(SupplierConstant.LUO_SI_MAO).massTexting(Collections.singletonList(PHONE), "");
|
||||||
|
Assert.isTrue(smsResponse2.isSuccess());
|
||||||
|
|
||||||
|
// 螺丝帽 定时批量发送接口详细 send_batch.json
|
||||||
|
LuoSiMaoSmsImpl luoSiMao = (LuoSiMaoSmsImpl) SmsFactory.getBySupplier(SupplierConstant.LUO_SI_MAO);
|
||||||
|
SmsResponse smsResponse3 = luoSiMao.massTextingOnTime(Collections.singletonList(PHONE), "", new Date());
|
||||||
|
Assert.isTrue(smsResponse3.isSuccess());
|
||||||
|
|
||||||
|
// 螺丝帽 查询账户余额 status.json
|
||||||
|
SmsResponse smsResponse4 = luoSiMao.queryAccountBalance();
|
||||||
|
Assert.isTrue(smsResponse4.isSuccess());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SUBMAIL短信
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void mysubmailSmsTest() {
|
||||||
|
// 短信发送 send.json 【xxxx】签名可配置 系统自动带入
|
||||||
|
SmsResponse smsResponse1 = SmsFactory.getBySupplier(SupplierConstant.MY_SUBMAIL).sendMessage(PHONE, "【SUBMAIL】你好,你的验证码是2257");
|
||||||
|
Assert.isTrue(smsResponse1.isSuccess());
|
||||||
|
|
||||||
|
// 短信模板发送 xsend.json
|
||||||
|
LinkedHashMap<String, String> vars = new LinkedHashMap<>();
|
||||||
|
vars.put("code", "123456");
|
||||||
|
SmsResponse smsResponse2 = SmsFactory.getBySupplier(SupplierConstant.MY_SUBMAIL).sendMessage(PHONE, "xxx", vars);
|
||||||
|
Assert.isTrue(smsResponse2.isSuccess());
|
||||||
|
|
||||||
|
// 短信一对多发送 multisend.json 【xxxx】签名可配置 系统自动带入 content字段说明:短信正文 案例没有说明无需传
|
||||||
|
LinkedHashMap<String, String> vars1 = new LinkedHashMap<>();
|
||||||
|
vars1.put("content", "【SUBMAIL】您的短信验证码:4438,请在10分钟内输入。");
|
||||||
|
vars1.put("code", "123456");
|
||||||
|
vars1.put("time", "10");
|
||||||
|
SmsResponse smsResponse3 = SmsFactory.getBySupplier(SupplierConstant.MY_SUBMAIL).massTexting(Collections.singletonList(PHONE), JSONUtil.toJsonStr(vars1));
|
||||||
|
Assert.isTrue(smsResponse3.isSuccess());
|
||||||
|
|
||||||
|
// 短信模板一对多发送 multixsend.json
|
||||||
|
LinkedHashMap<String, String> vars2 = new LinkedHashMap<>();
|
||||||
|
vars2.put("code", "123456");
|
||||||
|
SmsResponse smsResponse4 = SmsFactory.getBySupplier(SupplierConstant.MY_SUBMAIL).massTexting(Collections.singletonList(PHONE), "xxx", vars2);
|
||||||
|
Assert.isTrue(smsResponse4.isSuccess());
|
||||||
|
|
||||||
|
// 短信批量群发 batchsend.json 【xxxx】签名可配置 系统自动带入 content字段说明:短信正文 案例没有说明无需传
|
||||||
|
LinkedHashMap<String, String> vars3 = new LinkedHashMap<>();
|
||||||
|
vars3.put("content", "123456");
|
||||||
|
SmsResponse smsResponse5 = SmsFactory.getBySupplier(SupplierConstant.MY_SUBMAIL).massTexting(Collections.singletonList(PHONE), JSONUtil.toJsonStr(vars3));
|
||||||
|
Assert.isTrue(smsResponse5.isSuccess());
|
||||||
|
|
||||||
|
// 短信批量模板群发 batchxsend.json
|
||||||
|
LinkedHashMap<String, String> vars4 = new LinkedHashMap<>();
|
||||||
|
vars4.put("code", "123456");
|
||||||
|
vars4.put("time", "10");
|
||||||
|
SmsResponse smsResponse6 = SmsFactory.getBySupplier(SupplierConstant.MY_SUBMAIL).massTexting(Collections.singletonList(PHONE), "xxx", vars4);
|
||||||
|
Assert.isTrue(smsResponse6.isSuccess());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* danmi短信
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void danmiSmsTest() {
|
||||||
|
// 短信发送 distributor/sendSMS 群发 massTexting
|
||||||
|
SmsResponse smsResponse1 = SmsFactory.getBySupplier(SupplierConstant.DAN_MI).sendMessage(PHONE, "【danmi】你好,你的验证码是666");
|
||||||
|
Assert.isTrue(smsResponse1.isSuccess());
|
||||||
|
|
||||||
|
DanMiSmsImpl danMiSms = (DanMiSmsImpl) SmsFactory.getBySupplier(SupplierConstant.DAN_MI);
|
||||||
|
// 短信余额查询 distributor/user/query
|
||||||
|
SmsResponse smsResponse2 = danMiSms.queryBalance();
|
||||||
|
Assert.isTrue(smsResponse2.isSuccess());
|
||||||
|
|
||||||
|
// 语音验证码发送 voice/voiceCode
|
||||||
|
SmsResponse smsResponse3 = danMiSms.voiceCode(PHONE, "666");
|
||||||
|
Assert.isTrue(smsResponse3.isSuccess());
|
||||||
|
|
||||||
|
// 语音通知文件发送 voice/voiceNotify
|
||||||
|
SmsResponse smsResponse4 = danMiSms.voiceNotify(PHONE, "sjkhduiq");
|
||||||
|
Assert.isTrue(smsResponse4.isSuccess());
|
||||||
|
|
||||||
|
// 语音模板通知发送 voice/voiceTemplate
|
||||||
|
SmsResponse smsResponse5 = danMiSms.voiceTemplate(PHONE, "opipedlqza", "111,222,333");
|
||||||
|
Assert.isTrue(smsResponse5.isSuccess());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -71,31 +71,31 @@ public class SmsUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void listToString() {
|
public void joinComma() {
|
||||||
List<String> list = new ArrayList<>();
|
List<String> list = new ArrayList<>();
|
||||||
list.add("12312341234");
|
list.add("12312341234");
|
||||||
list.add("12312341235");
|
list.add("12312341235");
|
||||||
String str = SmsUtils.listToString(list);
|
String str = SmsUtils.joinComma(list);
|
||||||
log.info(str);
|
log.info(str);
|
||||||
Assert.isTrue(str.equals("12312341234,12312341235"));
|
Assert.isTrue(str.equals("12312341234,12312341235"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void arrayToString() {
|
public void addCodePrefixIfNot() {
|
||||||
List<String> list = new ArrayList<>();
|
List<String> list = new ArrayList<>();
|
||||||
list.add("12312341234");
|
list.add("12312341234");
|
||||||
list.add("12312341235");
|
list.add("12312341235");
|
||||||
String str = SmsUtils.arrayToString(list);
|
String str = SmsUtils.addCodePrefixIfNot(list);
|
||||||
log.info(str);
|
log.info(str);
|
||||||
Assert.isTrue(str.equals("+8612312341234,+8612312341235"));
|
Assert.isTrue(str.equals("+8612312341234,+8612312341235"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void listToArray() {
|
public void addCodePrefixIfNotToArray() {
|
||||||
List<String> list = new ArrayList<>();
|
List<String> list = new ArrayList<>();
|
||||||
list.add("12312341234");
|
list.add("12312341234");
|
||||||
list.add("12312341235");
|
list.add("12312341235");
|
||||||
String[] str = SmsUtils.listToArray(list);
|
String[] str = SmsUtils.addCodePrefixIfNotToArray(list);
|
||||||
Assert.isTrue(str[0].equals("+8612312341234") && str[1].equals("+8612312341235"));
|
Assert.isTrue(str[0].equals("+8612312341234") && str[1].equals("+8612312341235"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import org.dromara.sms4j.core.proxy.processor.CoreMethodParamValidateProcessor;
|
|||||||
import org.dromara.sms4j.core.proxy.processor.RestrictedProcessor;
|
import org.dromara.sms4j.core.proxy.processor.RestrictedProcessor;
|
||||||
import org.dromara.sms4j.core.proxy.processor.SingleBlendRestrictedProcessor;
|
import org.dromara.sms4j.core.proxy.processor.SingleBlendRestrictedProcessor;
|
||||||
import org.dromara.sms4j.ctyun.config.CtyunFactory;
|
import org.dromara.sms4j.ctyun.config.CtyunFactory;
|
||||||
|
import org.dromara.sms4j.danmi.config.DanMiFactory;
|
||||||
import org.dromara.sms4j.dingzhong.config.DingZhongFactory;
|
import org.dromara.sms4j.dingzhong.config.DingZhongFactory;
|
||||||
import org.dromara.sms4j.emay.config.EmayFactory;
|
import org.dromara.sms4j.emay.config.EmayFactory;
|
||||||
import org.dromara.sms4j.huawei.config.HuaweiFactory;
|
import org.dromara.sms4j.huawei.config.HuaweiFactory;
|
||||||
@ -29,6 +30,7 @@ import org.dromara.sms4j.jdcloud.config.JdCloudFactory;
|
|||||||
import org.dromara.sms4j.chuanglan.config.ChuangLanFactory;
|
import org.dromara.sms4j.chuanglan.config.ChuangLanFactory;
|
||||||
import org.dromara.sms4j.jg.config.JgFactory;
|
import org.dromara.sms4j.jg.config.JgFactory;
|
||||||
import org.dromara.sms4j.lianlu.config.LianLuFactory;
|
import org.dromara.sms4j.lianlu.config.LianLuFactory;
|
||||||
|
import org.dromara.sms4j.luosimao.config.LuoSiMaoFactory;
|
||||||
import org.dromara.sms4j.mas.config.MasFactory;
|
import org.dromara.sms4j.mas.config.MasFactory;
|
||||||
import org.dromara.sms4j.netease.config.NeteaseFactory;
|
import org.dromara.sms4j.netease.config.NeteaseFactory;
|
||||||
import org.dromara.sms4j.provider.config.SmsConfig;
|
import org.dromara.sms4j.provider.config.SmsConfig;
|
||||||
@ -36,6 +38,7 @@ import org.dromara.sms4j.provider.factory.BaseProviderFactory;
|
|||||||
import org.dromara.sms4j.provider.factory.ProviderFactoryHolder;
|
import org.dromara.sms4j.provider.factory.ProviderFactoryHolder;
|
||||||
import org.dromara.sms4j.qiniu.config.QiNiuFactory;
|
import org.dromara.sms4j.qiniu.config.QiNiuFactory;
|
||||||
import org.dromara.sms4j.solon.holder.SolonSmsDaoHolder;
|
import org.dromara.sms4j.solon.holder.SolonSmsDaoHolder;
|
||||||
|
import org.dromara.sms4j.submail.config.SubMailFactory;
|
||||||
import org.dromara.sms4j.tencent.config.TencentFactory;
|
import org.dromara.sms4j.tencent.config.TencentFactory;
|
||||||
import org.dromara.sms4j.unisms.config.UniFactory;
|
import org.dromara.sms4j.unisms.config.UniFactory;
|
||||||
import org.dromara.sms4j.yunpian.config.YunPianFactory;
|
import org.dromara.sms4j.yunpian.config.YunPianFactory;
|
||||||
@ -101,7 +104,7 @@ public class SmsBlendsInitializer {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
configMap.put("config-id", configId);
|
configMap.put("config-id", configId);
|
||||||
SmsUtils.replaceKeysSeperator(configMap, "-", "_");
|
SmsUtils.replaceKeysSeparator(configMap, "-", "_");
|
||||||
JSONObject configJson = new JSONObject(configMap);
|
JSONObject configJson = new JSONObject(configMap);
|
||||||
SupplierConfig supplierConfig = JSONUtil.toBean(configJson, providerFactory.getConfigClass());
|
SupplierConfig supplierConfig = JSONUtil.toBean(configJson, providerFactory.getConfigClass());
|
||||||
SmsFactory.createSmsBlend(supplierConfig);
|
SmsFactory.createSmsBlend(supplierConfig);
|
||||||
@ -124,13 +127,16 @@ public class SmsBlendsInitializer {
|
|||||||
ProviderFactoryHolder.registerFactory(YunPianFactory.instance());
|
ProviderFactoryHolder.registerFactory(YunPianFactory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(ZhutongFactory.instance());
|
ProviderFactoryHolder.registerFactory(ZhutongFactory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(LianLuFactory.instance());
|
ProviderFactoryHolder.registerFactory(LianLuFactory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(ChuangLanFactory.instance());
|
|
||||||
ProviderFactoryHolder.registerFactory(JgFactory.instance());
|
|
||||||
ProviderFactoryHolder.registerFactory(DingZhongFactory.instance());
|
ProviderFactoryHolder.registerFactory(DingZhongFactory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(QiNiuFactory.instance());
|
ProviderFactoryHolder.registerFactory(QiNiuFactory.instance());
|
||||||
|
ProviderFactoryHolder.registerFactory(ChuangLanFactory.instance());
|
||||||
|
ProviderFactoryHolder.registerFactory(JgFactory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(BudingV2Factory.instance());
|
ProviderFactoryHolder.registerFactory(BudingV2Factory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(MasFactory.instance());
|
ProviderFactoryHolder.registerFactory(MasFactory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(BaiduFactory.instance());
|
ProviderFactoryHolder.registerFactory(BaiduFactory.instance());
|
||||||
|
ProviderFactoryHolder.registerFactory(LuoSiMaoFactory.instance());
|
||||||
|
ProviderFactoryHolder.registerFactory(SubMailFactory.instance());
|
||||||
|
ProviderFactoryHolder.registerFactory(DanMiFactory.instance());
|
||||||
if(SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
|
if(SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
|
||||||
ProviderFactoryHolder.registerFactory(JdCloudFactory.instance());
|
ProviderFactoryHolder.registerFactory(JdCloudFactory.instance());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -83,7 +83,7 @@ public class ZhangJunSmsImpl extends AbstractSmsBlend<ZhangJunConfig> {
|
|||||||
@Override
|
@Override
|
||||||
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
||||||
String messageStr = JSONUtil.toJsonStr(messages);
|
String messageStr = JSONUtil.toJsonStr(messages);
|
||||||
return getSmsResponse(SmsUtils.arrayToString(phones), messageStr, templateId);
|
return getSmsResponse(SmsUtils.addCodePrefixIfNot(phones), messageStr, templateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SmsResponse getSmsResponse(String phone, String message, String templateId) {
|
private SmsResponse getSmsResponse(String phone, String message, String templateId) {
|
||||||
@ -91,7 +91,7 @@ public class ZhangJunSmsImpl extends AbstractSmsBlend<ZhangJunConfig> {
|
|||||||
try {
|
try {
|
||||||
smsResponse = getResponse(http.postJson(getConfig().getUrl(), null, message));
|
smsResponse = getResponse(http.postJson(getConfig().getUrl(), null, message));
|
||||||
} catch (SmsBlendException e) {
|
} catch (SmsBlendException e) {
|
||||||
smsResponse = SmsRespUtils.error(e.getMessage(), getConfigId());
|
smsResponse = errorResp(e.message);
|
||||||
}
|
}
|
||||||
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
if (smsResponse.isSuccess() || retry == getConfig().getMaxRetries()) {
|
||||||
retry = 0;
|
retry = 0;
|
||||||
|
|||||||
@ -112,7 +112,7 @@ sms:
|
|||||||
template-id:
|
template-id:
|
||||||
# 可为空 不为空时请遵守中国移动云MAS开发文档中的描述[服务代码加扩展码总长度不能超过20位。]
|
# 可为空 不为空时请遵守中国移动云MAS开发文档中的描述[服务代码加扩展码总长度不能超过20位。]
|
||||||
add-serial:
|
add-serial:
|
||||||
# 中百度智能云 sms
|
# 百度智能云 sms
|
||||||
baidu:
|
baidu:
|
||||||
access-key-id: 访问密钥ID
|
access-key-id: 访问密钥ID
|
||||||
access-key-secret: 用户密钥
|
access-key-secret: 用户密钥
|
||||||
@ -137,6 +137,24 @@ sms:
|
|||||||
voice: action设置为voice_codes有效 语音验证码播报语言选择,0:中文播报,1:英文播报,2:中英混合播报
|
voice: action设置为voice_codes有效 语音验证码播报语言选择,0:中文播报,1:英文播报,2:中英混合播报
|
||||||
ttl: action设置为voice_codes有效 验证码有效期,默认为 60 秒
|
ttl: action设置为voice_codes有效 验证码有效期,默认为 60 秒
|
||||||
tag: action设置为messages/batch有效 标签
|
tag: action设置为messages/batch有效 标签
|
||||||
|
# 螺丝帽
|
||||||
|
luosimao:
|
||||||
|
accessKeyId: 后台提取的API key
|
||||||
|
action: 默认请求方法 send.json
|
||||||
|
# submail
|
||||||
|
submail:
|
||||||
|
accessKeyId: APPID
|
||||||
|
accessKeySecret: APPKEY
|
||||||
|
action: 默认请求方法 send.json
|
||||||
|
signType: MD5 或 SHA-1 默认MD5 填写任意值,不为即为 密匙明文验证模式
|
||||||
|
signVersion: signature加密计算方式 为2时会忽略某些字段
|
||||||
|
templateId: 模板ID
|
||||||
|
signature: 签名
|
||||||
|
# danmi
|
||||||
|
danmi:
|
||||||
|
accessKeyId: ACCOUNT SID
|
||||||
|
accessKeySecret: AUTH TOKEN
|
||||||
|
action: 默认请求方法 distributor/sendSMS
|
||||||
|
|
||||||
sms-oa:
|
sms-oa:
|
||||||
config-type: yaml
|
config-type: yaml
|
||||||
|
|||||||
@ -13,19 +13,18 @@ import org.dromara.sms4j.baidu.service.BaiduSmsImpl;
|
|||||||
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||||
import org.dromara.sms4j.comm.utils.SmsUtils;
|
import org.dromara.sms4j.comm.utils.SmsUtils;
|
||||||
import org.dromara.sms4j.core.factory.SmsFactory;
|
import org.dromara.sms4j.core.factory.SmsFactory;
|
||||||
|
import org.dromara.sms4j.danmi.service.DanMiSmsImpl;
|
||||||
import org.dromara.sms4j.jg.service.JgSmsImpl;
|
import org.dromara.sms4j.jg.service.JgSmsImpl;
|
||||||
import org.dromara.sms4j.lianlu.service.LianLuSmsImpl;
|
import org.dromara.sms4j.lianlu.service.LianLuSmsImpl;
|
||||||
|
import org.dromara.sms4j.luosimao.service.LuoSiMaoSmsImpl;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
class Sms4jTest {
|
public class Sms4jTest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 填测试手机号
|
* 填测试手机号
|
||||||
@ -434,4 +433,97 @@ class Sms4jTest {
|
|||||||
Assert.isTrue(smsResponse4.isSuccess());
|
Assert.isTrue(smsResponse4.isSuccess());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* 螺丝帽短信
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void luosimaoSmsTest() {
|
||||||
|
// 螺丝帽 发送短信接口详细 发送短信接口详细 send.json
|
||||||
|
SmsResponse smsResponse1 = SmsFactory.getBySupplier(SupplierConstant.LUO_SI_MAO).sendMessage(PHONE, "");
|
||||||
|
Assert.isTrue(smsResponse1.isSuccess());
|
||||||
|
|
||||||
|
// 螺丝帽 批量发送接口详细 send_batch.json
|
||||||
|
SmsResponse smsResponse2 = SmsFactory.getBySupplier(SupplierConstant.LUO_SI_MAO).massTexting(Collections.singletonList(PHONE), "");
|
||||||
|
Assert.isTrue(smsResponse2.isSuccess());
|
||||||
|
|
||||||
|
// 螺丝帽 定时批量发送接口详细 send_batch.json
|
||||||
|
LuoSiMaoSmsImpl luoSiMao = (LuoSiMaoSmsImpl) SmsFactory.getBySupplier(SupplierConstant.LUO_SI_MAO);
|
||||||
|
SmsResponse smsResponse3 = luoSiMao.massTextingOnTime(Collections.singletonList(PHONE), "", new Date());
|
||||||
|
Assert.isTrue(smsResponse3.isSuccess());
|
||||||
|
|
||||||
|
// 螺丝帽 查询账户余额 status.json
|
||||||
|
SmsResponse smsResponse4 = luoSiMao.queryAccountBalance();
|
||||||
|
Assert.isTrue(smsResponse4.isSuccess());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SUBMAIL短信
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void mysubmailSmsTest() {
|
||||||
|
// 短信发送 send.json 【xxxx】签名可配置 系统自动带入
|
||||||
|
SmsResponse smsResponse1 = SmsFactory.getBySupplier(SupplierConstant.MY_SUBMAIL).sendMessage(PHONE, "【SUBMAIL】你好,你的验证码是2257");
|
||||||
|
Assert.isTrue(smsResponse1.isSuccess());
|
||||||
|
|
||||||
|
// 短信模板发送 xsend.json
|
||||||
|
LinkedHashMap<String, String> vars = new LinkedHashMap<>();
|
||||||
|
vars.put("code", "123456");
|
||||||
|
SmsResponse smsResponse2 = SmsFactory.getBySupplier(SupplierConstant.MY_SUBMAIL).sendMessage(PHONE, "xxx", vars);
|
||||||
|
Assert.isTrue(smsResponse2.isSuccess());
|
||||||
|
|
||||||
|
// 短信一对多发送 multisend.json 【xxxx】签名可配置 系统自动带入 content字段说明:短信正文 案例没有说明无需传
|
||||||
|
LinkedHashMap<String, String> vars1 = new LinkedHashMap<>();
|
||||||
|
vars1.put("content", "【SUBMAIL】您的短信验证码:4438,请在10分钟内输入。");
|
||||||
|
vars1.put("code", "123456");
|
||||||
|
vars1.put("time", "10");
|
||||||
|
SmsResponse smsResponse3 = SmsFactory.getBySupplier(SupplierConstant.MY_SUBMAIL).massTexting(Collections.singletonList(PHONE), JSONUtil.toJsonStr(vars1));
|
||||||
|
Assert.isTrue(smsResponse3.isSuccess());
|
||||||
|
|
||||||
|
// 短信模板一对多发送 multixsend.json
|
||||||
|
LinkedHashMap<String, String> vars2 = new LinkedHashMap<>();
|
||||||
|
vars2.put("code", "123456");
|
||||||
|
SmsResponse smsResponse4 = SmsFactory.getBySupplier(SupplierConstant.MY_SUBMAIL).massTexting(Collections.singletonList(PHONE), "xxx", vars2);
|
||||||
|
Assert.isTrue(smsResponse4.isSuccess());
|
||||||
|
|
||||||
|
// 短信批量群发 batchsend.json 【xxxx】签名可配置 系统自动带入 content字段说明:短信正文 案例没有说明无需传
|
||||||
|
LinkedHashMap<String, String> vars3 = new LinkedHashMap<>();
|
||||||
|
vars3.put("content", "123456");
|
||||||
|
SmsResponse smsResponse5 = SmsFactory.getBySupplier(SupplierConstant.MY_SUBMAIL).massTexting(Collections.singletonList(PHONE), JSONUtil.toJsonStr(vars3));
|
||||||
|
Assert.isTrue(smsResponse5.isSuccess());
|
||||||
|
|
||||||
|
// 短信批量模板群发 batchxsend.json
|
||||||
|
LinkedHashMap<String, String> vars4 = new LinkedHashMap<>();
|
||||||
|
vars4.put("code", "123456");
|
||||||
|
vars4.put("time", "10");
|
||||||
|
SmsResponse smsResponse6 = SmsFactory.getBySupplier(SupplierConstant.MY_SUBMAIL).massTexting(Collections.singletonList(PHONE), "xxx", vars4);
|
||||||
|
Assert.isTrue(smsResponse6.isSuccess());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* danmi短信
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void danmiSmsTest() {
|
||||||
|
// 短信发送 distributor/sendSMS 群发 massTexting
|
||||||
|
SmsResponse smsResponse1 = SmsFactory.getBySupplier(SupplierConstant.DAN_MI).sendMessage(PHONE, "【danmi】你好,你的验证码是666");
|
||||||
|
Assert.isTrue(smsResponse1.isSuccess());
|
||||||
|
|
||||||
|
DanMiSmsImpl danMiSms = (DanMiSmsImpl) SmsFactory.getBySupplier(SupplierConstant.DAN_MI);
|
||||||
|
// 短信余额查询 distributor/user/query
|
||||||
|
SmsResponse smsResponse2 = danMiSms.queryBalance();
|
||||||
|
Assert.isTrue(smsResponse2.isSuccess());
|
||||||
|
|
||||||
|
// 语音验证码发送 voice/voiceCode
|
||||||
|
SmsResponse smsResponse3 = danMiSms.voiceCode(PHONE, "666");
|
||||||
|
Assert.isTrue(smsResponse3.isSuccess());
|
||||||
|
|
||||||
|
// 语音通知文件发送 voice/voiceNotify
|
||||||
|
SmsResponse smsResponse4 = danMiSms.voiceNotify(PHONE, "sjkhduiq");
|
||||||
|
Assert.isTrue(smsResponse4.isSuccess());
|
||||||
|
|
||||||
|
// 语音模板通知发送 voice/voiceTemplate
|
||||||
|
SmsResponse smsResponse5 = danMiSms.voiceTemplate(PHONE, "opipedlqza", "111,222,333");
|
||||||
|
Assert.isTrue(smsResponse5.isSuccess());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -68,31 +68,31 @@ public class SmsUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void listToString() {
|
public void joinComma() {
|
||||||
List<String> list = new ArrayList<>();
|
List<String> list = new ArrayList<>();
|
||||||
list.add("12312341234");
|
list.add("12312341234");
|
||||||
list.add("12312341235");
|
list.add("12312341235");
|
||||||
String str = SmsUtils.listToString(list);
|
String str = SmsUtils.joinComma(list);
|
||||||
log.info(str);
|
log.info(str);
|
||||||
Assert.isTrue(str.equals("12312341234,12312341235"));
|
Assert.isTrue(str.equals("12312341234,12312341235"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void arrayToString() {
|
public void addCodePrefixIfNot() {
|
||||||
List<String> list = new ArrayList<>();
|
List<String> list = new ArrayList<>();
|
||||||
list.add("12312341234");
|
list.add("12312341234");
|
||||||
list.add("12312341235");
|
list.add("12312341235");
|
||||||
String str = SmsUtils.arrayToString(list);
|
String str = SmsUtils.addCodePrefixIfNot(list);
|
||||||
log.info(str);
|
log.info(str);
|
||||||
Assert.isTrue(str.equals("+8612312341234,+8612312341235"));
|
Assert.isTrue(str.equals("+8612312341234,+8612312341235"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void listToArray() {
|
public void addCodePrefixIfNotToArray() {
|
||||||
List<String> list = new ArrayList<>();
|
List<String> list = new ArrayList<>();
|
||||||
list.add("12312341234");
|
list.add("12312341234");
|
||||||
list.add("12312341235");
|
list.add("12312341235");
|
||||||
String[] str = SmsUtils.listToArray(list);
|
String[] str = SmsUtils.addCodePrefixIfNotToArray(list);
|
||||||
Assert.isTrue(str[0].equals("+8612312341234") && str[1].equals("+8612312341235"));
|
Assert.isTrue(str[0].equals("+8612312341234") && str[1].equals("+8612312341235"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class ConfigCombineMapAdeptor<S, M> extends HashMap {
|
public class ConfigCombineMapAdaptor<S, M> extends HashMap {
|
||||||
@Override
|
@Override
|
||||||
public M get(Object key) {
|
public M get(Object key) {
|
||||||
Object o = super.get(key);
|
Object o = super.get(key);
|
||||||
@ -41,6 +41,4 @@ public class ConfigCombineMapAdeptor<S, M> extends HashMap {
|
|||||||
}
|
}
|
||||||
return (M)o;
|
return (M)o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -12,7 +12,7 @@ import org.dromara.sms4j.budingyun.config.BudingV2Factory;
|
|||||||
import org.dromara.sms4j.api.verify.PhoneVerify;
|
import org.dromara.sms4j.api.verify.PhoneVerify;
|
||||||
import org.dromara.sms4j.cloopen.config.CloopenFactory;
|
import org.dromara.sms4j.cloopen.config.CloopenFactory;
|
||||||
import org.dromara.sms4j.comm.constant.Constant;
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
import org.dromara.sms4j.comm.enumerate.ConfigType;
|
import org.dromara.sms4j.comm.enums.ConfigType;
|
||||||
import org.dromara.sms4j.comm.utils.SmsUtils;
|
import org.dromara.sms4j.comm.utils.SmsUtils;
|
||||||
import org.dromara.sms4j.core.datainterface.SmsReadConfig;
|
import org.dromara.sms4j.core.datainterface.SmsReadConfig;
|
||||||
import org.dromara.sms4j.core.factory.SmsFactory;
|
import org.dromara.sms4j.core.factory.SmsFactory;
|
||||||
@ -24,6 +24,7 @@ import org.dromara.sms4j.core.proxy.processor.CoreMethodParamValidateProcessor;
|
|||||||
import org.dromara.sms4j.core.proxy.processor.RestrictedProcessor;
|
import org.dromara.sms4j.core.proxy.processor.RestrictedProcessor;
|
||||||
import org.dromara.sms4j.core.proxy.processor.SingleBlendRestrictedProcessor;
|
import org.dromara.sms4j.core.proxy.processor.SingleBlendRestrictedProcessor;
|
||||||
import org.dromara.sms4j.ctyun.config.CtyunFactory;
|
import org.dromara.sms4j.ctyun.config.CtyunFactory;
|
||||||
|
import org.dromara.sms4j.danmi.config.DanMiFactory;
|
||||||
import org.dromara.sms4j.dingzhong.config.DingZhongFactory;
|
import org.dromara.sms4j.dingzhong.config.DingZhongFactory;
|
||||||
import org.dromara.sms4j.emay.config.EmayFactory;
|
import org.dromara.sms4j.emay.config.EmayFactory;
|
||||||
import org.dromara.sms4j.huawei.config.HuaweiFactory;
|
import org.dromara.sms4j.huawei.config.HuaweiFactory;
|
||||||
@ -31,13 +32,15 @@ import org.dromara.sms4j.jdcloud.config.JdCloudFactory;
|
|||||||
import org.dromara.sms4j.chuanglan.config.ChuangLanFactory;
|
import org.dromara.sms4j.chuanglan.config.ChuangLanFactory;
|
||||||
import org.dromara.sms4j.jg.config.JgFactory;
|
import org.dromara.sms4j.jg.config.JgFactory;
|
||||||
import org.dromara.sms4j.lianlu.config.LianLuFactory;
|
import org.dromara.sms4j.lianlu.config.LianLuFactory;
|
||||||
|
import org.dromara.sms4j.luosimao.config.LuoSiMaoFactory;
|
||||||
import org.dromara.sms4j.mas.config.MasFactory;
|
import org.dromara.sms4j.mas.config.MasFactory;
|
||||||
import org.dromara.sms4j.netease.config.NeteaseFactory;
|
import org.dromara.sms4j.netease.config.NeteaseFactory;
|
||||||
import org.dromara.sms4j.provider.config.SmsConfig;
|
import org.dromara.sms4j.provider.config.SmsConfig;
|
||||||
import org.dromara.sms4j.provider.factory.BaseProviderFactory;
|
import org.dromara.sms4j.provider.factory.BaseProviderFactory;
|
||||||
import org.dromara.sms4j.provider.factory.ProviderFactoryHolder;
|
import org.dromara.sms4j.provider.factory.ProviderFactoryHolder;
|
||||||
import org.dromara.sms4j.qiniu.config.QiNiuFactory;
|
import org.dromara.sms4j.qiniu.config.QiNiuFactory;
|
||||||
import org.dromara.sms4j.starter.adepter.ConfigCombineMapAdeptor;
|
import org.dromara.sms4j.starter.adepter.ConfigCombineMapAdaptor;
|
||||||
|
import org.dromara.sms4j.submail.config.SubMailFactory;
|
||||||
import org.dromara.sms4j.tencent.config.TencentFactory;
|
import org.dromara.sms4j.tencent.config.TencentFactory;
|
||||||
import org.dromara.sms4j.unisms.config.UniFactory;
|
import org.dromara.sms4j.unisms.config.UniFactory;
|
||||||
import org.dromara.sms4j.yunpian.config.YunPianFactory;
|
import org.dromara.sms4j.yunpian.config.YunPianFactory;
|
||||||
@ -76,7 +79,7 @@ public class SmsBlendsInitializer {
|
|||||||
|
|
||||||
if (ConfigType.YAML.equals(this.smsConfig.getConfigType())) {
|
if (ConfigType.YAML.equals(this.smsConfig.getConfigType())) {
|
||||||
//持有初始化配置信息
|
//持有初始化配置信息
|
||||||
Map<String, Map<String, Object>> blendsInclude = new ConfigCombineMapAdeptor<String, Map<String, Object>>();
|
Map<String, Map<String, Object>> blendsInclude = new ConfigCombineMapAdaptor<String, Map<String, Object>>();
|
||||||
blendsInclude.putAll(this.blends);
|
blendsInclude.putAll(this.blends);
|
||||||
int num = 0;
|
int num = 0;
|
||||||
for (SmsReadConfig smsReadConfig : extendsSmsConfigs) {
|
for (SmsReadConfig smsReadConfig : extendsSmsConfigs) {
|
||||||
@ -146,6 +149,9 @@ public class SmsBlendsInitializer {
|
|||||||
ProviderFactoryHolder.registerFactory(BudingV2Factory.instance());
|
ProviderFactoryHolder.registerFactory(BudingV2Factory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(MasFactory.instance());
|
ProviderFactoryHolder.registerFactory(MasFactory.instance());
|
||||||
ProviderFactoryHolder.registerFactory(BaiduFactory.instance());
|
ProviderFactoryHolder.registerFactory(BaiduFactory.instance());
|
||||||
|
ProviderFactoryHolder.registerFactory(LuoSiMaoFactory.instance());
|
||||||
|
ProviderFactoryHolder.registerFactory(SubMailFactory.instance());
|
||||||
|
ProviderFactoryHolder.registerFactory(DanMiFactory.instance());
|
||||||
if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
|
if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
|
||||||
if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
|
if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
|
||||||
ProviderFactoryHolder.registerFactory(JdCloudFactory.instance());
|
ProviderFactoryHolder.registerFactory(JdCloudFactory.instance());
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
|
|||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import org.dromara.sms4j.api.SmsBlend;
|
import org.dromara.sms4j.api.SmsBlend;
|
||||||
import org.dromara.sms4j.comm.constant.Constant;
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
import org.dromara.sms4j.comm.enumerate.ConfigType;
|
import org.dromara.sms4j.comm.enums.ConfigType;
|
||||||
import org.dromara.sms4j.core.datainterface.SmsReadConfig;
|
import org.dromara.sms4j.core.datainterface.SmsReadConfig;
|
||||||
import org.dromara.sms4j.provider.config.SmsConfig;
|
import org.dromara.sms4j.provider.config.SmsConfig;
|
||||||
import org.dromara.sms4j.provider.factory.BaseProviderFactory;
|
import org.dromara.sms4j.provider.factory.BaseProviderFactory;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user