短信推送demo

This commit is contained in:
caozehui
2026-02-26 15:45:19 +08:00
parent fac4a39214
commit c7f3687bf8
21 changed files with 381 additions and 117 deletions

View File

@@ -35,19 +35,19 @@ public class ClientConfiguration {
for (ChannelProviderConfigDO config : activeProviders) {
switch (config.getProviderType()) {
case MsgPushConstant.ALI_YUN: {
MessageProviderFactory orDefault = messageProviderFactoryMap.getOrDefault(MsgPushConstant.ALI_YUN, new AliyunProviderFactory());
messageProviderFactoryMap.put(MsgPushConstant.ALI_YUN, orDefault);
case MsgPushConstant.PROVIDER_TYPE_ALI_YUN: {
MessageProviderFactory orDefault = messageProviderFactoryMap.getOrDefault(MsgPushConstant.PROVIDER_TYPE_ALI_YUN, new AliyunProviderFactory());
messageProviderFactoryMap.put(MsgPushConstant.PROVIDER_TYPE_ALI_YUN, orDefault);
}
break;
case MsgPushConstant.TELECOM: {
MessageProviderFactory orDefault = messageProviderFactoryMap.getOrDefault(MsgPushConstant.TELECOM, new AliyunProviderFactory());
messageProviderFactoryMap.put(MsgPushConstant.TELECOM, orDefault);
case MsgPushConstant.PROVIDER_TYPE_TELECOM: {
MessageProviderFactory orDefault = messageProviderFactoryMap.getOrDefault(MsgPushConstant.PROVIDER_TYPE_TELECOM, new AliyunProviderFactory());
messageProviderFactoryMap.put(MsgPushConstant.PROVIDER_TYPE_TELECOM, orDefault);
}
break;
case MsgPushConstant.UNI_PUSH: {
MessageProviderFactory orDefault = messageProviderFactoryMap.getOrDefault(MsgPushConstant.UNI_PUSH, new AliyunProviderFactory());
messageProviderFactoryMap.put(MsgPushConstant.UNI_PUSH, orDefault);
case MsgPushConstant.PROVIDER_TYPE_UNI_PUSH: {
MessageProviderFactory orDefault = messageProviderFactoryMap.getOrDefault(MsgPushConstant.PROVIDER_TYPE_UNI_PUSH, new AliyunProviderFactory());
messageProviderFactoryMap.put(MsgPushConstant.PROVIDER_TYPE_UNI_PUSH, orDefault);
}
break;
default:

View File

@@ -13,7 +13,7 @@ public interface MessageProviderFactory {
/**
* 创建短信发送器
*/
SmsSender createSmsSender(ChannelProviderConfigDO config) throws Exception;
SmsSender createSmsSender(ChannelProviderConfigDO config);
/**
* 创建邮件发送器
@@ -23,5 +23,5 @@ public interface MessageProviderFactory {
/**
* 创建APP推送发送器
*/
AppPushSender createAppPushSender();
AppPushSender createAppPushSender(ChannelProviderConfigDO config);
}

View File

@@ -8,14 +8,16 @@ import com.njcn.msgpush.module.push.client.sender.impl.AliyunEmailSender;
import com.njcn.msgpush.module.push.client.sender.impl.AliyunSmsSender;
import com.njcn.msgpush.module.push.client.setting.impl.AliYunMailSetting;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
import lombok.extern.slf4j.Slf4j;
/**
* @author caozehui
* @data 2026-02-11
*/
@Slf4j
public class AliyunProviderFactory implements MessageProviderFactory {
@Override
public SmsSender createSmsSender(ChannelProviderConfigDO config) throws Exception {
public SmsSender createSmsSender(ChannelProviderConfigDO config) {
AliYunMailSetting aliYunSmsSetting = AliYunMailSetting.builder()
.accessKeyId(config.getAppKey())
.accessKeySecret(config.getAppSecret())
@@ -38,7 +40,8 @@ public class AliyunProviderFactory implements MessageProviderFactory {
}
@Override
public AppPushSender createAppPushSender() {
public AppPushSender createAppPushSender(ChannelProviderConfigDO config) {
log.error("阿里云暂不支持app推送");
return null;
}
}

View File

@@ -8,11 +8,13 @@ import com.njcn.msgpush.module.push.client.sender.impl.TelecomSmsSender;
import com.njcn.msgpush.module.push.client.setting.impl.TelecomSmsSetting;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
import com.njcn.msgpush.module.push.util.RestTemplateUtil;
import lombok.extern.slf4j.Slf4j;
/**
* @author caozehui
* @data 2026-02-11
*/
@Slf4j
public class TelecomProviderFactory implements MessageProviderFactory {
private RestTemplateUtil restTemplateUtil;
@@ -21,7 +23,7 @@ public class TelecomProviderFactory implements MessageProviderFactory {
}
@Override
public SmsSender createSmsSender(ChannelProviderConfigDO config) throws Exception {
public SmsSender createSmsSender(ChannelProviderConfigDO config) {
TelecomSmsSetting telecomSmsSetting = TelecomSmsSetting.builder()
.account(config.getAppKey())
.password(config.getAppSecret())
@@ -35,7 +37,8 @@ public class TelecomProviderFactory implements MessageProviderFactory {
}
@Override
public AppPushSender createAppPushSender() {
public AppPushSender createAppPushSender(ChannelProviderConfigDO config) {
log.error("电信暂不支持app推送");
return null;
}
}

View File

@@ -5,24 +5,29 @@ import com.njcn.msgpush.module.push.client.sender.AppPushSender;
import com.njcn.msgpush.module.push.client.sender.EmailSender;
import com.njcn.msgpush.module.push.client.sender.SmsSender;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
import lombok.extern.slf4j.Slf4j;
/**
* @author caozehui
* @data 2026-02-11
*/
@Slf4j
public class UniPushProviderFactory implements MessageProviderFactory {
@Override
public SmsSender createSmsSender(ChannelProviderConfigDO config) throws Exception {
public SmsSender createSmsSender(ChannelProviderConfigDO config) {
log.error("uniPush暂不支持短信推送");
return null;
}
@Override
public EmailSender createEmailSender(ChannelProviderConfigDO config) throws Exception {
log.error("uniPush暂不支持email推送");
return null;
}
@Override
public AppPushSender createAppPushSender() {
public AppPushSender createAppPushSender(ChannelProviderConfigDO config) {
log.error("阿里云暂不支持app推送");
return null;
}
}

View File

@@ -1,10 +1,12 @@
package com.njcn.msgpush.module.push.client.sender;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
/**
* @author caozehui
* @data 2026-02-11
*/
public interface AppPushSender {
boolean appPush();
boolean appPush(MessageRecordDO message);
}

View File

@@ -15,5 +15,5 @@ public interface EmailSender {
* @param toAddressList 接收地址集合
* @return 发送结果
*/
boolean sendEmail(Map<String, Object> params, List<String> toAddressList) throws Exception;
boolean sendEmail(Map<String, Object> params, List<String> toAddressList);
}

View File

@@ -1,5 +1,7 @@
package com.njcn.msgpush.module.push.client.sender;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import java.util.List;
import java.util.Map;
@@ -11,18 +13,16 @@ public interface SmsSender {
/**
* 向单个手机号发送短信
*
* @param phoneNumber 手机号
* @param params 参数
* @param message 消息
* @return 发送结果
*/
boolean sendSms(Map<String, Object> params, String phoneNumber) throws Exception;
boolean sendSms(MessageRecordDO message);
/**
* 向多个手机号发送短信
*
* @param phoneNumbers 手机号集合
* @param params 参数
* @param messageList 消息集合
* @return 发送结果
*/
boolean sendBatchSms(Map<String, Object> params, List<String> phoneNumbers);
boolean sendBatchSms(List<MessageRecordDO> messageList);
}

View File

@@ -63,7 +63,7 @@ public class AliyunEmailSender implements EmailSender {
}
@Override
public boolean sendEmail(Map<String, Object> params, List<String> toAddressList) throws Exception {
public boolean sendEmail(Map<String, Object> params, List<String> toAddressList) {
RuntimeOptions runtimeOptions = new RuntimeOptions();
runtimeOptions.autoretry = true;
SingleSendMailRequest request = new SingleSendMailRequest()
@@ -75,7 +75,11 @@ public class AliyunEmailSender implements EmailSender {
.setHtmlBody(params.get(HTML_BODY).toString())
.setTextBody(params.get(TEXT_BODY).toString());
SingleSendMailResponse response = this.emailClient.singleSendMailWithOptions(request, runtimeOptions);
try {
SingleSendMailResponse response = this.emailClient.singleSendMailWithOptions(request, runtimeOptions);
} catch (Exception e) {
throw new RuntimeException(e);
}
// if(OK.equals(response.)){
// return true;
// }else {

View File

@@ -2,18 +2,19 @@ package com.njcn.msgpush.module.push.client.sender.impl;
import cn.hutool.core.util.ObjectUtil;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendBatchSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendBatchSmsResponse;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.njcn.msgpush.module.push.client.sender.SmsSender;
import com.njcn.msgpush.module.push.client.setting.impl.AliYunMailSetting;
import com.njcn.msgpush.module.push.constant.MessageStatusConstant;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import lombok.extern.slf4j.Slf4j;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -41,14 +42,14 @@ public class AliyunSmsSender implements SmsSender {
new java.util.concurrent.ArrayBlockingQueue<>(1000),
r -> {
Thread thread = new Thread(r);
thread.setName("AliYunSmsClient-Pool-" + thread.getId());
thread.setName("AliyunSmsSender-Pool-" + thread.getId());
thread.setDaemon(false);
return thread;
},
new ThreadPoolExecutor.CallerRunsPolicy()
);
public AliyunSmsSender(AliYunMailSetting aliYunSmsSetting) throws Exception {
public AliyunSmsSender(AliYunMailSetting aliYunSmsSetting) {
if (ObjectUtil.isNotNull(aliYunSmsSetting)) {
Config config = new Config()
.setAccessKeyId(aliYunSmsSetting.getAccessKeyId())
@@ -60,27 +61,31 @@ public class AliyunSmsSender implements SmsSender {
this.smsClient = new Client(config);
} catch (Exception e) {
log.error("阿里云-短信服务初始化失败,请检查配置信息");
throw e;
throw new RuntimeException(e);
}
}
}
@Override
public boolean sendSms(Map<String, Object> params, String phoneNumber) throws Exception {
public boolean sendSms(MessageRecordDO message) {
Future<Boolean> future = THREAD_POOL_EXECUTOR.submit(() -> {
// todo 修改消息的状态为 sending
message.setStatus(MessageStatusConstant.SENDING);
RuntimeOptions runtimeOptions = new RuntimeOptions();
// 设置自动重试默认是不开启的。重试次数默认是3次
runtimeOptions.autoretry = true;
SendSmsRequest request = new SendSmsRequest()
.setPhoneNumbers(phoneNumber)
.setSignName(params.get(SIGN_NAME).toString())
.setTemplateCode(params.get(TEMPLATE_CODE).toString())
.setTemplateParam(params.get(TEMPLATE_PARAM).toString());
.setPhoneNumbers(message.getReceiver())
.setSignName(message.getTitle())
.setTemplateCode(message.getTemplateCode())
.setTemplateParam(message.getTemplateParams());
try {
LocalDateTime now = LocalDateTime.now();
long start = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
message.setSendTime(now);
SendSmsResponse response = this.smsClient.sendSmsWithOptions(request, runtimeOptions);
LocalDateTime end = LocalDateTime.now();
message.setCostTime((int) (end.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() - start));
System.out.println(toJSONString(response));
if (OK.equals(response.body.code)) {
return true;
@@ -92,36 +97,27 @@ public class AliyunSmsSender implements SmsSender {
throw new Exception(e);
}
});
Boolean b = future.get(3, TimeUnit.SECONDS);
Boolean b = null;
try {
b = future.get(3, TimeUnit.SECONDS);
} catch (Exception e) {
throw new RuntimeException(e);
}
if (b) {
// todo 修改消息的状态为 success
message.setStatus(MessageStatusConstant.SUCCESS);
} else {
// todo 修改消息的状态为 failed
message.setStatus(MessageStatusConstant.FAILED);
}
return b;
}
@Override
public boolean sendBatchSms(Map<String, Object> params, List<String> phoneNumbers) {
RuntimeOptions runtimeOptions = new RuntimeOptions();
// 设置自动重试默认是不开启的。重试次数默认是3次
runtimeOptions.autoretry = true;
SendBatchSmsRequest request = new SendBatchSmsRequest()
.setPhoneNumberJson(toJSONString(phoneNumbers))
.setSignNameJson(toJSONString(params.get(SIGN_NAME)))
.setTemplateCode(params.get(TEMPLATE_CODE).toString())
.setTemplateParamJson(toJSONString(params.get(TEMPLATE_PARAM)));
try {
SendBatchSmsResponse response = this.smsClient.sendBatchSmsWithOptions(request, runtimeOptions);
System.out.println(toJSONString(response));
if (OK.equals(response.body.code)) {
return true;
} else {
return false;
}
} catch (Exception e) {
log.error("阿里云-短信服务发送失败");
throw new RuntimeException(e);
public boolean sendBatchSms(List<MessageRecordDO> messageIdList) {
boolean res = true;
for (MessageRecordDO message : messageIdList) {
res &= this.sendSms(message);
}
return res;
}
}

View File

@@ -1,15 +1,22 @@
package com.njcn.msgpush.module.push.client.sender.impl;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.njcn.msgpush.module.push.client.sender.SmsSender;
import com.njcn.msgpush.module.push.client.setting.impl.TelecomSmsSetting;
import com.njcn.msgpush.module.push.constant.MessageStatusConstant;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import com.njcn.msgpush.module.push.util.RestTemplateUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author caozehui
@@ -29,12 +36,40 @@ public class TelecomSmsSender implements SmsSender {
*/
private static final String CONTENT_TYPE = "application/json;charset=utf-8";
public static final String CONTENT = "content";
private TelecomSmsSetting telecomSmsSetting;
private RestTemplateUtil restTemplateUtil;
private final ThreadPoolExecutor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
5,
5,
1000,
TimeUnit.MILLISECONDS,
new java.util.concurrent.ArrayBlockingQueue<>(1000),
r -> {
Thread thread = new Thread(r);
thread.setName("TelecomSmsSender-Pool-" + thread.getId());
thread.setDaemon(false);
return thread;
},
new ThreadPoolExecutor.CallerRunsPolicy()
);
private class TelecomSmsResponse {
private String status;
private Double balance;
private List<TelecomSmsMessageRes> list;
}
private class TelecomSmsMessageRes {
//消息ID用于状态报告匹配
private String mid;
//手机号码
private String mobile;
//短信提交错误代码
private Integer result;
}
public TelecomSmsSender(TelecomSmsSetting telecomSmsSetting, RestTemplateUtil restTemplateUtil) {
this.telecomSmsSetting = telecomSmsSetting;
@@ -42,25 +77,79 @@ public class TelecomSmsSender implements SmsSender {
}
@Override
public boolean sendSms(Map<String, Object> params, String phoneNumber) throws Exception {
return this.sendBatchSms(params, List.of(phoneNumber));
public boolean sendSms(MessageRecordDO message) {
Future<Boolean> future = THREAD_POOL_EXECUTOR.submit(() -> {
message.setStatus(MessageStatusConstant.SENDING);
// 构建请求参数
Map<String, Object> request = new HashMap<>();
request.put("action", "send");
request.put("account", telecomSmsSetting.getAccount());
request.put("password", telecomSmsSetting.getPassword());
request.put("mobile", message.getReceiver());
request.put("content", message.getContent());
request.put("extno", ACCESS_CODE);
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", CONTENT_TYPE);
LocalDateTime now = LocalDateTime.now();
long start = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
message.setSendTime(now);
// 发送请求
ResponseEntity<String> response = restTemplateUtil.post(
API_URL,
request,
headers,
String.class
);
LocalDateTime end = LocalDateTime.now();
message.setCostTime((int) (end.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() - start));
TelecomSmsResponse telecomSmsResponse = JSON.parseObject(response.getBody(), TelecomSmsResponse.class);
if (telecomSmsResponse.list.get(0).result == 0) {
return true;
} else {
return false;
}
});
Boolean b = null;
try {
b = future.get(3, TimeUnit.SECONDS);
} catch (Exception e) {
throw new RuntimeException(e);
}
if (b) {
message.setStatus(MessageStatusConstant.SUCCESS);
} else {
message.setStatus(MessageStatusConstant.FAILED);
}
return b;
}
@Override
public boolean sendBatchSms(Map<String, Object> params, List<String> phoneNumbers) {
// 构建请求参数
public boolean sendBatchSms(List<MessageRecordDO> messageList) {
Map<String, Object> request = new HashMap<>();
request.put("action", "send");
request.put("action", "p2p");
request.put("account", telecomSmsSetting.getAccount());
request.put("password", telecomSmsSetting.getPassword());
request.put("mobile", StrUtil.join(StrUtil.COMMA, phoneNumbers));
request.put("content", params.get(CONTENT).toString());
Map<String, String> mobileContentKvp = new HashMap<>();
for (MessageRecordDO message : messageList) {
mobileContentKvp.put(message.getReceiver(), "" + message.getTitle() + "" + message.getContent());
message.setStatus(MessageStatusConstant.SENDING);
}
request.put("mobileContentKvp", JSON.toJSONString(mobileContentKvp));
request.put("extno", ACCESS_CODE);
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", CONTENT_TYPE);
LocalDateTime now = LocalDateTime.now();
long start = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
// 发送请求
ResponseEntity<String> response = restTemplateUtil.post(
API_URL,
@@ -68,12 +157,16 @@ public class TelecomSmsSender implements SmsSender {
headers,
String.class
);
String body = response.getBody();
if (body.contains("\"status\": 0")) {
return true;
} else {
return false;
LocalDateTime end = LocalDateTime.now();
for (MessageRecordDO message : messageList) {
message.setSendTime(now);
message.setCostTime((int) (end.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() - start));
}
TelecomSmsResponse telecomSmsResponse = JSON.parseObject(response.getBody(), TelecomSmsResponse.class);
boolean res = true;
for (TelecomSmsMessageRes telecomSmsMessageRes : telecomSmsResponse.list) {
res &= telecomSmsMessageRes.result == 0;
}
return res;
}
}

View File

@@ -0,0 +1,27 @@
package com.njcn.msgpush.module.push.client.sender.impl;
import com.njcn.msgpush.module.push.client.sender.AppPushSender;
import com.njcn.msgpush.module.push.client.setting.impl.UniPushAppPushSetting;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import com.njcn.msgpush.module.push.util.RestTemplateUtil;
/**
* @author caozehui
* @data 2026-02-26
*/
public class UniPushEmailSender implements AppPushSender {
private UniPushAppPushSetting uniPushAppPushSetting;
private RestTemplateUtil restTemplateUtil;
public UniPushEmailSender(UniPushAppPushSetting uniPushAppPushSetting, RestTemplateUtil restTemplateUtil) {
this.uniPushAppPushSetting = uniPushAppPushSetting;
this.restTemplateUtil = restTemplateUtil;
}
@Override
public boolean appPush(MessageRecordDO message) {
return false;
}
}

View File

@@ -12,6 +12,8 @@ import lombok.*;
@Builder
@EqualsAndHashCode(callSuper = true)
public class UniPushAppPushSetting extends AppPushSetting {
private String accessKeyId;
private String accessKeySecret;
private String appId;
private String appKey;
private String appSecret;
private String masterSecret;
}

View File

@@ -0,0 +1,27 @@
package com.njcn.msgpush.module.push.constant;
/**
* @author caozehui
* @data 2026-02-26
*/
public class MessageStatusConstant {
//待发送
public static final String PENDING = "pending";
//发送中
public static final String SENDING = "sending";
//发送成功
public static final String SUCCESS = "success";
//发送失败(可重试)
public static final String FAILED = "failed";
//最终失败(超过最大重试次数,系统自动判定)
public static final String FINALFAILED = "final_failed";
//黑名单拦截
public static final String BLACKLISTED = "blacklisted";
//配额超限
public static final String QUOTAEXCEEDED = "quota_exceeded";
//频率限制
public static final String RATE_LIMITED = "rate_limited";
//手动终止重试(运维在重试队列管理中主动终止区别于系统自动判定的final_failed)
public static final String ABANDONED = "abandoned";
}

View File

@@ -5,7 +5,11 @@ package com.njcn.msgpush.module.push.constant;
* @data 2026-02-11
*/
public class MsgPushConstant {
public static final String ALI_YUN = "aliyun";
public static final String TELECOM = "telecom";
public static final String UNI_PUSH = "UniPush";
public static final String PROVIDER_TYPE_ALI_YUN = "aliyun";
public static final String PROVIDER_TYPE_TELECOM = "telecom";
public static final String PROVIDER_TYPE_UNI_PUSH = "UniPush";
public static final String CHANNEL_SMS = "sms";
public static final String CHANNEL_EMAIL = "email";
public static final String CHANNEL_APP_PUSH = "app_push";
}

View File

@@ -3,6 +3,7 @@ package com.njcn.msgpush.module.push.controller.admin.channel;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.module.push.client.factory.MessageProviderFactory;
import com.njcn.msgpush.module.push.controller.admin.channel.vo.ChannelProviderConfigReqVO;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
import com.njcn.msgpush.module.push.service.channel.ChannelProviderConfigService;
@@ -10,11 +11,13 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@Tag(name = "管理后台 - 渠道服务商")
@Slf4j
@@ -26,6 +29,10 @@ public class ChannelProviderConfigController {
@Autowired
private ChannelProviderConfigService channelProviderConfigService;
@Autowired
@Qualifier("messageProviderFactoryMap")
private Map<String, MessageProviderFactory> messageProviderFactoryMap;
@PostMapping("/list")
@Operation(summary = "分页查询渠道服务商列表")
@@ -35,7 +42,7 @@ public class ChannelProviderConfigController {
return CommonResult.success(res);
}
@PostMapping("add")
@PostMapping("/add")
@Operation(summary = "新增渠道服务商")
@PreAuthorize("@ss.hasPermission('push:channel:add')")
public CommonResult<Boolean> addChannelProvider(@Validated @RequestBody ChannelProviderConfigReqVO reqVO) {
@@ -43,7 +50,7 @@ public class ChannelProviderConfigController {
return CommonResult.success(res);
}
@PostMapping("update")
@PostMapping("/update")
@Operation(summary = "更新渠道服务商")
@PreAuthorize("@ss.hasPermission('push:channel:update')")
public CommonResult<Boolean> updateChannelProvider(@Validated @RequestBody ChannelProviderConfigReqVO reqVO) {
@@ -51,7 +58,7 @@ public class ChannelProviderConfigController {
return CommonResult.success(res);
}
@PostMapping("delete")
@PostMapping("/delete")
@Operation(summary = "删除渠道服务商")
@PreAuthorize("@ss.hasPermission('push:channel:delete')")
public CommonResult<Boolean> deleteChannelProvider(@RequestBody List<String> ids) {
@@ -59,11 +66,39 @@ public class ChannelProviderConfigController {
return CommonResult.success(res);
}
@GetMapping("toggle")
@GetMapping("/toggle")
@Operation(summary = "启用/禁用渠道服务商")
@PreAuthorize("@ss.hasPermission('push:channel:toggle')")
public CommonResult<Boolean> toggleEnableChannelProvider(@RequestParam("id") String id) {
boolean res = channelProviderConfigService.toggleEnableField(id);
return CommonResult.success(res);
}
/**
* 添加指定providerType服务商对应的bean
*
* @param providerType 服务商类型例如aliyun\telecom\UniPush
*/
public void registerProviderBean(String providerType) {
// DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory();
// BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass);
// for (Object arg : args) {
// builder.addConstructorArgValue(arg);
// }
// beanFactory.registerBeanDefinition(beanName, builder.getBeanDefinition());
}
/**
* 移除指定providerType服务商对应的bean
*
* @param providerType 服务商类型例如aliyun\telecom\UniPush
*/
public void removeProviderBean(String providerType) {
// DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory();
// if (beanFactory.containsBeanDefinition(beanName)) {
// beanFactory.removeBeanDefinition(beanName);
// }
messageProviderFactoryMap.remove(providerType);
}
}

View File

@@ -19,4 +19,13 @@ public interface ChannelProviderConfigService extends IService<ChannelProviderCo
* @return
*/
boolean toggleEnableField(String id);
/**
* 根据类型和渠道获取服务提供商
*
* @param providerType 服务提供商类型
* @param channel 渠道
* @return
*/
ChannelProviderConfigDO getByTypeAndChannel(String providerType, String channel);
}

View File

@@ -7,18 +7,12 @@ import com.njcn.msgpush.framework.common.util.object.PageUtils;
import com.njcn.msgpush.module.push.controller.admin.channel.vo.ChannelProviderConfigReqVO;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
import com.njcn.msgpush.module.push.dal.mysql.channel.ChannelProviderConfigMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ChannelProviderConfigServiceImpl extends ServiceImpl<ChannelProviderConfigMapper, ChannelProviderConfigDO> implements ChannelProviderConfigService {
@Autowired
private ConfigurableApplicationContext applicationContext;
@Override
public Page<ChannelProviderConfigDO> listChannelProviderCfg(ChannelProviderConfigReqVO pageReqVO) {
@@ -44,19 +38,10 @@ public class ChannelProviderConfigServiceImpl extends ServiceImpl<ChannelProvide
return false;
}
public void registerBean(String beanName, Class<?> beanClass, Object... args) {
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory();
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass);
for (Object arg : args) {
builder.addConstructorArgValue(arg);
}
beanFactory.registerBeanDefinition(beanName, builder.getBeanDefinition());
}
public void removeBean(String beanName) {
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory();
if (beanFactory.containsBeanDefinition(beanName)) {
beanFactory.removeBeanDefinition(beanName);
}
@Override
public ChannelProviderConfigDO getByTypeAndChannel(String providerType, String channel) {
return this.lambdaQuery().eq(ChannelProviderConfigDO::getProviderType, providerType)
.eq(ChannelProviderConfigDO::getChannel, channel)
.one();
}
}

View File

@@ -11,4 +11,12 @@ public interface MessageRecordService {
* @return 发送是否成功的结果
*/
Boolean send(MessageRecordSendReqVO messageRecordSendReqVO);
/**
* 添加消息记录
*
* @param messageRecordSendReqVO
* @return
*/
Boolean add(MessageRecordSendReqVO messageRecordSendReqVO);
}

View File

@@ -1,13 +1,55 @@
package com.njcn.msgpush.module.push.service.message;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.msgpush.module.push.client.factory.MessageProviderFactory;
import com.njcn.msgpush.module.push.constant.MessageStatusConstant;
import com.njcn.msgpush.module.push.constant.MsgPushConstant;
import com.njcn.msgpush.module.push.controller.admin.message.vo.MessageRecordSendReqVO;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import com.njcn.msgpush.module.push.dal.mysql.message.MessageRecordMapper;
import com.njcn.msgpush.module.push.service.channel.ChannelProviderConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.util.Map;
@Service
public class MessageRecordServiceImpl implements MessageRecordService{
public class MessageRecordServiceImpl extends ServiceImpl<MessageRecordMapper, MessageRecordDO> implements MessageRecordService {
@Autowired
@Qualifier("messageProviderFactoryMap")
private Map<String, MessageProviderFactory> messageProviderFactoryMap;
@Autowired
private ChannelProviderConfigService channelProviderConfigService;
@Override
public Boolean send(MessageRecordSendReqVO messageRecordSendReqVO) {
MessageRecordDO messageRecordDO = BeanUtil.copyProperties(messageRecordSendReqVO, MessageRecordDO.class);
messageRecordDO.setStatus(MessageStatusConstant.PENDING);
this.save(messageRecordDO);
ChannelProviderConfigDO channelProviderConfigDO = channelProviderConfigService.getByTypeAndChannel(messageRecordDO.getProviderType(), messageRecordDO.getChannel());
//channelProviderConfigDO.setAppKey("LTAI4FxsR76x2dq3w9c5puUe");
//channelProviderConfigDO.setAppSecret("GxkTR8fsrvHtixTlD9UPmOGli35tZs");
MessageProviderFactory messageProviderFactory = messageProviderFactoryMap.get(messageRecordDO.getProviderType());
boolean sendResult = switch (messageRecordDO.getChannel()) {
case MsgPushConstant.CHANNEL_SMS -> messageProviderFactory.createSmsSender(channelProviderConfigDO).sendSms(messageRecordDO);
//case MsgPushConstant.CHANNEL_EMAIL ->
//messageProviderFactory.createEmailSender(channelProviderConfigDO).sendEmail(messageRecordDO.getTemplateParams(), messageRecordDO.getReceiver());
case MsgPushConstant.CHANNEL_APP_PUSH -> messageProviderFactory.createAppPushSender(channelProviderConfigDO).appPush(messageRecordDO);
default -> throw new RuntimeException("暂不支持该渠道:" + messageRecordDO.getChannel());
};
return sendResult;
}
@Override
public Boolean add(MessageRecordSendReqVO messageRecordSendReqVO) {
return null;
}
}

View File

@@ -5,11 +5,13 @@ import com.njcn.msgpush.module.push.client.sender.SmsSender;
import com.njcn.msgpush.module.push.client.sender.impl.AliyunSmsSender;
import com.njcn.msgpush.module.push.constant.MsgPushConstant;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -27,17 +29,21 @@ public class MsgPushClientTest {
@Test
public void testSendSms() throws Exception {
Map<String, Object> params = new HashMap<>();
params.put(AliyunSmsSender.SIGN_NAME, "灿能云");
params.put(AliyunSmsSender.TEMPLATE_CODE, "SMS_481710295");
params.put(AliyunSmsSender.TEMPLATE_PARAM, "{\"code\":\"123456\"}");
ChannelProviderConfigDO channelProviderConfigDO = new ChannelProviderConfigDO();
channelProviderConfigDO.setAppKey("LTAI4FxsR76x2dq3w9c5puUe");
channelProviderConfigDO.setAppSecret("GxkTR8fsrvHtixTlD9UPmOGli35tZs");
SmsSender smsSender = messageProviderFactoryMap.get(MsgPushConstant.ALI_YUN).createSmsSender(channelProviderConfigDO);
SmsSender smsSender = messageProviderFactoryMap.get(MsgPushConstant.PROVIDER_TYPE_ALI_YUN).createSmsSender(channelProviderConfigDO);
boolean b = smsSender.sendSms(params, "18839431215");
MessageRecordDO message = new MessageRecordDO();
message.setMessageId("1c2w1e2a3c456");
message.setChannel(MsgPushConstant.CHANNEL_SMS);
message.setTitle("灿能云");
message.setReceiver("18839431215");
message.setTemplateCode("SMS_481710295");
message.setTemplateParams("{\"code\":\"123456\"}");
message.setProviderType(MsgPushConstant.PROVIDER_TYPE_ALI_YUN);
boolean b = smsSender.sendSms(message);
System.out.println(System.currentTimeMillis() + " " + b);
}
@@ -48,12 +54,25 @@ public class MsgPushClientTest {
params.put(AliyunSmsSender.TEMPLATE_CODE, "SMS_481710295");
params.put(AliyunSmsSender.TEMPLATE_PARAM, List.of("{\"code\":\"123456\"}"));
List<MessageRecordDO> messageIdList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
MessageRecordDO message = new MessageRecordDO();
message.setMessageId(i + "c518e2a3c");
message.setChannel(MsgPushConstant.CHANNEL_SMS);
message.setTitle("灿能云");
message.setReceiver("18839431215");
message.setTemplateCode("SMS_481710295");
message.setTemplateParams("{\"code\":\"65432" + i + "\"}");
message.setProviderType(MsgPushConstant.PROVIDER_TYPE_ALI_YUN);
messageIdList.add(message);
}
ChannelProviderConfigDO channelProviderConfigDO = new ChannelProviderConfigDO();
channelProviderConfigDO.setAppKey("LTAI4FxsR76x2dq3w9c5puUe");
channelProviderConfigDO.setAppSecret("GxkTR8fsrvHtixTlD9UPmOGli35tZs");
SmsSender smsSender = messageProviderFactoryMap.get(MsgPushConstant.ALI_YUN).createSmsSender(channelProviderConfigDO);
SmsSender smsSender = messageProviderFactoryMap.get(MsgPushConstant.PROVIDER_TYPE_ALI_YUN).createSmsSender(channelProviderConfigDO);
boolean b = smsSender.sendBatchSms(params, List.of("18839431215"));
boolean b = smsSender.sendBatchSms(messageIdList);
System.out.println(System.currentTimeMillis() + " " + b);
}
}