This commit is contained in:
caozehui
2026-02-11 16:17:13 +08:00
parent 1219b30f43
commit fac4a39214
40 changed files with 620 additions and 446 deletions

View File

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.func.Func1;
import cn.hutool.core.lang.func.LambdaUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.njcn.msgpush.framework.common.pojo.PageParam;
import com.njcn.msgpush.framework.common.pojo.SortablePageParam;
import com.njcn.msgpush.framework.common.pojo.SortingField;
@@ -64,4 +65,12 @@ public class PageUtils {
}
}
public static Integer getPageNum(PageParam pageParam) {
return !ObjectUtil.isNull(pageParam.getPageNo()) && pageParam.getPageNo() != 0 ? pageParam.getPageNo() : 1;
}
public static Integer getPageSize(PageParam pageParam) {
return !ObjectUtil.isNull(pageParam.getPageSize()) && pageParam.getPageSize() != 0 ? pageParam.getPageSize() : 10;
}
}

View File

@@ -0,0 +1,63 @@
package com.njcn.msgpush.module.push.client;
import com.njcn.msgpush.module.push.client.factory.MessageProviderFactory;
import com.njcn.msgpush.module.push.client.factory.impl.AliyunProviderFactory;
import com.njcn.msgpush.module.push.constant.MsgPushConstant;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
import com.njcn.msgpush.module.push.service.channel.ChannelProviderConfigService;
import com.njcn.msgpush.module.push.util.RestTemplateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author caozehui
* @data 2026-02-10
*/
@Configuration
public class ClientConfiguration {
@Autowired
private RestTemplateUtil restTemplateUtil;
@Autowired
private ChannelProviderConfigService channelProviderConfigService;
@Bean
public Map<String, MessageProviderFactory> messageProviderFactoryMap() throws Exception {
List<ChannelProviderConfigDO> activeProviders = channelProviderConfigService.getActiveProviders();
Map<String, MessageProviderFactory> messageProviderFactoryMap = new HashMap<>();
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);
}
break;
case MsgPushConstant.TELECOM: {
MessageProviderFactory orDefault = messageProviderFactoryMap.getOrDefault(MsgPushConstant.TELECOM, new AliyunProviderFactory());
messageProviderFactoryMap.put(MsgPushConstant.TELECOM, orDefault);
}
break;
case MsgPushConstant.UNI_PUSH: {
MessageProviderFactory orDefault = messageProviderFactoryMap.getOrDefault(MsgPushConstant.UNI_PUSH, new AliyunProviderFactory());
messageProviderFactoryMap.put(MsgPushConstant.UNI_PUSH, orDefault);
}
break;
default:
throw new IllegalArgumentException("" + config.getProviderType() + "服务商暂不支持");
}
}
if (messageProviderFactoryMap.isEmpty()) {
throw new Exception("当前没有激活的渠道服务商!");
}
return messageProviderFactoryMap;
}
}

View File

@@ -1,8 +0,0 @@
package com.njcn.msgpush.module.push.client.channel.appPush;
/**
* @author caozehui
* @data 2026-02-11
*/
public interface AppPushClient {
}

View File

@@ -1,8 +0,0 @@
package com.njcn.msgpush.module.push.client.channel.appPush.factory;
/**
* @author caozehui
* @data 2026-02-11
*/
public class AppPushFactory {
}

View File

@@ -1,15 +0,0 @@
package com.njcn.msgpush.module.push.client.channel.mail;
import java.util.List;
import java.util.Map;
/**
* @author caozehui
* @data 2026-02-11
*/
public interface MailClient {
void sendMail(String accountName, Integer addressType, Boolean replyToAddress, String toAddress, String subject, String htmlBody);
void queryMailAddressByParam();
}

View File

@@ -1,27 +0,0 @@
package com.njcn.msgpush.module.push.client.channel.mail.factory;
import cn.hutool.core.util.StrUtil;
import com.njcn.msgpush.module.push.client.channel.mail.MailClient;
import com.njcn.msgpush.module.push.client.channel.mail.impl.AliYunMailClient;
import com.njcn.msgpush.module.push.client.constant.ClientConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author caozehui
* @data 2026-02-11
*/
@Component
public class MailFactory {
@Autowired
private AliYunMailClient aliYunMailClient;
public MailClient getClient(String mailProviderTypeName) throws RuntimeException {
if (StrUtil.equals(ClientConstant.ALI_YUN, mailProviderTypeName)) {
return aliYunMailClient;
} else {
throw new RuntimeException("暂时不提供" + mailProviderTypeName + "邮件服务提供商");
}
}
}

View File

