微调
This commit is contained in:
@@ -6,6 +6,7 @@ import org.springframework.core.Ordered;
|
|||||||
import org.springframework.security.config.Customizer;
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义的 URL 的安全配置
|
* 自定义的 URL 的安全配置
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class MsgpushSecurityAutoConfiguration {
|
|||||||
private SecurityProperties securityProperties;
|
private SecurityProperties securityProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 认证失败处理类 Bean
|
* 身份认证失败处理类 Bean
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public AuthenticationEntryPoint authenticationEntryPoint() {
|
public AuthenticationEntryPoint authenticationEntryPoint() {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.google.common.collect.Multimap;
|
|||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.annotation.security.PermitAll;
|
import jakarta.annotation.security.PermitAll;
|
||||||
import jakarta.servlet.DispatcherType;
|
import jakarta.servlet.DispatcherType;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import org.springframework.util.Assert;
|
|||||||
public class TransmittableThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
|
public class TransmittableThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用 TransmittableThreadLocal 作为上下文
|
* 使用 TransmittableThreadLocal 实现线程之间上下文的传递。
|
||||||
*/
|
*/
|
||||||
private static final ThreadLocal<SecurityContext> CONTEXT_HOLDER = new TransmittableThreadLocal<>();
|
private static final ThreadLocal<SecurityContext> CONTEXT_HOLDER = new TransmittableThreadLocal<>();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
com.njcn.msgpush.framework.security.config.MsgpushSecurityRpcAutoConfiguration
|
com.njcn.msgpush.framework.security.config.MsgpushSecurityRpcAutoConfiguration
|
||||||
com.njcn.msgpush.framework.security.config.MsgpushSecurityAutoConfiguration
|
com.njcn.msgpush.framework.security.config.MsgpushSecurityAutoConfiguration
|
||||||
com.njcn.msgpush.framework.security.config.MsgpushWebSecurityConfigurerAdapter
|
|
||||||
com.njcn.msgpush.framework.operatelog.config.MsgpushOperateLogConfiguration
|
com.njcn.msgpush.framework.operatelog.config.MsgpushOperateLogConfiguration
|
||||||
com.njcn.msgpush.framework.operatelog.config.MsgpushOperateLogRpcAutoConfiguration
|
com.njcn.msgpush.framework.operatelog.config.MsgpushOperateLogRpcAutoConfiguration
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.njcn.msgpush.module.push.annoation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-10
|
||||||
|
* @description 接口幂等性检查注解
|
||||||
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface CheckIdmpotent {
|
||||||
|
}
|
||||||
@@ -105,6 +105,20 @@
|
|||||||
<artifactId>hutool-extra</artifactId> <!-- 邮件 -->
|
<artifactId>hutool-extra</artifactId> <!-- 邮件 -->
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 阿里云 Direct Mail (邮箱服务) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.aliyun</groupId>
|
||||||
|
<artifactId>dm20151123</artifactId>
|
||||||
|
<version>1.9.3</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 阿里云短信服务 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.aliyun</groupId>
|
||||||
|
<artifactId>dysmsapi20170525</artifactId>
|
||||||
|
<version>4.2.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ package com.njcn.msgpush.module.push;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 项目的启动类
|
* 项目的启动类
|
||||||
|
*
|
||||||
* @author hongawen
|
* @author hongawen
|
||||||
*/
|
*/
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.njcn.msgpush.module.push.checker;
|
||||||
|
|
||||||
|
import com.njcn.msgpush.module.push.controller.admin.message.vo.MessageRecordSendReqVO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-27
|
||||||
|
* @description 检查器接口
|
||||||
|
*/
|
||||||
|
public interface IChecker {
|
||||||
|
|
||||||
|
boolean check(MessageRecordSendReqVO reqVO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package com.njcn.msgpush.module.push.checker;
|
||||||
|
|
||||||
|
import com.njcn.msgpush.module.push.checker.impl.BlacklistChecker;
|
||||||
|
import com.njcn.msgpush.module.push.checker.impl.IdempotencyChecker;
|
||||||
|
import com.njcn.msgpush.module.push.checker.impl.QuotaChecker;
|
||||||
|
import com.njcn.msgpush.module.push.checker.impl.RateLimitChecker;
|
||||||
|
import com.njcn.msgpush.module.push.controller.admin.message.vo.MessageRecordSendReqVO;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-28
|
||||||
|
* @description 检查链
|
||||||
|
*/
|
||||||
|
public class MsgPushGuardChain {
|
||||||
|
private final List<IChecker> checkers;
|
||||||
|
|
||||||
|
public MsgPushGuardChain() {
|
||||||
|
this.checkers = new ArrayList<>();
|
||||||
|
this.checkers.add(new IdempotencyChecker());
|
||||||
|
this.checkers.add(new BlacklistChecker());
|
||||||
|
this.checkers.add(new QuotaChecker());
|
||||||
|
this.checkers.add(new RateLimitChecker());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkAll(MessageRecordSendReqVO reqVO) {
|
||||||
|
for (IChecker checker : checkers) {
|
||||||
|
boolean result = checker.check(reqVO);
|
||||||
|
if (!result) {
|
||||||
|
// 任何一层检查失败,立即返回拒绝
|
||||||
|
logRejection(reqVO);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logRejection(MessageRecordSendReqVO reqVO) {
|
||||||
|
// 记录拒绝日志,用于监控和分析
|
||||||
|
System.out.printf("消息请求被拒绝: receiver=%s, messageId=%s, reason=%s%n", reqVO.getReceiver(), reqVO.getMessageId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.njcn.msgpush.module.push.checker.impl;
|
||||||
|
|
||||||
|
import com.njcn.msgpush.module.push.checker.IChecker;
|
||||||
|
import com.njcn.msgpush.module.push.controller.admin.message.vo.MessageRecordSendReqVO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-27
|
||||||
|
* @description 黑名单检查器
|
||||||
|
*/
|
||||||
|
public class BlacklistChecker implements IChecker {
|
||||||
|
@Override
|
||||||
|
public boolean check(MessageRecordSendReqVO reqVO) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.njcn.msgpush.module.push.checker.impl;
|
||||||
|
|
||||||
|
import com.njcn.msgpush.module.push.checker.IChecker;
|
||||||
|
import com.njcn.msgpush.module.push.controller.admin.message.vo.MessageRecordSendReqVO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-27
|
||||||
|
* @description 接口幂等性检查器
|
||||||
|
*/
|
||||||
|
public class IdempotencyChecker implements IChecker {
|
||||||
|
@Override
|
||||||
|
public boolean check(MessageRecordSendReqVO reqVO) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.njcn.msgpush.module.push.checker.impl;
|
||||||
|
|
||||||
|
import com.njcn.msgpush.module.push.checker.IChecker;
|
||||||
|
import com.njcn.msgpush.module.push.controller.admin.message.vo.MessageRecordSendReqVO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-27
|
||||||
|
* @description 系统配额检查器
|
||||||
|
*/
|
||||||
|
public class QuotaChecker implements IChecker {
|
||||||
|
@Override
|
||||||
|
public boolean check(MessageRecordSendReqVO reqVO) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.njcn.msgpush.module.push.checker.impl;
|
||||||
|
|
||||||
|
|
||||||
|
import com.njcn.msgpush.module.push.checker.IChecker;
|
||||||
|
import com.njcn.msgpush.module.push.controller.admin.message.vo.MessageRecordSendReqVO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-27
|
||||||
|
* @description 接收者频率检查器
|
||||||
|
*/
|
||||||
|
public class RateLimitChecker implements IChecker {
|
||||||
|
@Override
|
||||||
|
public boolean check(MessageRecordSendReqVO reqVO) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.njcn.msgpush.module.push.client.channel.appPush;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-11
|
||||||
|
*/
|
||||||
|
public interface AppPushClient {
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.njcn.msgpush.module.push.client.channel.appPush.factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-11
|
||||||
|
*/
|
||||||
|
public class AppPushFactory {
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
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 + "邮件服务提供商");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
package com.njcn.msgpush.module.push.client.channel.sms.Impl;
|
||||||
|
|
||||||
|
import com.aliyun.dysmsapi20170525.Client;
|
||||||
|
import com.aliyun.dysmsapi20170525.models.*;
|
||||||
|
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 lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
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 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";
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AliYunSmsSetting aliYunSmsSetting;
|
||||||
|
private Client client;
|
||||||
|
|
||||||
|
private static 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()
|
||||||
|
);
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean sendSms(Map<String, Object> params, String phoneNumber) throws Exception {
|
||||||
|
Future<Boolean> future = THREAD_POOL_EXECUTOR.submit(() -> {
|
||||||
|
// todo 修改消息的状态为 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());
|
||||||
|
try {
|
||||||
|
SendSmsResponse response = this.client.sendSmsWithOptions(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 Exception(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Boolean b = future.get(3, TimeUnit.SECONDS);
|
||||||
|
if (b) {
|
||||||
|
// todo 修改消息的状态为 success
|
||||||
|
} else {
|
||||||
|
// todo 修改消息的状态为 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.client.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package com.njcn.msgpush.module.push.client.channel.sms.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.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;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-11
|
||||||
|
* @description 电信e企云短信服务实现
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class TelecomSmsClient implements SmsClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 短信接口地址
|
||||||
|
*/
|
||||||
|
private static final String API_URL = "https://sms.ymeeting.cn/smsv2";
|
||||||
|
/**
|
||||||
|
* 虚拟接入码
|
||||||
|
*/
|
||||||
|
private static final String ACCESS_CODE = "106905631";
|
||||||
|
/**
|
||||||
|
* 短信接口内容类型
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean sendSms(Map<String, Object> params, String phoneNumber) throws Exception {
|
||||||
|
return this.sendBatchSms(params, List.of(phoneNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean sendBatchSms(Map<String, Object> params, List<String> phoneNumbers) {
|
||||||
|
// 构建请求参数
|
||||||
|
Map<String, Object> request = new HashMap<>();
|
||||||
|
request.put("action", "send");
|
||||||
|
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());
|
||||||
|
request.put("extno", ACCESS_CODE);
|
||||||
|
|
||||||
|
// 设置请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.set("Content-Type", CONTENT_TYPE);
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
ResponseEntity<String> response = restTemplateUtil.post(
|
||||||
|
API_URL,
|
||||||
|
request,
|
||||||
|
headers,
|
||||||
|
String.class
|
||||||
|
);
|
||||||
|
String body = response.getBody();
|
||||||
|
|
||||||
|
if (body.contains("\"status\": 0")) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void querySmsTemplateList() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.njcn.msgpush.module.push.client.channel.sms;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-10
|
||||||
|
*/
|
||||||
|
public interface SmsClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向单个手机号发送短信
|
||||||
|
*
|
||||||
|
* @param phoneNumber 手机号
|
||||||
|
* @param params 参数
|
||||||
|
* @return 发送结果
|
||||||
|
*/
|
||||||
|
boolean sendSms(Map<String, Object> params, String phoneNumber) throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向多个手机号发送短信
|
||||||
|
*
|
||||||
|
* @param phoneNumbers 手机号集合
|
||||||
|
* @param params 参数
|
||||||
|
* @return 发送结果
|
||||||
|
*/
|
||||||
|
boolean sendBatchSms(Map<String, Object> params, List<String> phoneNumbers);
|
||||||
|
|
||||||
|
void querySmsTemplateList();
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
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 + "短信服务提供商");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.njcn.msgpush.module.push.client.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-10
|
||||||
|
*/
|
||||||
|
public interface ClientConstant {
|
||||||
|
String ALI_YUN = "阿里云";
|
||||||
|
|
||||||
|
String TELECOM = "电信";
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.njcn.msgpush.module.push.client.setting;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-09
|
||||||
|
* @description 各个推送渠道通用的配置
|
||||||
|
*/
|
||||||
|
public abstract class BaseChannelSetting {
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
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; //示例
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.njcn.msgpush.module.push.client.setting.appPush;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-09
|
||||||
|
* @description UniPush应用推送配置
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class UniPushAppPushSetting extends AppPushSetting {
|
||||||
|
private String accessKeyId;
|
||||||
|
private String accessKeySecret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.njcn.msgpush.module.push.client.setting.mail;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-09
|
||||||
|
* @description 阿里云邮件配置
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "aliyun.mail")
|
||||||
|
public class AliYunMailSetting extends MailSetting {
|
||||||
|
private String accessKeyId;
|
||||||
|
private String accessKeySecret;
|
||||||
|
private String regionId;
|
||||||
|
private String endpoint;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
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 {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.njcn.msgpush.module.push.client.setting.sms;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-09
|
||||||
|
* @description 阿里云短信应用配置
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "aliyun.sms")
|
||||||
|
public class AliYunSmsSetting extends SmsSetting {
|
||||||
|
private String accessKeyId;
|
||||||
|
private String accessKeySecret;
|
||||||
|
private String regionId;
|
||||||
|
private String endpoint;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
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 {
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.njcn.msgpush.module.push.client.setting.sms;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-10
|
||||||
|
* @description 电信e企云短信服务应用配置
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "telecom.sms")
|
||||||
|
public class TelecomSmsSetting extends SmsSetting {
|
||||||
|
private String account;
|
||||||
|
private String password;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.njcn.msgpush.module.push.controller.admin.channel;
|
||||||
|
|
||||||
|
import com.njcn.msgpush.module.push.service.channel.ChannelProviderConfigService;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@Tag(name = "管理后台 - 渠道服务商")
|
||||||
|
@Slf4j
|
||||||
|
@Validated
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/push/channel")
|
||||||
|
public class ChannelProviderConfigController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ChannelProviderConfigService channelProviderConfigService;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.njcn.msgpush.module.push.controller.admin.channel.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Schema(description = "管理后台 - 渠道服务商配置 Request VO")
|
||||||
|
public class ChannelProviderConfigReqVO {
|
||||||
|
@Schema(description = "渠道类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sms/email/app_push")
|
||||||
|
private String channel;
|
||||||
|
|
||||||
|
@Schema(description = "服务商名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "中国电信/阿里云/UniPush")
|
||||||
|
private String providerName;
|
||||||
|
|
||||||
|
@Schema(description = "服务商类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "telecom/cmcc/aliyun/twilio/unipush")
|
||||||
|
private String providerType;
|
||||||
|
|
||||||
|
@Schema(description = "API地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://api.example.com")
|
||||||
|
private String apiUrl;
|
||||||
|
|
||||||
|
@Schema(description = "AppKey", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
|
||||||
|
private String appKey;
|
||||||
|
|
||||||
|
@Schema(description = "AppSecret", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
|
||||||
|
private String appSecret;
|
||||||
|
|
||||||
|
@Schema(description = "额外配置(JSON格式)", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
|
||||||
|
private String extraConfig;
|
||||||
|
|
||||||
|
@Schema(description = "优先级(数字越小优先级越高)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Integer priority;
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.njcn.msgpush.module.push.controller.admin.message;
|
||||||
|
|
||||||
|
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||||
|
import com.njcn.msgpush.module.push.controller.admin.message.vo.MessageRecordSendReqVO;
|
||||||
|
import com.njcn.msgpush.module.push.service.message.MessageRecordService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.security.PermitAll;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@Tag(name = "管理后台 - 消息")
|
||||||
|
@Slf4j
|
||||||
|
@Validated
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/push/message")
|
||||||
|
public class MessageRecordController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MessageRecordService messageRecordService;
|
||||||
|
|
||||||
|
@PostMapping("send")
|
||||||
|
@PermitAll
|
||||||
|
@Operation(summary = "使用账号密码登录")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||||
|
public CommonResult<Boolean> send(MessageRecordSendReqVO messageRecordSendReqVO) {
|
||||||
|
Boolean result = messageRecordService.send(messageRecordSendReqVO);
|
||||||
|
return CommonResult.success(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.njcn.msgpush.module.push.controller.admin.message.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Schema(description = "管理后台 - 消息记录发送 Request VO")
|
||||||
|
public class MessageRecordSendReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "消息唯一ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
|
||||||
|
private String messageId;
|
||||||
|
|
||||||
|
@Schema(description = "应用名称/来源系统标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "NPQS-9500")
|
||||||
|
private String appName;
|
||||||
|
|
||||||
|
@Schema(description = "渠道类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sms/email/app_push")
|
||||||
|
private String channel;
|
||||||
|
|
||||||
|
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "verify_code/order_notify/marketing/system_notify")
|
||||||
|
private String messageType;
|
||||||
|
|
||||||
|
@Schema(description = "接收者", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300")
|
||||||
|
private String receiver;
|
||||||
|
|
||||||
|
@Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
@Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private String templateCode;
|
||||||
|
|
||||||
|
@Schema(description = "模板参数")
|
||||||
|
private String templateParams;
|
||||||
|
|
||||||
|
@Schema(description = "服务商类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "telecom/cmcc/aliyun/twilio")
|
||||||
|
private String providerType;
|
||||||
|
|
||||||
|
@Schema(description = "第三方消息ID")
|
||||||
|
private String thirdPartyId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package com.njcn.msgpush.module.push.dal.dataobject.channel;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.njcn.msgpush.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-06
|
||||||
|
* @description 渠道服务商配置表对应的数据对象
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("push_channel_provider_config")
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ChannelProviderConfigDO extends BaseDO {
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 渠道类型:sms/email/app_push
|
||||||
|
*/
|
||||||
|
private String channel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务商名称:中国电信/阿里云/UniPush
|
||||||
|
*/
|
||||||
|
private String providerName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务商类型:telecom/cmcc/aliyun/twilio/unipush
|
||||||
|
*/
|
||||||
|
private String providerType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API地址
|
||||||
|
*/
|
||||||
|
private String apiUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AppKey
|
||||||
|
*/
|
||||||
|
private String appKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AppSecret
|
||||||
|
*/
|
||||||
|
private String appSecret;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 额外配置(JSON格式)
|
||||||
|
*/
|
||||||
|
private String extraConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优先级(数字越小优先级越高)
|
||||||
|
*/
|
||||||
|
private Integer priority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否启用:0-禁用 1-启用(手动控制)
|
||||||
|
*/
|
||||||
|
private Integer enabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 健康状态:0-异常 1-正常(自动检测)
|
||||||
|
*/
|
||||||
|
private Integer healthStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 连续失败次数(自动统计)
|
||||||
|
*/
|
||||||
|
private Integer failureCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后失败时间(自动记录)
|
||||||
|
*/
|
||||||
|
private LocalDateTime lastFailureTime;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
package com.njcn.msgpush.module.push.dal.dataobject.message;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.njcn.msgpush.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-06
|
||||||
|
* @description 消息记录表对应的数据对象
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("push_message_record")
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class MessageRecordDO extends BaseDO {
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息唯一ID
|
||||||
|
*/
|
||||||
|
private String messageId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用名称/来源系统标识
|
||||||
|
*/
|
||||||
|
private String appName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 渠道类型:sms/email/app_push
|
||||||
|
*/
|
||||||
|
private String channel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息类型:verify_code/order_notify/marketing/system_notify
|
||||||
|
*/
|
||||||
|
private String messageType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收者
|
||||||
|
*/
|
||||||
|
private String receiver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标题
|
||||||
|
*/
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息内容
|
||||||
|
*/
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板编码
|
||||||
|
*/
|
||||||
|
private String templateCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板参数
|
||||||
|
*/
|
||||||
|
private String templateParams;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态:pending/sending/success/failed/final_failed/blacklisted/quota_exceeded/rate_limited/abandoned
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime sendTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送耗时(毫秒)
|
||||||
|
*/
|
||||||
|
private Integer costTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已重试次数
|
||||||
|
*/
|
||||||
|
private Integer retryCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后重试时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime lastRetryTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下次重试时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime nextRetryTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务商类型:telecom/cmcc/aliyun/twilio
|
||||||
|
*/
|
||||||
|
private String providerType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方消息ID
|
||||||
|
*/
|
||||||
|
private String thirdPartyId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一错误码
|
||||||
|
*/
|
||||||
|
private String errorCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误信息
|
||||||
|
*/
|
||||||
|
private String errorMsg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过期时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime expireTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.njcn.msgpush.module.push.dal.mysql.channel;
|
||||||
|
|
||||||
|
import com.njcn.msgpush.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface ChannelProviderConfigMapper extends BaseMapperX<ChannelProviderConfigDO> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.njcn.msgpush.module.push.dal.mysql.message;
|
||||||
|
|
||||||
|
import com.njcn.msgpush.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface MessageRecordMapper extends BaseMapperX<MessageRecordDO> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package com.njcn.msgpush.module.push.service.channel;
|
||||||
|
|
||||||
|
public interface ChannelProviderConfigService {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.njcn.msgpush.module.push.service.channel;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ChannelProviderConfigServiceImpl implements ChannelProviderConfigService {
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.njcn.msgpush.module.push.service.message;
|
||||||
|
|
||||||
|
import com.njcn.msgpush.module.push.controller.admin.message.vo.MessageRecordSendReqVO;
|
||||||
|
|
||||||
|
public interface MessageRecordService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息(包括email、sms、app_push)
|
||||||
|
*
|
||||||
|
* @param messageRecordSendReqVO
|
||||||
|
* @return 发送是否成功的结果
|
||||||
|
*/
|
||||||
|
Boolean send(MessageRecordSendReqVO messageRecordSendReqVO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.njcn.msgpush.module.push.service.message;
|
||||||
|
|
||||||
|
|
||||||
|
import com.njcn.msgpush.module.push.controller.admin.message.vo.MessageRecordSendReqVO;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class MessageRecordServiceImpl implements MessageRecordService{
|
||||||
|
@Override
|
||||||
|
public Boolean send(MessageRecordSendReqVO messageRecordSendReqVO) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package com.njcn.msgpush.module.push.util;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caozehui
|
||||||
|
* @data 2026-02-10
|
||||||
|
* @description restTemplate工具类
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class RestTemplateUtil {
|
||||||
|
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
|
||||||
|
public RestTemplateUtil() {
|
||||||
|
this.restTemplate = new RestTemplate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> ResponseEntity<T> get(String url, Class<T> responseType) {
|
||||||
|
return get(url, null, responseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> ResponseEntity<T> get(String url, HttpHeaders headers, Class<T> responseType) {
|
||||||
|
try {
|
||||||
|
HttpEntity<String> requestEntity = new HttpEntity<>(headers);
|
||||||
|
log.info("发送GET请求到: {}", url);
|
||||||
|
ResponseEntity<T> response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, responseType);
|
||||||
|
log.info("GET请求响应状态: {}", response.getStatusCode());
|
||||||
|
return response;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("GET请求异常: {}", e.getMessage(), e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> ResponseEntity<T> post(String url, Object requestBody, Class<T> responseType) {
|
||||||
|
return post(url, requestBody, null, responseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> ResponseEntity<T> post(String url, Object requestBody, HttpHeaders headers, Class<T> responseType) {
|
||||||
|
try {
|
||||||
|
if (headers == null) {
|
||||||
|
headers = new HttpHeaders();
|
||||||
|
}
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
HttpEntity<Object> request = new HttpEntity<>(requestBody, headers);
|
||||||
|
log.info("发送POST请求到: {}", url);
|
||||||
|
ResponseEntity<T> response = restTemplate.postForEntity(url, request, responseType);
|
||||||
|
log.info("POST请求响应状态: {}", response.getStatusCode());
|
||||||
|
return response;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("POST请求异常: {}", e.getMessage(), e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> ResponseEntity<T> postForm(String url, Map<String, String> formData, Class<T> responseType) {
|
||||||
|
return postForm(url, formData, null, responseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> ResponseEntity<T> postForm(String url, Map<String, String> formData, HttpHeaders headers, Class<T> responseType) {
|
||||||
|
try {
|
||||||
|
if (headers == null) {
|
||||||
|
headers = new HttpHeaders();
|
||||||
|
}
|
||||||
|
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||||
|
|
||||||
|
HttpEntity<Map<String, String>> request = new HttpEntity<>(formData, headers);
|
||||||
|
log.info("发送POST表单请求到: {}", url);
|
||||||
|
ResponseEntity<T> response = restTemplate.postForEntity(url, request, responseType);
|
||||||
|
log.info("POST表单请求响应状态: {}", response.getStatusCode());
|
||||||
|
return response;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("POST表单请求异常: {}", e.getMessage(), e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T getForObject(String url, Class<T> responseType) {
|
||||||
|
try {
|
||||||
|
log.info("发送GET请求获取对象到: {}", url);
|
||||||
|
T result = restTemplate.getForObject(url, responseType);
|
||||||
|
log.info("GET请求成功获取对象");
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("GET请求获取对象异常: {}", e.getMessage(), e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T postForObject(String url, Object requestBody, Class<T> responseType) {
|
||||||
|
try {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
HttpEntity<Object> request = new HttpEntity<>(requestBody, headers);
|
||||||
|
|
||||||
|
log.info("发送POST请求获取对象到: {}", url);
|
||||||
|
T result = restTemplate.postForObject(url, request, responseType);
|
||||||
|
log.info("POST请求成功获取对象");
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("POST请求获取对象异常: {}", e.getMessage(), e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(String url) {
|
||||||
|
return getForObject(url, String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String postString(String url, Object requestBody) {
|
||||||
|
return postForObject(url, requestBody, String.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,13 +7,13 @@ spring:
|
|||||||
username: # Nacos 账号
|
username: # Nacos 账号
|
||||||
password: # Nacos 密码
|
password: # Nacos 密码
|
||||||
discovery: # 【配置中心】配置项
|
discovery: # 【配置中心】配置项
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
namespace: msgCenter # 命名空间。这里使用 dev 开发环境
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
group: DEV # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||||
metadata:
|
metadata:
|
||||||
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
||||||
config: # 【注册中心】配置项
|
config: # 【注册中心】配置项
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
namespace: msgCenter # 命名空间。这里使用 dev 开发环境
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
group: DEV # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||||
|
|
||||||
--- #################### 数据库相关配置 ####################
|
--- #################### 数据库相关配置 ####################
|
||||||
spring:
|
spring:
|
||||||
|
|||||||
@@ -1,23 +1,30 @@
|
|||||||
--- #################### 注册中心 + 配置中心相关配置 ####################
|
--- #################### 注册中心 + 配置中心相关配置 ####################
|
||||||
|
|
||||||
|
#spring:
|
||||||
|
# cloud:
|
||||||
|
# nacos:
|
||||||
|
# server-addr: 192.168.1.103:18848 # Nacos 服务器地址
|
||||||
|
# username: # Nacos 账号
|
||||||
|
# password: # Nacos 密码
|
||||||
|
# discovery: # 【配置中心】配置项
|
||||||
|
# namespace: msgCenter # 命名空间。这里使用 dev 开发环境
|
||||||
|
# group: DEV # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||||
|
# metadata:
|
||||||
|
# version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
||||||
|
# config: # 【注册中心】配置项
|
||||||
|
# namespace: msgCenter # 命名空间。这里使用 dev 开发环境
|
||||||
|
# group: DEV # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||||
spring:
|
spring:
|
||||||
cloud:
|
cloud:
|
||||||
nacos:
|
nacos:
|
||||||
server-addr: 192.168.1.103:18848 # Nacos 服务器地址
|
discovery:
|
||||||
username: # Nacos 账号
|
enabled: false
|
||||||
password: # Nacos 密码
|
config:
|
||||||
discovery: # 【配置中心】配置项
|
enabled: false
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
|
||||||
metadata:
|
|
||||||
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
|
||||||
config: # 【注册中心】配置项
|
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
|
||||||
|
|
||||||
--- #################### 数据库相关配置 ####################
|
--- #################### 数据库相关配置 ####################
|
||||||
spring:
|
spring:
|
||||||
|
|
||||||
# 数据源配置项
|
# 数据源配置项
|
||||||
autoconfigure:
|
autoconfigure:
|
||||||
exclude:
|
exclude:
|
||||||
|
|||||||
@@ -106,3 +106,20 @@ msgpush:
|
|||||||
|
|
||||||
|
|
||||||
debug: false
|
debug: false
|
||||||
|
aliyun:
|
||||||
|
sms:
|
||||||
|
access-key-id: LTAI4FxsR76x2dq3w9c5puUe
|
||||||
|
access-key-secret: GxkTR8fsrvHtixTlD9UPmOGli35tZs
|
||||||
|
regionId: cn-hangzhou
|
||||||
|
endpoint: dysmsapi.aliyuncs.com
|
||||||
|
mail:
|
||||||
|
access-key-id: LTAI4FxsR76x2dq3w9c5puUe
|
||||||
|
access-key-secret: GxkTR8fsrvHtixTlD9UPmOGli35tZs
|
||||||
|
regionId: cn-hangzhou
|
||||||
|
endpoint: dm.aliyuncs.com
|
||||||
|
|
||||||
|
telecom:
|
||||||
|
sms:
|
||||||
|
account: 925631
|
||||||
|
password: AMW2pOVrdky
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,9 +9,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|||||||
* @author hongawen
|
* @author hongawen
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("SpringComponentScan") // 忽略 IDEA 无法识别 ${msgpush.info.base-package}
|
@SuppressWarnings("SpringComponentScan") // 忽略 IDEA 无法识别 ${msgpush.info.base-package}
|
||||||
@SpringBootApplication(scanBasePackages = {"${msgpush.info.base-package}.server", "${msgpush.info.base-package}.module"},
|
@SpringBootApplication(scanBasePackages = {"${msgpush.info.base-package}.server", "${msgpush.info.base-package}.module"}, excludeName = {})
|
||||||
excludeName = {
|
|
||||||
})
|
|
||||||
public class MsgpushServerApplication {
|
public class MsgpushServerApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
Reference in New Issue
Block a user