feat: netease

This commit is contained in:
adam 2023-06-02 15:34:57 +08:00
parent f4b1ecb01a
commit 6028b004b3
8 changed files with 380 additions and 13 deletions

View File

@ -9,6 +9,7 @@ import org.dromara.sms4j.ctyun.config.CtyunConfig;
import org.dromara.sms4j.emay.config.EmayConfig;
import org.dromara.sms4j.huawei.config.HuaweiConfig;
import org.dromara.sms4j.jdcloud.config.JdCloudConfig;
import org.dromara.sms4j.netease.config.NeteaseConfig;
import org.dromara.sms4j.provider.enumerate.SupplierType;
import org.dromara.sms4j.tencent.config.TencentConfig;
import org.dromara.sms4j.unisms.config.UniConfig;
@ -29,7 +30,7 @@ public class SupplierSqlConfig {
* readSqlConfig
* <p>读取数据库配置信息
* @author :Wind
*/
*/
public static void readSqlConfig(){
select = JDBCTool.selectConfig();
}
@ -38,7 +39,7 @@ public class SupplierSqlConfig {
* refreshSqlConfig
* <p>读取并刷新数据库配置
* @author :Wind
*/
*/
public static void refreshSqlConfig(){
readSqlConfig();
alibaba();
@ -50,6 +51,7 @@ public class SupplierSqlConfig {
cloopen();
emay();
ctyun();
netease();
}
public SupplierSqlConfig() {
@ -64,17 +66,17 @@ public class SupplierSqlConfig {
* alibaba
* <p>数据库读取并设置阿里云短信
* @author :Wind
*/
*/
public static void alibaba(){
AlibabaConfig alibabaConfig = SmsUtil.jsonForObject(select.get(SupplierType.ALIBABA.getName()), AlibabaConfig.class);
SupplierFactory.setAlibabaConfig(alibabaConfig);
SupplierFactory.setAlibabaConfig(alibabaConfig);
}
/**
* huawei
* <p>数据库读取并设置华为短信
* @author :Wind
*/
*/
public static void huawei(){
HuaweiConfig huaweiConfig = SmsUtil.jsonForObject(select.get(SupplierType.HUAWEI.getName()), HuaweiConfig.class);
SupplierFactory.setHuaweiConfig(huaweiConfig);
@ -84,7 +86,7 @@ public class SupplierSqlConfig {
* jingdong
* <p>数据库读取并设置京东短信
* @author :Wind
*/
*/
public static void jingdong(){
JdCloudConfig jdCloudConfig = SmsUtil.jsonForObject(select.get(SupplierType.JD_CLOUD.getName()), JdCloudConfig.class);
SupplierFactory.setJdCloudConfig(jdCloudConfig);
@ -94,7 +96,7 @@ public class SupplierSqlConfig {
* tencent
* <p>数据库读取并设置腾讯短信
* @author :Wind
*/
*/
public static void tencent(){
TencentConfig tencentConfig = SmsUtil.jsonForObject(select.get(SupplierType.TENCENT.getName()), TencentConfig.class);
SupplierFactory.setTencentConfig(tencentConfig);
@ -104,7 +106,7 @@ public class SupplierSqlConfig {
* uniSms
* <p>数据库读取并设置合一短信配置
* @author :Wind
*/
*/
public static void uniSms(){
UniConfig uniConfig = SmsUtil.jsonForObject(select.get(SupplierType.UNI_SMS.getName()), UniConfig.class);
SupplierFactory.setUniConfig(uniConfig);
@ -114,7 +116,7 @@ public class SupplierSqlConfig {
* yunPian
* <p>数据库读取并设置云片短信
* @author :Wind
*/
*/
public static void yunPian(){
YunpianConfig yunpianConfig = SmsUtil.jsonForObject(select.get(SupplierType.YUNPIAN.getName()), YunpianConfig.class);
SupplierFactory.setYunpianConfig(yunpianConfig);
@ -124,7 +126,7 @@ public class SupplierSqlConfig {
* cloopen
* <p>数据库读取并设置容联云短信
* @author :Wind
*/
*/
public static void cloopen(){
CloopenConfig cloopenConfig = SmsUtil.jsonForObject(select.get(SupplierType.CLOOPEN.getName()), CloopenConfig.class);
SupplierFactory.setCloopenConfig(cloopenConfig);
@ -143,9 +145,19 @@ public class SupplierSqlConfig {
* ctyun
* <p>数据库读取并设置天翼云短信
* @author :Wind
*/
*/
public static void ctyun(){
CtyunConfig ctyunConfig = SmsUtil.jsonForObject(select.get(SupplierType.CTYUN.getName()), CtyunConfig.class);
SupplierFactory.setCtyunConfig(ctyunConfig);
}
/**
* netease
* <p>数据库读取并设置网易云短信
* @author : Adam
*/
public static void netease(){
NeteaseConfig neteaseConfig = SmsUtil.jsonForObject(select.get(SupplierType.NETEASE.getName()), NeteaseConfig.class);
SupplierFactory.setNeteaseConfig(neteaseConfig);
}
}

View File

@ -15,6 +15,8 @@ import org.dromara.sms4j.huawei.config.HuaweiConfig;
import org.dromara.sms4j.huawei.config.HuaweiFactory;
import org.dromara.sms4j.jdcloud.config.JdCloudConfig;
import org.dromara.sms4j.jdcloud.config.JdCloudFactory;
import org.dromara.sms4j.netease.config.NeteaseConfig;
import org.dromara.sms4j.netease.config.NeteaseFactory;
import org.dromara.sms4j.provider.enumerate.SupplierType;
import org.dromara.sms4j.tencent.config.TencentConfig;
import org.dromara.sms4j.tencent.config.TencentFactory;
@ -96,12 +98,19 @@ public class SupplierFactory {
return CtyunFactory.instance().getConfig();
}
/**
* 网易云信配置获取
*/
public static NeteaseConfig getNeteaseConfig() {
return NeteaseFactory.instance().getConfig();
}
/**
* setSupplierConfig
* <p>通用化set用于设置
* @param t 配置对象
* @author :Wind
*/
*/
public static <T extends SupplierConfig> void setSupplierConfig(T t) {
if (t instanceof AlibabaConfig) {
setAlibabaConfig((AlibabaConfig) t);
@ -121,7 +130,9 @@ public class SupplierFactory {
setEmayConfig((EmayConfig) t);
} else if (t instanceof CtyunConfig) {
setCtyunConfig((CtyunConfig) t);
}else {
} else if (t instanceof NeteaseConfig) {
setNeteaseConfig((NeteaseConfig) t);
} else {
throw new SmsBlendException("Loading failure! Please check the configuration type.");
}
}
@ -197,4 +208,12 @@ public class SupplierFactory {
CtyunFactory.instance().setConfig(ctyunConfig);
SmsFactory.refresh(SupplierType.CTYUN);
}
/**
* 设置 neteaseConfig
*/
public static void setNeteaseConfig(NeteaseConfig neteaseConfig) {
NeteaseFactory.instance().setConfig(neteaseConfig);
SmsFactory.refresh(SupplierType.NETEASE);
}
}

View File

@ -0,0 +1,56 @@
package org.dromara.sms4j.netease.config;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.SuperBuilder;
import org.dromara.sms4j.api.universal.SupplierConfig;
import org.dromara.sms4j.comm.config.BaseConfig;
/**
* @author adam
*/
@Data
@SuperBuilder
public class NeteaseConfig extends BaseConfig implements SupplierConfig {
/**
* 模板变量名称
*/
private String templateId;
/**
* appKey
*/
private String appKey;
/**
* secret
*/
private String secret;
/**
* 模板短信请求地址
*/
@Builder.Default
private String templateUrl = "https://api.netease.im/sms/sendtemplate.action";
/**
* 验证码短信请求地址
*/
@Builder.Default
private String codeUrl = "https://api.netease.im/sms/sendcode.action";
/**
* 验证码验证请求地址
*/
@Builder.Default
private String verifyUrl = "https://api.netease.im/sms/verifycode.action";
/**
* 是否需要支持短信上行true:需要false:不需要
* 说明如果开通了短信上行抄送功能该参数需要设置为true其它情况设置无效
*/
private final Boolean needUp;
}

View File

@ -0,0 +1,81 @@
package org.dromara.sms4j.netease.config;
import org.dromara.sms4j.comm.factory.BeanFactory;
import org.dromara.sms4j.netease.service.NeteaseSmsImpl;
import org.dromara.sms4j.provider.base.BaseProviderFactory;
/**
* NeteaseSmsConfig
* <p> 网易云信短信
*
* @author :adam
* 2023-05-30
**/
public class NeteaseFactory implements BaseProviderFactory<NeteaseSmsImpl, NeteaseConfig> {
private static NeteaseSmsImpl neteaseSms;
private static final NeteaseFactory INSTANCE = new NeteaseFactory();
private static final class ConfigHolder {
private static NeteaseConfig config = NeteaseConfig.builder().build();
}
private NeteaseFactory() {
}
/**
* 获取建造者实例
* @return 建造者实例
*/
public static NeteaseFactory instance() {
return INSTANCE;
}
/**
* 建造一个网易云的短信实现
*/
@Override
public NeteaseSmsImpl createSms(NeteaseConfig neteaseConfig) {
if (neteaseSms == null) {
neteaseSms = new NeteaseSmsImpl(
neteaseConfig,
BeanFactory.getExecutor(),
BeanFactory.getDelayedTime()
);
}
return neteaseSms;
}
/**
* 刷新对象
*/
@Override
public NeteaseSmsImpl refresh(NeteaseConfig neteaseConfig) {
neteaseSms = new NeteaseSmsImpl(
neteaseConfig,
BeanFactory.getExecutor(),
BeanFactory.getDelayedTime()
);
return neteaseSms;
}
/**
* 获取配置
* @return 配置对象
*/
@Override
public NeteaseConfig getConfig() {
return ConfigHolder.config;
}
/**
* 设置配置
* @param config 配置对象
*/
@Override
public void setConfig(NeteaseConfig config) {
ConfigHolder.config = config;
}
}

View File

@ -0,0 +1,134 @@
package org.dromara.sms4j.netease.service;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.api.AbstractSmsBlend;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.comm.annotation.Restricted;
import org.dromara.sms4j.comm.delayedTime.DelayedTime;
import org.dromara.sms4j.comm.exception.SmsBlendException;
import org.dromara.sms4j.netease.config.NeteaseConfig;
import org.dromara.sms4j.netease.utils.NeteaseUtils;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReference;
/**
* Created with IntelliJ IDEA.
*
* @author adam
* @create 2023/5/29 17:34
*/
@Slf4j
public class NeteaseSmsImpl extends AbstractSmsBlend {
private NeteaseConfig config;
public NeteaseSmsImpl(NeteaseConfig config, Executor pool, DelayedTime delayed) {
super(pool, delayed);
this.config = config;
}
/**
*
* @param phone 接收短信的手机号
* @param message 短信变量 ["xxx","yyy"]
* @return
*/
@Override
@Restricted
public SmsResponse sendMessage(String phone, String message) {
Optional.ofNullable(phone).orElseThrow(() -> new SmsBlendException("手机号不能为空"));
Optional.ofNullable(config.getTemplateId()).orElseThrow(() -> new SmsBlendException("模板ID不能为空"));
return getSmsResponse(config.getTemplateUrl(), Collections.singletonList(phone), message, config.getTemplateId());
}
/**
*
* @param phone
* @param templateId 模板id
* @param messages 短信变量 key为默认 params value为模板变量值 ["xxx","yyy"]
* @return
*/
@Override
@Restricted
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
Optional.ofNullable(phone).orElseThrow(() -> new SmsBlendException("手机号不能为空"));
Optional.ofNullable(config.getTemplateId()).orElseThrow(() -> new SmsBlendException("模板ID不能为空"));
String messageStr = messages.get("params");
return getSmsResponse(config.getTemplateUrl(), Collections.singletonList(phone), messageStr, templateId);
}
@Override
@Restricted
public SmsResponse massTexting(List<String> phones, String message) {
if (phones.size() < 1) {
throw new SmsBlendException("手机号不能为空");
}
if (phones.size() > 100) {
throw new SmsBlendException("单次发送超过最大发送上限建议每次群发短信人数低于100");
}
Optional.ofNullable(config.getTemplateId()).orElseThrow(() -> new SmsBlendException("模板ID不能为空"));
return getSmsResponse(config.getTemplateUrl(), phones, config.getTemplateId(), message);
}
@Override
@Restricted
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
if (phones.size() > 100) {
throw new SmsBlendException("单次发送超过最大发送上限建议每次群发短信人数低于100");
}
Optional.ofNullable(config.getTemplateId()).orElseThrow(() -> new SmsBlendException("模板ID不能为空"));
String messageStr = messages.get("message");
return getSmsResponse(config.getTemplateUrl(), phones, messageStr, templateId);
}
private SmsResponse getSmsResponse(String requestUrl, List<String> phones, String message, String templateId) {
AtomicReference<SmsResponse> reference = new AtomicReference<>();
String nonce = IdUtil.fastSimpleUUID();
String curTime = String.valueOf(DateUtil.currentSeconds());
String checkSum = NeteaseUtils.getCheckSum(config.getSecret(), nonce, curTime);
Map<String, Object> body = new LinkedHashMap<>(4);
body.put("templateid", templateId);
body.put("mobiles", JSONArray.parseArray(JSON.toJSONString(phones)).toJSONString());
body.put("params", message);
body.put("needUp", config.getNeedUp());
http.post(requestUrl)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("AppKey", config.getAppKey())
.addHeader("Nonce", nonce)
.addHeader("CurTime", curTime)
.addHeader("CheckSum", checkSum)
.addBody(body)
.onSuccess(((data, req, res) -> {
reference.set(this.getResponse(res.get(JSONObject.class)));
}))
.onError((ex, req, res) -> {
reference.set(this.getResponse(res.get(JSONObject.class)));
})
.execute();
return reference.get();
}
private SmsResponse getResponse(JSONObject jsonObject) {
SmsResponse response = new SmsResponse();
Integer code = jsonObject.getInteger("code");
if (code > 200) {
response.setErrorCode(String.valueOf(code));
response.setErrMessage(jsonObject.getString("msg"));
} else {
response.setCode(String.valueOf(code));
response.setMessage(jsonObject.getString("msg"));
response.setData(jsonObject.get("obj"));
}
return response;
}
}

View File

@ -0,0 +1,51 @@
package org.dromara.sms4j.netease.utils;
import org.dromara.sms4j.comm.exception.SmsBlendException;
import java.security.MessageDigest;
/**
* Created with IntelliJ IDEA.
*
* @author adam
* @create 2023/5/29 17:49
*/
public class NeteaseUtils {
/**
* 计算并获取CheckSum
* @param appSecret
* @param nonce
* @param curTime
* @return
*/
public static String getCheckSum(String appSecret, String nonce, String curTime) {
return encode("sha1", appSecret + nonce + curTime);
}
private static String encode(String algorithm, String value) {
if (value == null) {
return null;
}
try {
MessageDigest messageDigest
= MessageDigest.getInstance(algorithm);
messageDigest.update(value.getBytes());
return getFormattedText(messageDigest.digest());
} catch (Exception e) {
throw new SmsBlendException(e.getMessage());
}
}
private static String getFormattedText(byte[] bytes) {
int len = bytes.length;
StringBuilder buf = new StringBuilder(len * 2);
for (int j = 0; j < len; j++) {
buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
}
return buf.toString();
}
private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
}

View File

@ -8,6 +8,7 @@ import org.dromara.sms4j.ctyun.config.CtyunFactory;
import org.dromara.sms4j.emay.config.EmayFactory;
import org.dromara.sms4j.huawei.config.HuaweiFactory;
import org.dromara.sms4j.jdcloud.config.JdCloudFactory;
import org.dromara.sms4j.netease.config.NeteaseFactory;
import org.dromara.sms4j.provider.base.BaseProviderFactory;
import org.dromara.sms4j.tencent.config.TencentFactory;
import org.dromara.sms4j.unisms.config.UniFactory;
@ -38,6 +39,8 @@ public enum SupplierType {
EMAY("亿美软通", EmayFactory.instance()),
/** 天翼云 */
CTYUN("天翼云短信", CtyunFactory.instance()),
/** 网易云信 */
NETEASE("网易云短信", NeteaseFactory.instance())
;

View File

@ -7,6 +7,7 @@ import org.dromara.sms4j.ctyun.config.CtyunConfig;
import org.dromara.sms4j.emay.config.EmayConfig;
import org.dromara.sms4j.huawei.config.HuaweiConfig;
import org.dromara.sms4j.jdcloud.config.JdCloudConfig;
import org.dromara.sms4j.netease.config.NeteaseConfig;
import org.dromara.sms4j.tencent.config.TencentConfig;
import org.dromara.sms4j.unisms.config.UniConfig;
import org.dromara.sms4j.yunpian.config.YunpianConfig;
@ -82,4 +83,14 @@ public class SupplierConfig {
protected CtyunConfig ctyunConfig(){
return SupplierFactory.getCtyunConfig();
}
/**
* 网易云信差异化配置
*/
@Bean
@ConfigurationProperties(prefix = "sms.netease")
protected NeteaseConfig neteaseConfig(){
return SupplierFactory.getNeteaseConfig();
}
}