@@ -1,86 +0,0 @@
package com.njcn.msgpush.module.push.client.channel.mail.impl;
import com.alibaba.fastjson.JSON;
import com.aliyun.dm20151123.Client;
import com.aliyun.dm20151123.models.QueryMailAddressByParamRequest;
import com.aliyun.dm20151123.models.QueryMailAddressByParamResponse;
import com.aliyun.dm20151123.models.SingleSendMailRequest;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.njcn.msgpush.module.push.client.channel.mail.MailClient;
import com.njcn.msgpush.module.push.client.setting.mail.AliYunMailSetting;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
/**
* @author caozehui
* @data 2026-02-11
*/
@Slf4j
@Service
public class AliYunMailClient implements MailClient {
private static final String ACCOUNT_NAME = "accountName";
private static final Integer ADDRESS_TYPE = 0;
private static final String REPLY_TO_ADDRESS = "replyToAddress";
private static final String HTML_BODY = "htmlBody";
private static final String TEXT_BODY = "textBody";
private static final String TO_ADDRESS = "toAddress";
private static final String SUBJECT = "subject";
private static final String CLICK_TRACE = "1";
@Autowired
private AliYunMailSetting aliYunMailSetting;
private Client client;
@PostConstruct
public void init() {
Config config = new Config()
.setAccessKeyId(aliYunMailSetting.getAccessKeyId())
.setAccessKeySecret(aliYunMailSetting.getAccessKeySecret())
.setRegionId(aliYunMailSetting.getRegionId())
.setEndpoint(aliYunMailSetting.getEndpoint());
try {
this.client = new Client(config);
} catch (Exception e) {
log.error("阿里云-邮件服务初始化失败,请检查配置信息");
throw new RuntimeException(e);
}
}
@Override
public void sendMail(String accountName, Integer addressType, Boolean replyToAddress, String toAddress, String subject, String htmlBody) {
RuntimeOptions runtimeOptions = new RuntimeOptions();
// 设置自动重试默认是不开启的。重试次数默认是3次
runtimeOptions.autoretry = true;
SingleSendMailRequest request = new SingleSendMailRequest()
.setAccountName(accountName)
.setAddressType(addressType)
.setReplyToAddress(replyToAddress)
.setToAddress(toAddress)
.setSubject(subject)
.setHtmlBody(htmlBody);
try {
client.singleSendMailWithOptions(request, runtimeOptions);
} catch (Exception e) {
throw new RuntimeException("阿里云-邮件服务发送失败");
}
}
@Override
public void queryMailAddressByParam() {
QueryMailAddressByParamRequest queryMailAddressByParamRequest = null;
try {
queryMailAddressByParamRequest = QueryMailAddressByParamRequest.build(new HashMap<>());
QueryMailAddressByParamResponse response = client.queryMailAddressByParam(queryMailAddressByParamRequest);
System.out.println(JSON.toJSON(response));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -1,33 +0,0 @@
package com.njcn.msgpush.module.push.client.channel.sms.factory;
import cn.hutool.core.util.StrUtil;
import com.njcn.msgpush.module.push.client.channel.sms.Impl.AliYunSmsClient;
import com.njcn.msgpush.module.push.client.channel.sms.Impl.TelecomSmsClient;
import com.njcn.msgpush.module.push.client.channel.sms.SmsClient;
import com.njcn.msgpush.module.push.client.constant.ClientConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author caozehui
* @data 2026-02-11
*/
@Component
public class SmsFactory {
@Autowired
private AliYunSmsClient aliYunSmsClient;
@Autowired
private TelecomSmsClient telecomSmsClient;
public SmsClient getClient(String smsProviderTypeName) throws RuntimeException {
if (StrUtil.equals(ClientConstant.ALI_YUN, smsProviderTypeName)) {
return aliYunSmsClient;
} else if (StrUtil.equals(ClientConstant.TELECOM, smsProviderTypeName)) {
return telecomSmsClient;
} else {
throw new RuntimeException("暂时不提供" + smsProviderTypeName + "短信服务提供商");
}
}
}

View File

@@ -1,11 +0,0 @@
package com.njcn.msgpush.module.push.client.constant;
/**
* @author caozehui
* @data 2026-02-10
*/
public interface ClientConstant {
String ALI_YUN = "阿里云";
String TELECOM = "电信";
}

View File

@@ -0,0 +1,27 @@
package com.njcn.msgpush.module.push.client.factory;
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;
/**
* @author caozehui
* @data 2026-02-11
*/
public interface MessageProviderFactory {
/**
* 创建短信发送器
*/
SmsSender createSmsSender(ChannelProviderConfigDO config) throws Exception;
/**
* 创建邮件发送器
*/
EmailSender createEmailSender(ChannelProviderConfigDO config) throws Exception;
/**
* 创建APP推送发送器
*/
AppPushSender createAppPushSender();
}

View File

@@ -0,0 +1,44 @@
package com.njcn.msgpush.module.push.client.factory.impl;
import com.njcn.msgpush.module.push.client.factory.MessageProviderFactory;
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.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;
/**
* @author caozehui
* @data 2026-02-11
*/
public class AliyunProviderFactory implements MessageProviderFactory {
@Override
public SmsSender createSmsSender(ChannelProviderConfigDO config) throws Exception {
AliYunMailSetting aliYunSmsSetting = AliYunMailSetting.builder()
.accessKeyId(config.getAppKey())
.accessKeySecret(config.getAppSecret())
.regionId("cn-hangzhou")
.endpoint("dysmsapi.aliyuncs.com")
.build();
return new AliyunSmsSender(aliYunSmsSetting);
}
@Override
public EmailSender createEmailSender(ChannelProviderConfigDO config) throws Exception {
AliYunMailSetting aliYunSmsSetting = AliYunMailSetting.builder()
.accessKeyId(config.getAppKey())
.accessKeySecret(config.getAppSecret())
.regionId("cn-hangzhou")
.endpoint("dm.aliyuncs.com")
.build();
return new AliyunEmailSender(aliYunSmsSetting);
}
@Override
public AppPushSender createAppPushSender() {
return null;
}
}

View File

@@ -0,0 +1,41 @@
package com.njcn.msgpush.module.push.client.factory.impl;
import com.njcn.msgpush.module.push.client.factory.MessageProviderFactory;
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.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;
/**
* @author caozehui
* @data 2026-02-11
*/
public class TelecomProviderFactory implements MessageProviderFactory {
private RestTemplateUtil restTemplateUtil;
public TelecomProviderFactory(RestTemplateUtil restTemplateUtil) {
this.restTemplateUtil = restTemplateUtil;
}
@Override
public SmsSender createSmsSender(ChannelProviderConfigDO config) throws Exception {
TelecomSmsSetting telecomSmsSetting = TelecomSmsSetting.builder()
.account(config.getAppKey())
.password(config.getAppSecret())
.build();
return new TelecomSmsSender(telecomSmsSetting, restTemplateUtil);
}
@Override
public EmailSender createEmailSender(ChannelProviderConfigDO config) throws Exception {
return null;
}
@Override
public AppPushSender createAppPushSender() {
return null;
}
}

View File

@@ -0,0 +1,28 @@
package com.njcn.msgpush.module.push.client.factory.impl;
import com.njcn.msgpush.module.push.client.factory.MessageProviderFactory;
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;
/**
* @author caozehui
* @data 2026-02-11
*/
public class UniPushProviderFactory implements MessageProviderFactory {
@Override
public SmsSender createSmsSender(ChannelProviderConfigDO config) throws Exception {
return null;
}
@Override
public EmailSender createEmailSender(ChannelProviderConfigDO config) throws Exception {
return null;
}
@Override
public AppPushSender createAppPushSender() {
return null;
}
}

View File

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

View File

@@ -0,0 +1,19 @@
package com.njcn.msgpush.module.push.client.sender;
import java.util.List;
import java.util.Map;
/**
* @author caozehui
* @data 2026-02-11
*/
public interface EmailSender {
/**
* 发送邮件
*
* @param params 参数
* @param toAddressList 接收地址集合
* @return 发送结果
*/
boolean sendEmail(Map<String, Object> params, List<String> toAddressList) throws Exception;
}

View File

@@ -1,14 +1,13 @@
package com.njcn.msgpush.module.push.client.channel.sms;
package com.njcn.msgpush.module.push.client.sender;
import java.util.List;
import java.util.Map;
/**
* @author caozehui
* @data 2026-02-10
* @data 2026-02-11
*/
public interface SmsClient {
public interface SmsSender {
/**
* 向单个手机号发送短信
*
@@ -26,6 +25,4 @@ public interface SmsClient {
* @return 发送结果
*/
boolean sendBatchSms(Map<String, Object> params, List<String> phoneNumbers);
void querySmsTemplateList();
}

View File

@@ -0,0 +1,87 @@
package com.njcn.msgpush.module.push.client.sender.impl;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyun.dm20151123.Client;
import com.aliyun.dm20151123.models.SingleSendMailRequest;
import com.aliyun.dm20151123.models.SingleSendMailResponse;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.njcn.msgpush.module.push.client.sender.EmailSender;
import com.njcn.msgpush.module.push.client.setting.impl.AliYunMailSetting;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author caozehui
* @data 2026-02-11
*/
@Slf4j
public class AliyunEmailSender implements EmailSender {
public static final String ACCOUNT_NAME = "accountName";
public static final String REPLY_TO_ADDRESS = "replyToAddress";
public static final String SUBJECT = "subject";
public static final String HTML_BODY = "htmlBody";
public static final String TEXT_BODY = "textBody";
private Client emailClient;
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("AliYunSmsClient-Pool-" + thread.getId());
thread.setDaemon(false);
return thread;
},
new ThreadPoolExecutor.CallerRunsPolicy()
);
public AliyunEmailSender(AliYunMailSetting aliYunMailSetting) throws Exception {
if (ObjectUtil.isNotNull(aliYunMailSetting)) {
Config config = new Config()
.setAccessKeyId(aliYunMailSetting.getAccessKeyId())
.setAccessKeySecret(aliYunMailSetting.getAccessKeySecret())
.setRegionId(aliYunMailSetting.getRegionId())
.setEndpoint(aliYunMailSetting.getEndpoint());
try {
this.emailClient = new com.aliyun.dm20151123.Client(config);
} catch (Exception e) {
log.error("阿里云-邮件服务初始化失败,请检查配置信息");
throw e;
}
}
}
@Override
public boolean sendEmail(Map<String, Object> params, List<String> toAddressList) throws Exception {
RuntimeOptions runtimeOptions = new RuntimeOptions();
runtimeOptions.autoretry = true;
SingleSendMailRequest request = new SingleSendMailRequest()
.setAccountName(params.get(ACCOUNT_NAME).toString())
.setAddressType(1)
.setReplyToAddress((boolean) params.get(REPLY_TO_ADDRESS))
.setToAddress(StrUtil.join(StrUtil.COMMA, toAddressList))
.setSubject(params.get(SUBJECT).toString())
.setHtmlBody(params.get(HTML_BODY).toString())
.setTextBody(params.get(TEXT_BODY).toString());
SingleSendMailResponse response = this.emailClient.singleSendMailWithOptions(request, runtimeOptions);
// if(OK.equals(response.)){
// return true;
// }else {
// return false;
// }
return false;
}
}

View File

@@ -1,15 +1,16 @@
package com.njcn.msgpush.module.push.client.channel.sms.Impl;
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.*;
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.channel.sms.SmsClient;
import com.njcn.msgpush.module.push.client.setting.sms.AliYunSmsSetting;
import jakarta.annotation.PostConstruct;
import com.njcn.msgpush.module.push.client.sender.SmsSender;
import com.njcn.msgpush.module.push.client.setting.impl.AliYunMailSetting;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@@ -19,27 +20,20 @@ import java.util.concurrent.TimeUnit;
import static com.aliyun.teautil.Common.toJSONString;
/**
* @author caozehui
* @data 2026-02-11
* @description 阿里云短信服务实现
*/
@Slf4j
@Service
public class AliYunSmsClient implements SmsClient {
public class AliyunSmsSender implements SmsSender {
public static final String SIGN_NAME = "signName";
public static final String TEMPLATE_CODE = "templateCode";
public static final String TEMPLATE_PARAM = "templateParam";
public static final String OK = "OK";
private Client smsClient;
@Autowired
private AliYunSmsSetting aliYunSmsSetting;
private Client client;
private static final ThreadPoolExecutor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
private final ThreadPoolExecutor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
5,
5,
1000,
@@ -54,22 +48,24 @@ public class AliYunSmsClient implements SmsClient {
new ThreadPoolExecutor.CallerRunsPolicy()
);
@PostConstruct
public void init() {
Config config = new Config()
.setAccessKeyId(aliYunSmsSetting.getAccessKeyId())
.setAccessKeySecret(aliYunSmsSetting.getAccessKeySecret())
.setRegionId(aliYunSmsSetting.getRegionId())
.setEndpoint(aliYunSmsSetting.getEndpoint());
public AliyunSmsSender(AliYunMailSetting aliYunSmsSetting) throws Exception {
if (ObjectUtil.isNotNull(aliYunSmsSetting)) {
Config config = new Config()
.setAccessKeyId(aliYunSmsSetting.getAccessKeyId())
.setAccessKeySecret(aliYunSmsSetting.getAccessKeySecret())
.setRegionId(aliYunSmsSetting.getRegionId())
.setEndpoint(aliYunSmsSetting.getEndpoint());
try {
this.client = new Client(config);
} catch (Exception e) {
log.error("阿里云-短信服务初始化失败,请检查配置信息");
throw new RuntimeException(e);
try {
this.smsClient = new Client(config);
} catch (Exception e) {
log.error("阿里云-短信服务初始化失败,请检查配置信息");
throw e;
}
}
}
@Override
public boolean sendSms(Map<String, Object> params, String phoneNumber) throws Exception {
Future<Boolean> future = THREAD_POOL_EXECUTOR.submit(() -> {
@@ -84,7 +80,7 @@ public class AliYunSmsClient implements SmsClient {
.setTemplateCode(params.get(TEMPLATE_CODE).toString())
.setTemplateParam(params.get(TEMPLATE_PARAM).toString());
try {
SendSmsResponse response = this.client.sendSmsWithOptions(request, runtimeOptions);
SendSmsResponse response = this.smsClient.sendSmsWithOptions(request, runtimeOptions);
System.out.println(toJSONString(response));
if (OK.equals(response.body.code)) {
return true;
@@ -116,7 +112,7 @@ public class AliYunSmsClient implements SmsClient {
.setTemplateCode(params.get(TEMPLATE_CODE).toString())
.setTemplateParamJson(toJSONString(params.get(TEMPLATE_PARAM)));
try {
SendBatchSmsResponse response = this.client.sendBatchSmsWithOptions(request, runtimeOptions);
SendBatchSmsResponse response = this.smsClient.sendBatchSmsWithOptions(request, runtimeOptions);
System.out.println(toJSONString(response));
if (OK.equals(response.body.code)) {
return true;
@@ -128,17 +124,4 @@ public class AliYunSmsClient implements SmsClient {
throw new RuntimeException(e);
}
}
@Override
public void querySmsTemplateList() {
QuerySmsTemplateListRequest request = new QuerySmsTemplateListRequest();
request.setPageIndex(1);
request.setPageSize(10);
try {
QuerySmsTemplateListResponse querySmsTemplateListResponse = this.client.querySmsTemplateList(request);
System.out.println(toJSONString(querySmsTemplateListResponse));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -1,14 +1,11 @@
package com.njcn.msgpush.module.push.client.channel.sms.Impl;
package com.njcn.msgpush.module.push.client.sender.impl;
import cn.hutool.core.util.StrUtil;
import com.njcn.msgpush.module.push.client.channel.sms.SmsClient;
import com.njcn.msgpush.module.push.client.setting.sms.TelecomSmsSetting;
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.util.RestTemplateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
@@ -17,12 +14,8 @@ import java.util.Map;
/**
* @author caozehui
* @data 2026-02-11
* @description 电信e企云短信服务实现
*/
@Slf4j
@Service
public class TelecomSmsClient implements SmsClient {
public class TelecomSmsSender implements SmsSender {
/**
* 短信接口地址
*/
@@ -36,16 +29,18 @@ public class TelecomSmsClient implements SmsClient {
*/
private static final String CONTENT_TYPE = "application/json;charset=utf-8";
// public static final String ACCOUNT = "account";
// public static final String PASSWORD = "password";
public static final String CONTENT = "content";
@Autowired
private TelecomSmsSetting telecomSmsSetting;
@Autowired
private RestTemplateUtil restTemplateUtil;
public TelecomSmsSender(TelecomSmsSetting telecomSmsSetting, RestTemplateUtil restTemplateUtil) {
this.telecomSmsSetting = telecomSmsSetting;
this.restTemplateUtil = restTemplateUtil;
}
@Override
public boolean sendSms(Map<String, Object> params, String phoneNumber) throws Exception {
return this.sendBatchSms(params, List.of(phoneNumber));
@@ -81,9 +76,4 @@ public class TelecomSmsClient implements SmsClient {
return false;
}
}
@Override
public void querySmsTemplateList() {
}
}

View File

@@ -0,0 +1,12 @@
package com.njcn.msgpush.module.push.client.setting;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author caozehui
* @data 2026-02-09
* @description App推送配置
*/
public abstract class AppPushSetting {
}

View File

@@ -1,9 +0,0 @@
package com.njcn.msgpush.module.push.client.setting;
/**
* @author caozehui
* @data 2026-02-09
* @description 各个推送渠道通用的配置
*/
public abstract class BaseChannelSetting {
}

View File

@@ -0,0 +1,13 @@
package com.njcn.msgpush.module.push.client.setting;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author caozehui
* @data 2026-02-09
* @description 邮箱配置
*/
public abstract class EMailSetting {
}

View File

@@ -0,0 +1,12 @@
package com.njcn.msgpush.module.push.client.setting;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author caozehui
* @data 2026-02-09
* @description 短信配置抽象类
*/
public abstract class SmsSetting {
}

View File

@@ -1,18 +0,0 @@
package com.njcn.msgpush.module.push.client.setting.appPush;
import com.njcn.msgpush.module.push.client.setting.BaseChannelSetting;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author caozehui
* @data 2026-02-09
* @description App推送配置
*/
@Data
@EqualsAndHashCode(callSuper = true)
public abstract class AppPushSetting extends BaseChannelSetting {
private String appKey; //示例
private String secret; //示例
private String key; //示例
}

View File

@@ -1,9 +1,9 @@
package com.njcn.msgpush.module.push.client.setting.mail;
package com.njcn.msgpush.module.push.client.setting.impl;
import com.njcn.msgpush.module.push.client.setting.EMailSetting;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author caozehui
@@ -11,10 +11,9 @@ import org.springframework.stereotype.Component;
* @description 阿里云邮件配置
*/
@Data
@Builder
@EqualsAndHashCode(callSuper = true)
@Component
@ConfigurationProperties(prefix = "aliyun.mail")
public class AliYunMailSetting extends MailSetting {
public class AliYunMailSetting extends EMailSetting {
private String accessKeyId;
private String accessKeySecret;
private String regionId;

View File

@@ -1,9 +1,9 @@
package com.njcn.msgpush.module.push.client.setting.sms;
package com.njcn.msgpush.module.push.client.setting.impl;
import com.njcn.msgpush.module.push.client.setting.SmsSetting;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author caozehui
@@ -11,9 +11,8 @@ import org.springframework.stereotype.Component;
* @description 阿里云短信应用配置
*/
@Data
@Builder
@EqualsAndHashCode(callSuper = true)
@Component
@ConfigurationProperties(prefix = "aliyun.sms")
public class AliYunSmsSetting extends SmsSetting {
private String accessKeyId;
private String accessKeySecret;

View File

@@ -1,9 +1,9 @@
package com.njcn.msgpush.module.push.client.setting.sms;
package com.njcn.msgpush.module.push.client.setting.impl;
import com.njcn.msgpush.module.push.client.setting.SmsSetting;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author caozehui
@@ -11,9 +11,8 @@ import org.springframework.stereotype.Component;
* @description 电信e企云短信服务应用配置
*/
@Data
@Builder
@EqualsAndHashCode(callSuper = true)
@Component
@ConfigurationProperties(prefix = "telecom.sms")
public class TelecomSmsSetting extends SmsSetting {
private String account;
private String password;

View File

@@ -1,9 +1,7 @@
package com.njcn.msgpush.module.push.client.setting.appPush;
package com.njcn.msgpush.module.push.client.setting.impl;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import com.njcn.msgpush.module.push.client.setting.AppPushSetting;
import lombok.*;
/**
* @author caozehui
@@ -11,8 +9,7 @@ import lombok.NoArgsConstructor;
* @description UniPush应用推送配置
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@EqualsAndHashCode(callSuper = true)
public class UniPushAppPushSetting extends AppPushSetting {
private String accessKeyId;

View File

@@ -1,16 +0,0 @@
package com.njcn.msgpush.module.push.client.setting.mail;
import com.njcn.msgpush.module.push.client.setting.BaseChannelSetting;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author caozehui
* @data 2026-02-09
* @description 邮箱配置
*/
@Data
@EqualsAndHashCode(callSuper = true)
public abstract class MailSetting extends BaseChannelSetting {
}

View File

@@ -1,15 +0,0 @@
package com.njcn.msgpush.module.push.client.setting.sms;
import com.njcn.msgpush.module.push.client.setting.BaseChannelSetting;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author caozehui
* @data 2026-02-09
* @description 短信配置抽象类
*/
@Data
@EqualsAndHashCode(callSuper = true)
public abstract class SmsSetting extends BaseChannelSetting {
}

View File

@@ -0,0 +1,11 @@
package com.njcn.msgpush.module.push.constant;
/**
* @author caozehui
* @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";
}

View File

@@ -1,12 +1,20 @@
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.controller.admin.channel.vo.ChannelProviderConfigReqVO;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
import com.njcn.msgpush.module.push.service.channel.ChannelProviderConfigService;
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.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Tag(name = "管理后台 - 渠道服务商")
@Slf4j
@@ -19,4 +27,43 @@ public class ChannelProviderConfigController {
private ChannelProviderConfigService channelProviderConfigService;
@PostMapping("/list")
@Operation(summary = "分页查询渠道服务商列表")
@PreAuthorize("@ss.hasPermission('push:channel:list')")
public CommonResult<Page<ChannelProviderConfigDO>> getChannelProviderConfigPage(@Validated @RequestBody ChannelProviderConfigReqVO reqVO) {
Page<ChannelProviderConfigDO> res = channelProviderConfigService.listChannelProviderCfg(reqVO);
return CommonResult.success(res);
}
@PostMapping("add")
@Operation(summary = "新增渠道服务商")
@PreAuthorize("@ss.hasPermission('push:channel:add')")
public CommonResult<Boolean> addChannelProvider(@Validated @RequestBody ChannelProviderConfigReqVO reqVO) {
boolean res = channelProviderConfigService.save(BeanUtil.copyProperties(reqVO, ChannelProviderConfigDO.class));
return CommonResult.success(res);
}
@PostMapping("update")
@Operation(summary = "更新渠道服务商")
@PreAuthorize("@ss.hasPermission('push:channel:update')")
public CommonResult<Boolean> updateChannelProvider(@Validated @RequestBody ChannelProviderConfigReqVO reqVO) {
boolean res = channelProviderConfigService.updateById(BeanUtil.copyProperties(reqVO, ChannelProviderConfigDO.class));
return CommonResult.success(res);
}
@PostMapping("delete")
@Operation(summary = "删除渠道服务商")
@PreAuthorize("@ss.hasPermission('push:channel:delete')")
public CommonResult<Boolean> deleteChannelProvider(@RequestBody List<String> ids) {
boolean res = channelProviderConfigService.removeBatchByIds(ids);
return CommonResult.success(res);
}
@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);
}
}

View File

@@ -1,11 +1,12 @@
package com.njcn.msgpush.module.push.controller.admin.channel.vo;
import com.njcn.msgpush.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "管理后台 - 渠道服务商配置 Request VO")
public class ChannelProviderConfigReqVO {
public class ChannelProviderConfigReqVO extends PageParam {
@Schema(description = "渠道类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sms/email/app_push")
private String channel;

View File

@@ -24,9 +24,9 @@ public class MessageRecordController {
@Autowired
private MessageRecordService messageRecordService;
@PostMapping("send")
@PermitAll
@Operation(summary = "使用账号密码登录")
@PostMapping("send")
@Operation(summary = "消息推送")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
public CommonResult<Boolean> send(MessageRecordSendReqVO messageRecordSendReqVO) {
Boolean result = messageRecordService.send(messageRecordSendReqVO);

View File

@@ -1,4 +1,22 @@
package com.njcn.msgpush.module.push.service.channel;
public interface ChannelProviderConfigService {
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.njcn.msgpush.module.push.controller.admin.channel.vo.ChannelProviderConfigReqVO;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
import java.util.List;
public interface ChannelProviderConfigService extends IService<ChannelProviderConfigDO> {
Page<ChannelProviderConfigDO> listChannelProviderCfg(ChannelProviderConfigReqVO pageReqVO);
List<ChannelProviderConfigDO> getActiveProviders();
/**
* 切换服务提供商enable字段
*
* @param id 服务提供商id
* @return
*/
boolean toggleEnableField(String id);
}

View File

@@ -1,7 +1,62 @@
package com.njcn.msgpush.module.push.service.channel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
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 implements ChannelProviderConfigService {
public class ChannelProviderConfigServiceImpl extends ServiceImpl<ChannelProviderConfigMapper, ChannelProviderConfigDO> implements ChannelProviderConfigService {
@Autowired
private ConfigurableApplicationContext applicationContext;
@Override
public Page<ChannelProviderConfigDO> listChannelProviderCfg(ChannelProviderConfigReqVO pageReqVO) {
QueryWrapper<ChannelProviderConfigDO> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(ChannelProviderConfigDO::getChannel, pageReqVO.getChannel());
return this.page(new Page<>(PageUtils.getPageNum(pageReqVO), PageUtils.getPageSize(pageReqVO)), wrapper);
}
@Override
public List<ChannelProviderConfigDO> getActiveProviders() {
List<ChannelProviderConfigDO> configDOList = List.of(
new ChannelProviderConfigDO()
.setAppKey("LTAI4FxsR76x2dq3w9c5puUe")
.setAppSecret("GxkTR8fsrvHtixTlD9UPmOGli35tZs")
.setProviderName("阿里云")
.setProviderType("aliyun")
);
return configDOList;
}
@Override
public boolean toggleEnableField(String id) {
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);
}
}
}

View File

@@ -1,18 +0,0 @@
package com.njcn.msgpush.module.push;
import com.njcn.msgpush.module.push.client.channel.mail.impl.AliYunMailClient;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class AliYunMailClientTest {
@Autowired
private AliYunMailClient aliYunMailClient;
@Test
public void testQueryMailAddressByParam(){
aliYunMailClient.queryMailAddressByParam();
}
}

View File

@@ -1,49 +0,0 @@
package com.njcn.msgpush.module.push.sms;
import com.njcn.msgpush.module.push.client.channel.sms.Impl.AliYunSmsClient;
import com.njcn.msgpush.module.push.client.channel.sms.SmsClient;
import com.njcn.msgpush.module.push.client.channel.sms.factory.SmsFactory;
import com.njcn.msgpush.module.push.client.constant.ClientConstant;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author caozehui
* @data 2026-02-06
*/
@SpringBootTest
public class AliYumSmsClientTest {
@Autowired
private SmsFactory smsFactory;
@Test
public void testSendSms() throws Exception {
Map<String, Object> params = new HashMap<>();
params.put(AliYunSmsClient.SIGN_NAME, "灿能云");
params.put(AliYunSmsClient.TEMPLATE_CODE, "SMS_481710295");
params.put(AliYunSmsClient.TEMPLATE_PARAM, "{\"code\":\"123456\"}");
boolean b = smsFactory.getClient("阿里云").sendSms(params, "18839431215");
System.out.println(System.currentTimeMillis() + " " + b);
}
@Test
public void testSendBatchSms() {
Map<String, Object> params = new HashMap<>();
params.put(AliYunSmsClient.SIGN_NAME, List.of("灿能云"));
params.put(AliYunSmsClient.TEMPLATE_CODE, "SMS_481710295");
params.put(AliYunSmsClient.TEMPLATE_PARAM, List.of("{\"code\":\"123456\"}"));
smsFactory.getClient("阿里云").sendBatchSms(params, List.of("18839431215"));
}
@Test
public void testQuerySmsTemplateListRequest() {
SmsClient client = smsFactory.getClient(ClientConstant.ALI_YUN);
client.querySmsTemplateList();
}
}

View File

@@ -0,0 +1,59 @@
package com.njcn.msgpush.module.push.sms;
import com.njcn.msgpush.module.push.client.factory.MessageProviderFactory;
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 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.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author caozehui
* @data 2026-02-06
*/
@SpringBootTest
public class MsgPushClientTest {
@Autowired
@Qualifier("messageProviderFactoryMap")
private Map<String, MessageProviderFactory> messageProviderFactoryMap;
@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);
boolean b = smsSender.sendSms(params, "18839431215");
System.out.println(System.currentTimeMillis() + " " + b);
}
@Test
public void testSendBatchSms() throws Exception {
Map<String, Object> params = new HashMap<>();
params.put(AliyunSmsSender.SIGN_NAME, List.of("灿能云"));
params.put(AliyunSmsSender.TEMPLATE_CODE, "SMS_481710295");
params.put(AliyunSmsSender.TEMPLATE_PARAM, List.of("{\"code\":\"123456\"}"));
ChannelProviderConfigDO channelProviderConfigDO = new ChannelProviderConfigDO();
channelProviderConfigDO.setAppKey("LTAI4FxsR76x2dq3w9c5puUe");
channelProviderConfigDO.setAppSecret("GxkTR8fsrvHtixTlD9UPmOGli35tZs");
SmsSender smsSender = messageProviderFactoryMap.get(MsgPushConstant.ALI_YUN).createSmsSender(channelProviderConfigDO);
boolean b = smsSender.sendBatchSms(params, List.of("18839431215"));
System.out.println(System.currentTimeMillis() + " " + b);
}
}

View File

@@ -1,33 +0,0 @@
package com.njcn.msgpush.module.push.sms;
import com.njcn.msgpush.module.push.client.channel.sms.Impl.TelecomSmsClient;
import com.njcn.msgpush.module.push.client.channel.sms.factory.SmsFactory;
import com.njcn.msgpush.module.push.client.constant.ClientConstant;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
/**
* @author caozehui
* @data 2026-02-10
*/
@SpringBootTest
public class TelecomSmsClientTest {
@Autowired
private SmsFactory smsFactory;
@Test
public void testSendSms() throws Exception {
Map<String, Object> params = new HashMap<>();
// params.put(TelecomSmsClient.ACCOUNT, "925631");
// params.put(TelecomSmsClient.PASSWORD, "AMW2pOVrdky");
params.put(TelecomSmsClient.CONTENT, "【南京灿能电力】这是JUnit群发短信测试请忽略。时间" + LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
smsFactory.getClient(ClientConstant.TELECOM).sendSms(params, "18839431215");
}
}