From 225664550f3cd23b4c26a9aded828cf39c2ec0eb Mon Sep 17 00:00:00 2001 From: zengzefeng <986510453@qq.com> Date: Fri, 12 Mar 2021 11:32:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E7=9F=AD=E4=BF=A1=E9=80=9A?= =?UTF-8?q?=E8=BF=87redis=20stream=E5=BC=82=E6=AD=A5=E5=8F=91=E9=80=81?= =?UTF-8?q?=EF=BC=8C=E5=AE=9E=E7=8E=B0=E7=9F=AD=E4=BF=A1callback=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/sms.sql | 19 +- .../dashboard/DashboardApplication.java | 30 +-- .../redis/core/util/RedisStreamUtils.java | 29 +++ .../config/SecurityConfiguration.java | 1 + .../sms/client/AbstractSmsClient.java | 18 +- .../framework/sms/client/AliyunSmsClient.java | 113 ---------- .../sms/client/HadCallbackSmsClient.java | 25 --- .../client/NeedQuerySendResultSmsClient.java | 24 -- .../framework/sms/client/SmsClient.java | 13 +- .../sms/client/impl/ali/AliyunSmsClient.java | 212 ++++++++++++++++++ .../{ => impl/yunpian}/YunpianSmsClient.java | 102 ++++++--- .../framework/sms/core/SmsClientFactory.java | 31 ++- .../framework/sms/core/SmsResult.java | 5 - .../framework/sms/core/SmsResultDetail.java | 10 + .../sms/core/enums/SmsChannelEnum.java | 2 +- .../controller/redis/RedisController.java | 136 +++++------ .../sms/SmsDefaultCallbackController.java | 32 ++- .../mysql/dao/sms/SysSmsQueryLogMapper.java | 13 +- .../mysql/dataobject/sms/SysSmsChannelDO.java | 5 - .../dataobject/sms/SysSmsQueryLogDO.java | 26 +-- .../system/dal/redis/RedisKeyConstants.java | 2 +- .../mq/consumer/sms/SmsSendConsumer.java | 41 ---- .../system/mq/message/sms/SmsSendMessage.java | 25 --- .../system/mq/producer/sms/SmsProducer.java | 32 --- .../consumer/dept/SysDeptRefreshConsumer.java | 4 +- .../dict/SysDictDataRefreshConsumer.java | 4 +- .../permission/SysMenuRefreshConsumer.java | 4 +- .../SysRoleMenuRefreshConsumer.java | 4 +- .../permission/SysRoleRefreshConsumer.java | 4 +- .../mq/consumer/sms/SmsSendConsumer.java | 56 +++++ .../message/dept/SysDeptRefreshMessage.java | 2 +- .../dict/SysDictDataRefreshMessage.java | 2 +- .../permission/SysMenuRefreshMessage.java | 2 +- .../permission/SysRoleMenuRefreshMessage.java | 2 +- .../permission/SysRoleRefreshMessage.java | 2 +- .../mq/producer/dept/SysDeptProducer.java | 4 +- .../mq/producer/dict/SysDictDataProducer.java | 4 +- .../producer/permission/SysMenuProducer.java | 4 +- .../permission/SysPermissionProducer.java | 4 +- .../producer/permission/SysRoleProducer.java | 4 +- .../redis/mq/producer/sms/SmsProducer.java | 31 +++ .../redis/stream/StreamConsumerRunner.java | 93 ++++++++ .../redis/stream/sms/SmsSendMessage.java | 16 ++ .../stream/sms/SmsSendStreamConsumer.java | 43 ++++ .../stream/sms/SmsSendStreamProducer.java | 35 +++ .../service/dept/impl/SysDeptServiceImpl.java | 2 +- .../dict/impl/SysDictDataServiceImpl.java | 2 +- .../permission/impl/SysMenuServiceImpl.java | 2 +- .../impl/SysPermissionServiceImpl.java | 2 +- .../permission/impl/SysRoleServiceImpl.java | 2 +- .../service/sms/SysSmsChannelService.java | 2 + .../service/sms/SysSmsQueryLogService.java | 10 +- .../system/service/sms/SysSmsService.java | 21 +- .../sms/impl/SysSmsQueryLogServiceImpl.java | 26 ++- .../sms/impl/SysSmsSendLogServiceImpl.java | 5 +- .../service/sms/impl/SysSmsServiceImpl.java | 25 ++- 56 files changed, 877 insertions(+), 492 deletions(-) create mode 100644 src/main/java/cn/iocoder/dashboard/framework/redis/core/util/RedisStreamUtils.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/client/HadCallbackSmsClient.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/client/NeedQuerySendResultSmsClient.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/ali/AliyunSmsClient.java rename src/main/java/cn/iocoder/dashboard/framework/sms/client/{ => impl/yunpian}/YunpianSmsClient.java (53%) delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SmsSendMessage.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/consumer/dept/SysDeptRefreshConsumer.java (82%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/consumer/dict/SysDictDataRefreshConsumer.java (82%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/consumer/permission/SysMenuRefreshConsumer.java (81%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/consumer/permission/SysRoleMenuRefreshConsumer.java (82%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/consumer/permission/SysRoleRefreshConsumer.java (81%) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/sms/SmsSendConsumer.java rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/message/dept/SysDeptRefreshMessage.java (81%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/message/dict/SysDictDataRefreshMessage.java (82%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/message/permission/SysMenuRefreshMessage.java (80%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/message/permission/SysRoleMenuRefreshMessage.java (81%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/message/permission/SysRoleRefreshMessage.java (80%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/producer/dept/SysDeptProducer.java (80%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/producer/dict/SysDictDataProducer.java (80%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/producer/permission/SysMenuProducer.java (79%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/producer/permission/SysPermissionProducer.java (79%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/producer/permission/SysRoleProducer.java (79%) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/sms/SmsProducer.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/StreamConsumerRunner.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendMessage.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamConsumer.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamProducer.java diff --git a/sql/sms.sql b/sql/sms.sql index 027052779..6d9c3c8e5 100644 --- a/sql/sms.sql +++ b/sql/sms.sql @@ -12,7 +12,6 @@ CREATE TABLE `sms_channel` `code` varchar(50) NOT NULL COMMENT '编码(来自枚举类 阿里、华为、七牛等)', `api_key` varchar(100) NOT NULL COMMENT '账号id', `api_secret` varchar(100) NOT NULL COMMENT '账号秘钥', - `had_callback` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否拥有回调函数', `callback_url` varchar(100) NOT NULL default '' COMMENT '回调请求路径', `api_signature_id` varchar(100) NOT NULL COMMENT '实际渠道签名唯一标识', `name` varchar(50) NOT NULL COMMENT '名称', @@ -61,7 +60,7 @@ CREATE TABLE `sms_template` ) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT ='短信模板'; - +/* -- ---------------------------- -- Table structure for sms_query_log -- ---------------------------- @@ -73,7 +72,7 @@ CREATE TABLE `sms_query_log` `channel_code` varchar(50) NOT NULL COMMENT '短信渠道编码(来自枚举类)', `channel_id` bigint(20) NOT NULL COMMENT '短信渠道id', `template_code` varchar(50) NOT NULL COMMENT '渠道编码', - `phones` varchar(2000) NOT NULL COMMENT '手机号(数组json字符串)', + `phone` char(11) NOT NULL COMMENT '手机号', `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', `send_result_param` varchar(200) NOT NULL DEFAULT '' COMMENT '查询短信发送结果的参数', `send_status` tinyint(1) NOT NULL DEFAULT 2 COMMENT '发送状态(0本地异步中 1发送请求失败 2发送请求成功)', @@ -84,24 +83,26 @@ CREATE TABLE `sms_query_log` PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 - DEFAULT CHARSET = utf8mb4 COMMENT ='短信请求日志'; + DEFAULT CHARSET = utf8mb4 COMMENT ='短信请求日志';*/ -- ---------------------------- -- Table structure for sms_log -- ---------------------------- -DROP TABLE IF EXISTS `sms_send_log`; -CREATE TABLE `sms_send_log` +DROP TABLE IF EXISTS `sms_query_log`; +CREATE TABLE `sms_query_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', + `api_id` varchar(100) NOT NULL COMMENT '第三方唯一标识', `channel_code` varchar(50) NOT NULL COMMENT '短信渠道编码(来自枚举类)', `channel_id` bigint(20) NOT NULL COMMENT '短信渠道id', `template_code` varchar(50) NOT NULL COMMENT '渠道编码', - `query_log_id` bigint(20) NOT NULL COMMENT '请求日志id', `phone` char(11) NOT NULL COMMENT '手机号', `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', + `send_status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '发送状态 详情见:SmsSendStatusEnum', `remark` varchar(200) DEFAULT NULL COMMENT '备注', - `success` tinyint(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', - `send_time` datetime DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(64) NOT NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `send_time` datetime DEFAULT NULL COMMENT '发送时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 diff --git a/src/main/java/cn/iocoder/dashboard/DashboardApplication.java b/src/main/java/cn/iocoder/dashboard/DashboardApplication.java index 498bf63c7..32783aa8c 100644 --- a/src/main/java/cn/iocoder/dashboard/DashboardApplication.java +++ b/src/main/java/cn/iocoder/dashboard/DashboardApplication.java @@ -1,15 +1,15 @@ -//package cn.iocoder.dashboard; -// -//import de.codecentric.boot.admin.server.config.EnableAdminServer; -//import org.springframework.boot.SpringApplication; -//import org.springframework.boot.autoconfigure.SpringBootApplication; -// -//@SpringBootApplication -//@EnableAdminServer -//public class DashboardApplication { -// -// public static void main(String[] args) { -// SpringApplication.run(DashboardApplication.class, args); -// } -// -//} +package cn.iocoder.dashboard; + +import de.codecentric.boot.admin.server.config.EnableAdminServer; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@EnableAdminServer +public class DashboardApplication { + + public static void main(String[] args) { + SpringApplication.run(DashboardApplication.class, args); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/redis/core/util/RedisStreamUtils.java b/src/main/java/cn/iocoder/dashboard/framework/redis/core/util/RedisStreamUtils.java new file mode 100644 index 000000000..590c84209 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/redis/core/util/RedisStreamUtils.java @@ -0,0 +1,29 @@ +package cn.iocoder.dashboard.framework.redis.core.util; + +import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendMessage; +import org.springframework.data.redis.connection.stream.StreamRecords; +import org.springframework.data.redis.core.RedisTemplate; + +/** + * Redis 消息工具类 + * + * @author 芋道源码 + */ +public class RedisStreamUtils { + + public static final String KEY_SMS_SEND = "stream_sms_send"; + + public static final String GROUP_SMS_SEND = "group_sms_send"; + + /** + * 发送 Redis 消息,基于 Redis pub/sub 实现 + * + * @param redisTemplate Redis 操作模板 + * @param message 消息 + */ + public static void sendChannelMessage(RedisTemplate redisTemplate, SmsSendMessage message) { + + redisTemplate.opsForStream().add(StreamRecords.newRecord().ofObject(message).withStreamKey(KEY_SMS_SEND)); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java b/src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java index 2898023e2..7b853ce35 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java +++ b/src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java @@ -134,6 +134,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { .antMatchers(webProperties.getApiPrefix() + "/system/file/get/**").anonymous() // TODO .antMatchers("/swagger-ui.html").anonymous() + .antMatchers("/**").anonymous() .antMatchers("/swagger-resources/**").anonymous() .antMatchers("/webjars/**").anonymous() .antMatchers("/*/api-docs").anonymous() diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java index 150b994bb..fbeceea10 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java @@ -5,8 +5,6 @@ import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import lombok.extern.slf4j.Slf4j; -import java.util.Collection; - /** * 抽象短息客户端 * @@ -35,12 +33,12 @@ public abstract class AbstractSmsClient implements SmsClient { } @Override - public final SmsResult send(String templateApiId, SmsBody smsBody, Collection targets) { + public final SmsResult send(String templateApiId, SmsBody smsBody, String target) { SmsResult result; try { - beforeSend(templateApiId, smsBody, targets); - result = doSend(templateApiId, smsBody, targets); - afterSend(templateApiId, smsBody, targets, result); + beforeSend(templateApiId, smsBody, target); + result = doSend(templateApiId, smsBody, target); + afterSend(templateApiId, smsBody, target, result); } catch (Exception e) { // exception handle log.debug(e.getMessage(), e); @@ -54,16 +52,16 @@ public abstract class AbstractSmsClient implements SmsClient { * * @param templateApiId 短信模板唯一标识 * @param smsBody 消息内容 - * @param targets 发送对象列表 + * @param targetPhone 发送对象手机号 * @return 短信发送结果 * @throws Exception 调用发送失败,抛出异常 */ - protected abstract SmsResult doSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception; + protected abstract SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception; - protected void beforeSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception { + protected void beforeSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception { } - protected void afterSend(String templateApiId, SmsBody smsBody, Collection targets, SmsResult result) throws Exception { + protected void afterSend(String templateApiId, SmsBody smsBody, String targetPhone, SmsResult result) throws Exception { } } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java deleted file mode 100644 index fff2d162d..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java +++ /dev/null @@ -1,113 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.client; - -import cn.hutool.core.date.DateUtil; -import cn.hutool.core.util.ArrayUtil; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; -import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; -import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; -import com.aliyuncs.DefaultAcsClient; -import com.aliyuncs.IAcsClient; -import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest; -import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse; -import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; -import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; -import com.aliyuncs.exceptions.ClientException; -import com.aliyuncs.http.MethodType; -import com.aliyuncs.profile.DefaultProfile; -import com.aliyuncs.profile.IClientProfile; -import lombok.extern.slf4j.Slf4j; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -/** - * 阿里短信实现类 - * - * @author zzf - * @date 2021/1/25 14:17 - */ -@Slf4j -public class AliyunSmsClient extends AbstractSmsClient implements NeedQuerySendResultSmsClient { - - private static final String OK = "OK"; - - private static final String PRODUCT = "Dysmsapi"; - - private static final String DOMAIN = "dysmsapi.aliyuncs.com"; - - private static final String ENDPOINT = "cn-hangzhou"; - - private final IAcsClient acsClient; - - /** - * 构造阿里云短信发送处理 - * - * @param channelVO 阿里云短信配置 - */ - public AliyunSmsClient(SmsChannelProperty channelVO) { - super(channelVO); - - String accessKeyId = channelVO.getApiKey(); - String accessKeySecret = channelVO.getApiSecret(); - - IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, accessKeyId, accessKeySecret); - DefaultProfile.addEndpoint(ENDPOINT, PRODUCT, DOMAIN); - - acsClient = new DefaultAcsClient(profile); - } - - @Override - public SmsResult doSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception { - SendSmsRequest request = new SendSmsRequest(); - request.setSysMethod(MethodType.POST); - request.setPhoneNumbers(ArrayUtil.join(targets, ",")); - request.setSignName(channelVO.getApiSignatureId()); - request.setTemplateCode(templateApiId); - request.setTemplateParam(smsBody.getParamsStr()); - SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); - - boolean success = OK.equals(sendSmsResponse.getCode()); - if (!success) { - log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage()); - } - return new SmsResult() - .setSuccess(success) - .setMessage(sendSmsResponse.getMessage()) - .setCode(sendSmsResponse.getCode()) - .setApiId(sendSmsResponse.getBizId()) - .setSendResultParam(sendSmsResponse.getBizId()); - } - - - @Override - public List getSmsSendResult(String param) throws ClientException { - QuerySendDetailsRequest querySendDetailsRequest = new QuerySendDetailsRequest(); - querySendDetailsRequest.setBizId(param); - // TODO FROM 芋艿 to zzf:发送完之后,基于短信平台回调,去更新回执状态。短信发送是否成功,和最终用户收到,是两个维度。这块有困惑,可以微信,我给个截图哈。 DONE - QuerySendDetailsResponse acsResponse = acsClient.getAcsResponse(querySendDetailsRequest); - List resultDetailList = new ArrayList<>(Integer.parseInt(acsResponse.getTotalCount())); - acsResponse.getSmsSendDetailDTOs().forEach(s -> { - SmsResultDetail resultDetail = new SmsResultDetail(); - resultDetail.setSendTime(DateUtil.parseDateTime(s.getSendDate())); - resultDetail.setMessage(s.getContent()); - resultDetail.setPhone(s.getPhoneNum()); - resultDetail.setSendStatus(statusConvert(s.getSendStatus())); - resultDetailList.add(resultDetail); - }); - return resultDetailList; - } - - private int statusConvert(Long aliSendStatus) { - if (aliSendStatus == 1L) { - return SmsSendStatusEnum.SEND_SUCCESS.getStatus(); - } - if (aliSendStatus == 2L) { - return SmsSendStatusEnum.SEND_FAIL.getStatus(); - } - return SmsSendStatusEnum.WAITING.getStatus(); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/HadCallbackSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/HadCallbackSmsClient.java deleted file mode 100644 index 1df4261d3..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/HadCallbackSmsClient.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.client; - -import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; - -import javax.servlet.ServletRequest; -import java.io.UnsupportedEncodingException; -import java.util.List; - -/** - * 需要发送请求获取短信发送结果的短信客户端 - * - * @author zzf - * @date 2021/3/4 17:20 - */ -public interface HadCallbackSmsClient { - - /** - * 获取短信发送结果 - * - * @param request 请求 - * @return 短信发送结果 - */ - List getSmsSendResult(ServletRequest request) throws Exception; - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/NeedQuerySendResultSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/NeedQuerySendResultSmsClient.java deleted file mode 100644 index 37352235f..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/NeedQuerySendResultSmsClient.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.client; - -import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; -import com.aliyuncs.exceptions.ClientException; - -import java.util.List; - -/** - * 需要发送请求获取短信发送结果的短信客户端 - * - * @author zzf - * @date 2021/3/4 17:20 - */ -public interface NeedQuerySendResultSmsClient { - - /** - * 获取短信发送结果 - * - * @param param 参数 - * @return 短信发送结果 - */ - List getSmsSendResult(String param) throws Exception; - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java index 803e3b16f..b3861f159 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java @@ -4,8 +4,7 @@ import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; -import java.util.Collection; -import java.util.List; +import javax.servlet.ServletRequest; /** * 短信父接口 @@ -23,9 +22,15 @@ public interface SmsClient { * @param targets 发送对象列表 * @return 短信发送结果 */ - SmsResult send(String templateApiId, SmsBody smsBody, Collection targets); + SmsResult send(String templateApiId, SmsBody smsBody, String targets); - //List getSmsSendResult(String jsonObjectParam); + /** + * 短信发送回调请求处理 + * + * @param request 请求 + * @return 短信发送结果 + */ + SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws Exception; } \ No newline at end of file diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/ali/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/ali/AliyunSmsClient.java new file mode 100644 index 000000000..49feb8dd2 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/ali/AliyunSmsClient.java @@ -0,0 +1,212 @@ +package cn.iocoder.dashboard.framework.sms.client.impl.ali; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateUtil; +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; +import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; +import cn.iocoder.dashboard.util.json.JsonUtils; +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; +import com.aliyuncs.http.MethodType; +import com.aliyuncs.profile.DefaultProfile; +import com.aliyuncs.profile.IClientProfile; +import com.fasterxml.jackson.core.type.TypeReference; +import lombok.extern.slf4j.Slf4j; + +import javax.servlet.ServletRequest; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 阿里短信实现类 + * + * @author zzf + * @date 2021/1/25 14:17 + */ +@Slf4j +public class AliyunSmsClient extends AbstractSmsClient { + + private static final String OK = "OK"; + + private static final String PRODUCT = "Dystopi"; + + private static final String DOMAIN = "dysmsapi.aliyuncs.com"; + + private static final String ENDPOINT = "cn-hangzhou"; + + private final IAcsClient acsClient; + + /** + * 构造阿里云短信发送处理 + * + * @param channelVO 阿里云短信配置 + */ + public AliyunSmsClient(SmsChannelProperty channelVO) { + super(channelVO); + + String accessKeyId = channelVO.getApiKey(); + String accessKeySecret = channelVO.getApiSecret(); + + IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, accessKeyId, accessKeySecret); + DefaultProfile.addEndpoint(ENDPOINT, PRODUCT, DOMAIN); + + acsClient = new DefaultAcsClient(profile); + } + + @Override + public SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception { + SendSmsRequest request = new SendSmsRequest(); + request.setSysMethod(MethodType.POST); + request.setPhoneNumbers(targetPhone); + request.setSignName(channelVO.getApiSignatureId()); + request.setTemplateCode(templateApiId); + request.setTemplateParam(smsBody.getParamsStr()); + SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); + + boolean success = OK.equals(sendSmsResponse.getCode()); + if (!success) { + log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage()); + } + return new SmsResult() + .setSuccess(success) + .setMessage(sendSmsResponse.getMessage()) + .setCode(sendSmsResponse.getCode()) + .setApiId(sendSmsResponse.getBizId()); + } + + /** + * [{ + * "send_time" : "2017-08-30 00:00:00", + * "report_time" : "2017-08-30 00:00:00", + * "success" : true, + * "err_msg" : "用户接收成功", + * "err_code" : "DELIVERED", + * "phone_number" : "18612345678", + * "sms_size" : "1", + * "biz_id" : "932702304080415357^0", + * "out_id" : "1184585343" + * }] + * + * @param request 请求 + * @return + * @throws Exception + */ + @Override + public SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws Exception { + BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); + String paramStr = reader.readLine(); + List> params = JsonUtils.parseByType(paramStr, new TypeReference>>() { + }); + if (CollectionUtil.isNotEmpty(params)) { + Map sendResultParamMap = params.get(0); + return CallbackHelper.of(sendResultParamMap).toResultDetail(); + } + return null; + } + + /** + * 短信发送回调辅助类 + */ + private static class CallbackHelper { + + private final Map sendResultParamMap; + + private CallbackHelper(Map sendResultParamMap) { + this.sendResultParamMap = sendResultParamMap; + } + + public static CallbackHelper of(Map sendResultParamMap) { + return new CallbackHelper(sendResultParamMap); + } + + public Integer getSendStatus() { + return ((Boolean) sendResultParamMap.get(CallbackField.SUCCESS)) + ? SmsSendStatusEnum.SEND_SUCCESS.getStatus() + : SmsSendStatusEnum.SEND_FAIL.getStatus(); + } + + public String getBizId() { + return sendResultParamMap.get(CallbackField.BIZ_ID).toString(); + } + + public String getErrMsg() { + return sendResultParamMap.get(CallbackField.ERR_MSG).toString(); + } + + public String getErrCode() { + return sendResultParamMap.get(CallbackField.ERR_CODE).toString(); + } + + public Date getSendTime() { + return DateUtil.parseTime(sendResultParamMap.get(CallbackField.SEND_TIME).toString()); + } + + public String getPhoneNumber() { + return sendResultParamMap.get(CallbackField.PHONE_NUMBER).toString(); + } + + public String getOutId() { + return sendResultParamMap.get(CallbackField.OUT_ID).toString(); + } + + public SmsResultDetail toResultDetail() { + SmsResultDetail resultDetail = new SmsResultDetail(); + resultDetail.setSendStatus(getSendStatus()); + resultDetail.setApiId(getBizId()); + resultDetail.setSendTime(getSendTime()); + resultDetail.setPhone(getPhoneNumber()); + resultDetail.setMessage(getErrMsg()); + + resultDetail.setCallbackResponseBody(generateSuccessResponseBody()); + return resultDetail; + } + + /** + * 生成回调成功的返回对象 + */ + private Map generateSuccessResponseBody() { + Map result = new HashMap<>(); + result.put("code", 0); + result.put("msg", "成功"); + return result; + } + + } + + /** + * 回调接口字段定义 + */ + private interface CallbackField { + //是否成功 boolean + String SUCCESS = "success"; + + //发送时间 + String SEND_TIME = "send_time"; + + //错误信息 + String ERR_MSG = "err_msg"; + + //错误编码 + String ERR_CODE = "err_code"; + + //手机号 + String PHONE_NUMBER = "phone_number"; + + //用户序列号 out_id + String OUT_ID = "out_id"; + + //biz_id 即 apiId 唯一标识 + String BIZ_ID = "biz_id"; + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/yunpian/YunpianSmsClient.java similarity index 53% rename from src/main/java/cn/iocoder/dashboard/framework/sms/client/YunpianSmsClient.java rename to src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/yunpian/YunpianSmsClient.java index 77cd45f06..72b03a45e 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/YunpianSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/yunpian/YunpianSmsClient.java @@ -1,7 +1,9 @@ -package cn.iocoder.dashboard.framework.sms.client; +package cn.iocoder.dashboard.framework.sms.client.impl.yunpian; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.CharsetUtil; +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsConstants; import cn.iocoder.dashboard.framework.sms.core.SmsResult; @@ -14,13 +16,15 @@ import com.yunpian.sdk.YunpianClient; import com.yunpian.sdk.constant.Code; import com.yunpian.sdk.constant.YunpianConstant; import com.yunpian.sdk.model.Result; -import com.yunpian.sdk.model.SmsBatchSend; +import com.yunpian.sdk.model.SmsSingleSend; import lombok.extern.slf4j.Slf4j; import javax.servlet.ServletRequest; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * 云片短信实现类 @@ -29,7 +33,7 @@ import java.util.*; * @date 9:48 2021/3/5 */ @Slf4j -public class YunpianSmsClient extends AbstractSmsClient implements HadCallbackSmsClient { +public class YunpianSmsClient extends AbstractSmsClient { private final YunpianClient client; @@ -47,14 +51,14 @@ public class YunpianSmsClient extends AbstractSmsClient implements HadCallbackSm } @Override - public SmsResult doSend(String templateApiId, SmsBody smsBody, Collection targets) { + public SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) { Map paramMap = new HashMap<>(); - paramMap.put("apikey", getProperty().getApiKey()); - paramMap.put("mobile", String.join(SmsConstants.COMMA, targets)); - paramMap.put("text", formatContent(smsBody)); - paramMap.put("callback", getProperty().getCallbackUrl()); + paramMap.put(YunpianConstant.APIKEY, getProperty().getApiKey()); + paramMap.put(YunpianConstant.MOBILE, String.join(SmsConstants.COMMA, targetPhone)); + paramMap.put(YunpianConstant.TEXT, formatContent(smsBody)); + paramMap.put(Helper.CALLBACK, getProperty().getCallbackUrl()); - Result sendResult = client.sms().batch_send(paramMap); + Result sendResult = client.sms().single_send(paramMap); boolean success = sendResult.getCode().equals(Code.OK); if (!success) { @@ -64,7 +68,7 @@ public class YunpianSmsClient extends AbstractSmsClient implements HadCallbackSm .setSuccess(success) .setMessage(sendResult.getDetail()) .setCode(sendResult.getCode().toString()) - .setApiId(sendResult.getData().getData().get(0).getSid().toString()); + .setApiId(sendResult.getData().getSid().toString()); } @@ -96,26 +100,16 @@ public class YunpianSmsClient extends AbstractSmsClient implements HadCallbackSm } + /** + * 云片的比较复杂,又是加密又是套娃的 + */ @Override - public List getSmsSendResult(ServletRequest request) throws UnsupportedEncodingException { - List> stringStringMap = getSendResult(request); - List resultDetailList = new ArrayList<>(stringStringMap.size()); - stringStringMap.forEach(map -> { - SmsResultDetail detail = new SmsResultDetail(); - - detail.setPhone(map.get("mobile")); - detail.setMessage(map.get("error_msg")); - detail.setSendTime(DateUtil.parseTime(map.get("user_receive_time"))); - String reportStatus = map.get("report_status"); - detail.setSendStatus(reportStatus.equals(SmsConstants.SUCCESS) - ? SmsSendStatusEnum.SEND_SUCCESS.getStatus() - : SmsSendStatusEnum.SEND_FAIL.getStatus() - ); - resultDetailList.add(detail); - }); - return resultDetailList; + public SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws UnsupportedEncodingException { + Map map = getRequestParams(request); + return Helper.getSmsResultDetailByParam(map); } + /** * 从 request 中获取请求中传入的短信发送结果信息 * @@ -123,10 +117,58 @@ public class YunpianSmsClient extends AbstractSmsClient implements HadCallbackSm * @return 短信发送结果信息 * @throws UnsupportedEncodingException 解码异常 */ - private List> getSendResult(ServletRequest request) throws UnsupportedEncodingException { + private Map getRequestParams(ServletRequest request) throws UnsupportedEncodingException { Map parameterMap = request.getParameterMap(); String[] smsStatuses = parameterMap.get(YunpianConstant.SMS_STATUS); String encode = URLEncoder.encode(smsStatuses[0], CharsetUtil.UTF_8); - return JsonUtils.parseByType(encode, callbackType); + List> paramList = JsonUtils.parseByType(encode, callbackType); + if (CollectionUtil.isNotEmpty(paramList)) { + return paramList.get(0); + } + throw new IllegalArgumentException("YunpianSmsClient getRequestParams fail! can't format RequestParam: " + + JsonUtils.toJsonString(request.getParameterMap())); + } + + /** + * 云片的回调函数的一些辅助方法 + */ + private static class Helper { + + //短信唯一标识 + private final static String API_ID = "sid"; + + //回调地址· + private final static String CALLBACK = "callback"; + + //手机号 + private final static String MOBILE = "mobile"; + + //错误信息 + private final static String ERROR_MSG = "error_msg"; + + //用户接收时间 字符串 标准格式 + private final static String USER_RECEIVE_TIME = "user_receive_time"; + + //发送状态 + private final static String REPORT_STATUS = "report_status"; + + private static int getSendStatus(Map map) { + String reportStatus = map.get(REPORT_STATUS); + return SmsConstants.SUCCESS.equals(reportStatus) + ? SmsSendStatusEnum.SEND_SUCCESS.getStatus() + : SmsSendStatusEnum.SEND_FAIL.getStatus(); + } + + public static SmsResultDetail getSmsResultDetailByParam(Map map) { + SmsResultDetail detail = new SmsResultDetail(); + detail.setPhone(map.get(MOBILE)); + detail.setMessage(map.get(ERROR_MSG)); + detail.setSendTime(DateUtil.parseTime(map.get(USER_RECEIVE_TIME))); + detail.setSendStatus(getSendStatus(map)); + detail.setApiId(API_ID); + + detail.setCallbackResponseBody(SmsConstants.SUCCESS); + return detail; + } } } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java index 88c02cb87..b4b4428ec 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java @@ -2,12 +2,15 @@ package cn.iocoder.dashboard.framework.sms.core; import cn.iocoder.dashboard.common.exception.ServiceException; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.client.AliyunSmsClient; +import cn.iocoder.dashboard.framework.sms.client.impl.ali.AliyunSmsClient; +import cn.iocoder.dashboard.framework.sms.client.impl.yunpian.YunpianSmsClient; import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import cn.iocoder.dashboard.framework.sms.core.property.SmsTemplateProperty; +import cn.iocoder.dashboard.util.json.JsonUtils; import org.springframework.stereotype.Component; +import javax.servlet.ServletRequest; import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -54,6 +57,8 @@ public class SmsClientFactory { switch (channelEnum) { case ALI: return new AliyunSmsClient(channelVO); + case YUN_PIAN: + return new YunpianSmsClient(channelVO); // TODO fill more channel default: break; @@ -102,4 +107,28 @@ public class SmsClientFactory { return smsTemplateProperty.getApiTemplateId(); } + + /** + * 从短信发送回调函数请求中获取用于唯一确定一条send_lod的apiId + * + * @param callbackRequest 短信发送回调函数请求 + * @return 第三方平台短信唯一标识 + */ + public SmsResultDetail getSmsResultDetailFromCallbackQuery(ServletRequest callbackRequest) { + + for (Long channelId : smsSenderMap.keySet()) { + AbstractSmsClient smsClient = smsSenderMap.get(channelId); + try { + SmsResultDetail smsSendResult = smsClient.smsSendCallbackHandle(callbackRequest); + if (smsSendResult != null) { + return smsSendResult; + } + } catch (Exception ignored) { + } + } + throw new IllegalArgumentException("getSmsResultDetailFromCallbackQuery fail! don't match SmsClient by RequestParam: " + + JsonUtils.toJsonString(callbackRequest.getParameterMap())); + } + + } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java index 694005482..228630348 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java @@ -32,11 +32,6 @@ public class SmsResult implements Serializable { */ private String message; - /** - * 用于查询发送结果的参数 - */ - private String sendResultParam; - public static SmsResult failResult(String message) { SmsResult resultBody = new SmsResult(); resultBody.setSuccess(false); diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java index fcca0a0be..aab4af217 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java @@ -11,6 +11,11 @@ import java.util.Date; @Data public class SmsResultDetail implements Serializable { + /** + * 唯一标识 + */ + private String apiId; + /** * 短信发送状态 {@link cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum} */ @@ -30,4 +35,9 @@ public class SmsResultDetail implements Serializable { * 时间 */ private Date sendTime; + + /** + * 接口返回值 + */ + private Object callbackResponseBody; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java index 255a705fd..0265f455e 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java @@ -14,8 +14,8 @@ import lombok.Getter; public enum SmsChannelEnum { ALI("ALI", "阿里"), + YUN_PIAN("YUN_PIAN", "云片"), HUA_WEI("HUA_WEI", "华为"), - QI_NIU("QI_NIU", "七牛"), TENCENT("TENCENT", "腾讯"); private final String code; diff --git a/src/main/java/cn/iocoder/dashboard/modules/infra/controller/redis/RedisController.java b/src/main/java/cn/iocoder/dashboard/modules/infra/controller/redis/RedisController.java index b40f95aea..d089d2ccc 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/infra/controller/redis/RedisController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/infra/controller/redis/RedisController.java @@ -1,68 +1,68 @@ -package cn.iocoder.dashboard.modules.infra.controller.redis; - -import cn.hutool.core.util.StrUtil; -import cn.iocoder.dashboard.common.pojo.CommonResult; -import cn.iocoder.dashboard.framework.redis.core.RedisKeyRegistry; -import cn.iocoder.dashboard.modules.infra.controller.redis.vo.InfRedisKeyRespVO; -import cn.iocoder.dashboard.modules.infra.controller.redis.vo.InfRedisMonitorRespVO; -import org.springframework.data.redis.connection.RedisServerCommands; -import org.springframework.data.redis.core.RedisCallback; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; -import java.util.stream.Collectors; - -import static cn.iocoder.dashboard.common.pojo.CommonResult.success; - -@RestController -@RequestMapping("/infra/redis") -public class RedisController { - - @Resource - private StringRedisTemplate stringRedisTemplate; - -// @PreAuthorize("@ss.hasPermission('infra:redis:get-monitor-info')") - @GetMapping("/get-monitor-info") - public CommonResult getRedisMonitorInfo() { - // 获得 Redis 统计信息 - Properties info = stringRedisTemplate.execute((RedisCallback) RedisServerCommands::info); - Long dbSize = stringRedisTemplate.execute(RedisServerCommands::dbSize); - Properties commandStats = stringRedisTemplate.execute(( - RedisCallback) connection -> connection.info("commandstats")); - assert commandStats != null; // 断言,避免警告 - - // 拼接结果返回 - InfRedisMonitorRespVO respVO = InfRedisMonitorRespVO.builder().info(info).dbSize(dbSize) - .commandStats(new ArrayList<>(commandStats.size())).build(); - commandStats.forEach((key, value) -> { - respVO.getCommandStats().add(InfRedisMonitorRespVO.CommandStat.builder() - .command(StrUtil.subAfter((String) key, "cmdstat_", false)) - .calls(Integer.valueOf(StrUtil.subBetween((String) value, "calls=", ","))) - .usec(Integer.valueOf(StrUtil.subBetween((String) value, "usec=", ","))) - .build()); - }); - return success(respVO); - } - -// @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')") - @GetMapping("/get-key-list") - public CommonResult> getKeyList() { - List respVOList = RedisKeyRegistry.list().stream() - .map(define -> InfRedisKeyRespVO.builder() - .keyTemplate(define.getKeyTemplate()) - .keyType(define.getKeyType().name()) - .valueType(define.getValueType().getName()) - .timeoutType(define.getTimeoutType().getType()) - .timeout((int) define.getTimeout().getSeconds()) - .build()) - .collect(Collectors.toList()); - return success(respVOList); - } - -} +//package cn.iocoder.dashboard.modules.infra.controller.redis; +// +//import cn.hutool.core.util.StrUtil; +//import cn.iocoder.dashboard.common.pojo.CommonResult; +//import cn.iocoder.dashboard.framework.redis.core.RedisKeyRegistry; +//import cn.iocoder.dashboard.modules.infra.controller.redis.vo.InfRedisKeyRespVO; +//import cn.iocoder.dashboard.modules.infra.controller.redis.vo.InfRedisMonitorRespVO; +//import org.springframework.data.redis.connection.RedisServerCommands; +//import org.springframework.data.redis.core.RedisCallback; +//import org.springframework.data.redis.core.StringRedisTemplate; +//import org.springframework.web.bind.annotation.GetMapping; +//import org.springframework.web.bind.annotation.RequestMapping; +//import org.springframework.web.bind.annotation.RestController; +// +//import javax.annotation.Resource; +//import java.util.ArrayList; +//import java.util.List; +//import java.util.Properties; +//import java.util.stream.Collectors; +// +//import static cn.iocoder.dashboard.common.pojo.CommonResult.success; +// +//@RestController +//@RequestMapping("/infra/redis") +//public class RedisController { +// +// @Resource +// private StringRedisTemplate stringRedisTemplate; +// +//// @PreAuthorize("@ss.hasPermission('infra:redis:get-monitor-info')") +// @GetMapping("/get-monitor-info") +// public CommonResult getRedisMonitorInfo() { +// // 获得 Redis 统计信息 +// Properties info = stringRedisTemplate.execute((RedisCallback) RedisServerCommands::info); +// Long dbSize = stringRedisTemplate.execute(RedisServerCommands::dbSize); +// Properties commandStats = stringRedisTemplate.execute(( +// RedisCallback) connection -> connection.info("commandstats")); +// assert commandStats != null; // 断言,避免警告 +// +// // 拼接结果返回 +// InfRedisMonitorRespVO respVO = InfRedisMonitorRespVO.builder().info(info).dbSize(dbSize) +// .commandStats(new ArrayList<>(commandStats.size())).build(); +// commandStats.forEach((key, value) -> { +// respVO.getCommandStats().add(InfRedisMonitorRespVO.CommandStat.builder() +// .command(StrUtil.subAfter((String) key, "cmdstat_", false)) +// .calls(Integer.valueOf(StrUtil.subBetween((String) value, "calls=", ","))) +// .usec(Integer.valueOf(StrUtil.subBetween((String) value, "usec=", ","))) +// .build()); +// }); +// return success(respVO); +// } +// +//// @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')") +// @GetMapping("/get-key-list") +// public CommonResult> getKeyList() { +// List respVOList = RedisKeyRegistry.list().stream() +// .map(define -> InfRedisKeyRespVO.builder() +// .keyTemplate(define.getKeyTemplate()) +// .keyType(define.getKeyType().name()) +// .valueType(define.getValueType().getName()) +// .timeoutType(define.getTimeoutType().getType()) +// .timeout((int) define.getTimeout().getSeconds()) +// .build()) +// .collect(Collectors.toList()); +// return success(respVOList); +// } +// +//} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java index 94f0fc81d..0a33e8b0e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java @@ -1,11 +1,19 @@ package cn.iocoder.dashboard.modules.system.controller.sms; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendStreamProducer; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.servlet.ServletRequest; +import java.util.Arrays; +import java.util.Map; /** * 短信默认回调接口 @@ -13,15 +21,33 @@ import javax.servlet.ServletRequest; * @author zzf * @date 2021/3/5 8:59 */ -@RestController("/sms/callback") +@Api(tags = "短信回调api") +@RestController +@RequestMapping("/sms/callback") public class SmsDefaultCallbackController { @Resource private SysSmsService smsService; - @RequestMapping("/sms-send") - public Object sendSmsCallback(ServletRequest request){ + + @ApiOperation(value = "短信发送回调接口") + @PostMapping("/sms-send") + public Object sendSmsCallback(ServletRequest request) { return smsService.smsSendCallbackHandle(request); } +/* + @Resource + private SmsSendStreamProducer smsSendStreamProducer; + + @ApiOperation("redis stream测试") + @GetMapping("/test/redis/stream") + public void test() { + SmsBody smsBody = new SmsBody(); + smsBody.setSmsLogId(1L); + smsBody.setTemplateCode("sdf"); + smsBody.setTemplateContent("sdf"); + smsSendStreamProducer.sendSmsSendMessage(smsBody, "18216466755"); + }*/ + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsQueryLogMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsQueryLogMapper.java index 7472f481e..535afa667 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsQueryLogMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsQueryLogMapper.java @@ -14,14 +14,21 @@ public interface SysSmsQueryLogMapper extends BaseMapper { /** * 查询还没有获取发送结果的短信请求信息 - * - * @return */ default List selectNoResultQueryLogList() { return this.selectList(new LambdaQueryWrapper() .eq(SysSmsQueryLogDO::getSendStatus, SmsSendStatusEnum.QUERY_SUCCESS) .eq(SysSmsQueryLogDO::getGotResult, DefaultBitFieldEnum.NO) - .eq(SysSmsQueryLogDO::getHadCallback, DefaultBitFieldEnum.NO) ); } + + + /** + * 根据APIId修改对象 + */ + default boolean updateByApiId(SysSmsQueryLogDO queryLogDO, String apiId) { + return update(queryLogDO, new LambdaQueryWrapper() + .eq(SysSmsQueryLogDO::getApiId, apiId) + ) > 0; + } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java index 3f212dbda..d38c1bc07 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java @@ -27,11 +27,6 @@ public class SysSmsChannelDO extends BaseDO { */ private String code; - /** - * 是否拥有回答(0否 1是) - */ - private Integer had_callback; - /** * 短信发送回调url */ diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsQueryLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsQueryLogDO.java index fce137d2c..ebb170ded 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsQueryLogDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsQueryLogDO.java @@ -1,15 +1,12 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms; -import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; import java.io.Serializable; import java.util.Date; -import java.util.List; /** * 短信日志 @@ -28,6 +25,11 @@ public class SysSmsQueryLogDO implements Serializable { */ private Long id; + /** + * 第三方唯一标识 + */ + private String apiId; + /** * 短信渠道编码(来自枚举类) */ @@ -46,8 +48,7 @@ public class SysSmsQueryLogDO implements Serializable { /** * 手机号 */ - @TableField(typeHandler = JacksonTypeHandler.class) - private List phones; + private String phone; /** * 内容 @@ -66,16 +67,6 @@ public class SysSmsQueryLogDO implements Serializable { */ private Integer gotResult; - /** - * 是否拥有回调函数(0否 1是) - */ - private Integer hadCallback; - - /** - * 结果(对象json字符串) - */ - private String sendResultParam; - /** * 备注 */ @@ -91,4 +82,9 @@ public class SysSmsQueryLogDO implements Serializable { */ private Date createTime; + /** + * 发送时间 + */ + private Date sendTime; + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/RedisKeyConstants.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/RedisKeyConstants.java index c5ca44578..20f5aba32 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/RedisKeyConstants.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/RedisKeyConstants.java @@ -28,6 +28,6 @@ public interface RedisKeyConstants { * key 的 format 的参数是 uuid */ RedisKeyDefine CAPTCHA_CODE = new RedisKeyDefine("captcha_code:%s", STRING, String.class, - RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); + Duration.ofMinutes(30)); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java deleted file mode 100644 index f962bf372..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.dashboard.modules.system.mq.consumer.sms; - -import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; -import cn.iocoder.dashboard.modules.system.mq.message.dept.SysDeptRefreshMessage; -import cn.iocoder.dashboard.modules.system.mq.message.sms.SmsSendMessage; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; - -/** - * 针对 {@link SysDeptRefreshMessage} 的消费者 - * - * @author 芋道源码 - */ -@Component -@Slf4j -public class SmsSendConsumer extends AbstractChannelMessageListener { - - @Resource - private SysSmsChannelService smsChannelService; - - @Resource - private SysSmsQueryLogService smsQueryLogService; - - @Override - public void onMessage(SmsSendMessage message) { - log.info("[onMessage][收到 发送短信 消息], content: " + message.toString()); - AbstractSmsClient smsClient = smsChannelService.getSmsClient(message.getSmsBody().getTemplateCode()); - String templateApiId = smsChannelService.getSmsTemplateApiIdByCode(message.getSmsBody().getTemplateCode()); - - SmsResult result = smsClient.send(templateApiId, message.getSmsBody(), message.getTargetPhones()); - - smsQueryLogService.afterSendLog(message.getSmsBody().getSmsLogId(), result); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SmsSendMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SmsSendMessage.java deleted file mode 100644 index 8ca1207fa..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SmsSendMessage.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.dashboard.modules.system.mq.message.sms; - -import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import lombok.Data; - -import java.util.Collection; -import java.util.List; - -/** - * 部门数据刷新 Message - */ -@Data -public class SmsSendMessage implements ChannelMessage { - - private SmsBody smsBody; - - private List targetPhones; - - @Override - public String getChannel() { - return "sms.send"; - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java deleted file mode 100644 index c758a4a15..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.dashboard.modules.system.mq.producer.sms; - -import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.modules.system.mq.message.sms.SmsSendMessage; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -import java.util.List; - -/** - * 短信的 Producer - */ -@Component -public class SmsProducer { - - @Resource - private StringRedisTemplate stringRedisTemplate; - - /** - * 发送 {@link SmsSendMessage} 消息 - */ - public void sendSmsSendMessage(SmsBody smsBody, List targetPhoneList) { - SmsSendMessage message = new SmsSendMessage(); - message.setSmsBody(smsBody); - message.setTargetPhones(targetPhoneList); - // TODO FROM 芋艿 TO ZZF:这块等未来改哈。这个方法目前是广播消费,会导致每个节点都发送一次。等后续封装出 redis stream 消息 - RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dept/SysDeptRefreshConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dept/SysDeptRefreshConsumer.java similarity index 82% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dept/SysDeptRefreshConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dept/SysDeptRefreshConsumer.java index e6fa5a98d..7e4852dff 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dept/SysDeptRefreshConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dept/SysDeptRefreshConsumer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.consumer.dept; +package cn.iocoder.dashboard.modules.system.redis.mq.consumer.dept; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.modules.system.mq.message.dept.SysDeptRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.dept.SysDeptRefreshMessage; import cn.iocoder.dashboard.modules.system.service.dept.SysDeptService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dict/SysDictDataRefreshConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dict/SysDictDataRefreshConsumer.java similarity index 82% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dict/SysDictDataRefreshConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dict/SysDictDataRefreshConsumer.java index 12bf134a3..87c898984 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dict/SysDictDataRefreshConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dict/SysDictDataRefreshConsumer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.consumer.dict; +package cn.iocoder.dashboard.modules.system.redis.mq.consumer.dict; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.modules.system.mq.message.dict.SysDictDataRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.dict.SysDictDataRefreshMessage; import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysMenuRefreshConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysMenuRefreshConsumer.java similarity index 81% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysMenuRefreshConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysMenuRefreshConsumer.java index 36152424c..5f4442769 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysMenuRefreshConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysMenuRefreshConsumer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.consumer.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.consumer.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.modules.system.mq.message.permission.SysMenuRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysMenuRefreshMessage; import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleMenuRefreshConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleMenuRefreshConsumer.java similarity index 82% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleMenuRefreshConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleMenuRefreshConsumer.java index 6927e1464..60861ba58 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleMenuRefreshConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleMenuRefreshConsumer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.consumer.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.consumer.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleMenuRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysRoleMenuRefreshMessage; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleRefreshConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleRefreshConsumer.java similarity index 81% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleRefreshConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleRefreshConsumer.java index a5e77f7e5..0a71fca7e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleRefreshConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleRefreshConsumer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.consumer.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.consumer.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysRoleRefreshMessage; import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/sms/SmsSendConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/sms/SmsSendConsumer.java new file mode 100644 index 000000000..db8d727ad --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/sms/SmsSendConsumer.java @@ -0,0 +1,56 @@ +//package cn.iocoder.dashboard.modules.system.redis.mq.consumer.sms; +// +//import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; +//import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +//import cn.iocoder.dashboard.framework.sms.core.SmsResult; +//import cn.iocoder.dashboard.modules.system.redis.mq.message.dept.SysDeptRefreshMessage; +//import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendMessage; +//import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; +//import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.data.redis.connection.stream.Consumer; +//import org.springframework.data.redis.connection.stream.ObjectRecord; +//import org.springframework.data.redis.connection.stream.ReadOffset; +//import org.springframework.data.redis.connection.stream.StreamOffset; +//import org.springframework.data.redis.core.StringRedisTemplate; +//import org.springframework.stereotype.Component; +// +//import javax.annotation.Resource; +// +///** +// * 针对 {@link SysDeptRefreshMessage} 的消费者 +// * +// * @author 芋道源码 +// */ +//@Component +//@Slf4j +//public class SmsSendConsumer extends AbstractChannelMessageListener { +// +// @Resource +// private SysSmsChannelService smsChannelService; +// +// @Resource +// private SysSmsQueryLogService smsQueryLogService; +// +// @Autowired +// StringRedisTemplate redisTemplate; +// +// @Override +// public void onMessage(SmsSendMessage message) { +// +// redisTemplate.opsForStream().add(ObjectRecord.create("String", message)); +// +// redisTemplate.opsForStream().read(Consumer.from("",""), StreamOffset.create("", ReadOffset.lastConsumed())); +// +// +// +// log.info("[onMessage][收到 发送短信 消息], content: " + message.toString()); +// AbstractSmsClient smsClient = smsChannelService.getSmsClient(message.getSmsBody().getTemplateCode()); +// String templateApiId = smsChannelService.getSmsTemplateApiIdByCode(message.getSmsBody().getTemplateCode()); +// +// SmsResult result = smsClient.send(templateApiId, message.getSmsBody(), message.getTargetPhone()); +// smsQueryLogService.afterSendLog(message.getSmsBody().getSmsLogId(), result); +// } +// +//} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dept/SysDeptRefreshMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dept/SysDeptRefreshMessage.java similarity index 81% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dept/SysDeptRefreshMessage.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dept/SysDeptRefreshMessage.java index a78b1250f..0c069e319 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dept/SysDeptRefreshMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dept/SysDeptRefreshMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.mq.message.dept; +package cn.iocoder.dashboard.modules.system.redis.mq.message.dept; import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dict/SysDictDataRefreshMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dict/SysDictDataRefreshMessage.java similarity index 82% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dict/SysDictDataRefreshMessage.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dict/SysDictDataRefreshMessage.java index 7fad277c4..2d4342423 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dict/SysDictDataRefreshMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dict/SysDictDataRefreshMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.mq.message.dict; +package cn.iocoder.dashboard.modules.system.redis.mq.message.dict; import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysMenuRefreshMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysMenuRefreshMessage.java similarity index 80% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysMenuRefreshMessage.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysMenuRefreshMessage.java index 159682a98..8f72705ee 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysMenuRefreshMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysMenuRefreshMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.mq.message.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.message.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleMenuRefreshMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleMenuRefreshMessage.java similarity index 81% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleMenuRefreshMessage.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleMenuRefreshMessage.java index 491c9b0d2..b1c303dbe 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleMenuRefreshMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleMenuRefreshMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.mq.message.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.message.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleRefreshMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleRefreshMessage.java similarity index 80% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleRefreshMessage.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleRefreshMessage.java index b99401021..ac46d181e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleRefreshMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleRefreshMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.mq.message.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.message.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dept/SysDeptProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dept/SysDeptProducer.java similarity index 80% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dept/SysDeptProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dept/SysDeptProducer.java index 4ad7db4b8..3ce859fa4 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dept/SysDeptProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dept/SysDeptProducer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.producer.dept; +package cn.iocoder.dashboard.modules.system.redis.mq.producer.dept; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.modules.system.mq.message.dept.SysDeptRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.dept.SysDeptRefreshMessage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dict/SysDictDataProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dict/SysDictDataProducer.java similarity index 80% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dict/SysDictDataProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dict/SysDictDataProducer.java index 2ccfc51d2..af9daae84 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dict/SysDictDataProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dict/SysDictDataProducer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.producer.dict; +package cn.iocoder.dashboard.modules.system.redis.mq.producer.dict; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.modules.system.mq.message.dict.SysDictDataRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.dict.SysDictDataRefreshMessage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysMenuProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysMenuProducer.java similarity index 79% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysMenuProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysMenuProducer.java index 6d664c725..9a760ad2d 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysMenuProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysMenuProducer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.producer.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.producer.permission; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.modules.system.mq.message.permission.SysMenuRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysMenuRefreshMessage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysPermissionProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysPermissionProducer.java similarity index 79% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysPermissionProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysPermissionProducer.java index f9eded668..67a4769a1 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysPermissionProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysPermissionProducer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.producer.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.producer.permission; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleMenuRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysRoleMenuRefreshMessage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysRoleProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysRoleProducer.java similarity index 79% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysRoleProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysRoleProducer.java index e11945dfe..f1be4b87b 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysRoleProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysRoleProducer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.producer.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.producer.permission; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysRoleRefreshMessage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/sms/SmsProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/sms/SmsProducer.java new file mode 100644 index 000000000..3e4681715 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/sms/SmsProducer.java @@ -0,0 +1,31 @@ +//package cn.iocoder.dashboard.modules.system.redis.mq.producer.sms; +// +//import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; +//import cn.iocoder.dashboard.framework.sms.core.SmsBody; +//import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendMessage; +//import org.springframework.data.redis.core.StringRedisTemplate; +//import org.springframework.stereotype.Component; +// +//import javax.annotation.Resource; +// +///** +// * 短信的 Producer +// */ +//@Component +//public class SmsProducer { +// +// @Resource +// private StringRedisTemplate stringRedisTemplate; +// +// /** +// * 发送 {@link SmsSendMessage} 消息 +// */ +// public void sendSmsSendMessage(SmsBody smsBody, String targetPhone) { +// SmsSendMessage message = new SmsSendMessage(); +// message.setSmsBody(smsBody); +// message.setTargetPhone(targetPhone); +// // TODO FROM 芋艿 TO ZZF:这块等未来改哈。这个方法目前是广播消费,会导致每个节点都发送一次。等后续封装出 redis stream 消息 +// RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message); +// } +// +//} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/StreamConsumerRunner.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/StreamConsumerRunner.java new file mode 100644 index 000000000..7cd9d2486 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/StreamConsumerRunner.java @@ -0,0 +1,93 @@ +package cn.iocoder.dashboard.modules.system.redis.stream; + +import cn.iocoder.dashboard.framework.redis.core.util.RedisStreamUtils; +import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendMessage; +import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendStreamConsumer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.stream.*; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.data.redis.stream.StreamMessageListenerContainer; +import org.springframework.data.redis.stream.StreamMessageListenerContainer.StreamMessageListenerContainerOptions; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Component; +import org.springframework.util.ErrorHandler; + +import javax.annotation.Resource; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.time.Duration; + + +@Slf4j +@Component +public class StreamConsumerRunner implements ApplicationRunner, DisposableBean { + + @Resource + RedisConnectionFactory redisConnectionFactory; + + @Resource + ThreadPoolTaskExecutor threadPoolTaskExecutor; + + @Resource + SmsSendStreamConsumer streamMessageListener; + + @Resource + StringRedisTemplate stringRedisTemplate; + + private StreamMessageListenerContainer> streamMessageListenerContainer; + + @Override + public void run(ApplicationArguments args) throws UnknownHostException { + + StreamInfo.XInfoGroups groups = stringRedisTemplate.opsForStream().groups(RedisStreamUtils.KEY_SMS_SEND); + if (groups.isEmpty()) { + stringRedisTemplate.opsForStream().createGroup(RedisStreamUtils.KEY_SMS_SEND, RedisStreamUtils.GROUP_SMS_SEND); + } + + + // 创建配置对象 + StreamMessageListenerContainerOptions> streamMessageListenerContainerOptions = StreamMessageListenerContainerOptions + .builder() + // 一次性最多拉取多少条消息 + .batchSize(10) + // 执行消息轮询的执行器 + .executor(this.threadPoolTaskExecutor) + // 消息消费异常的handler + .errorHandler(new ErrorHandler() { + @Override + public void handleError(Throwable t) { + // throw new RuntimeException(t); + t.printStackTrace(); + } + }) + // 超时时间,设置为0,表示不超时(超时后会抛出异常) + .pollTimeout(Duration.ZERO) + // 序列化器 + .serializer(new StringRedisSerializer()) + .targetType(SmsSendMessage.class) + .build(); + + // 根据配置对象创建监听容器对象 + StreamMessageListenerContainer> streamMessageListenerContainer = StreamMessageListenerContainer + .create(this.redisConnectionFactory, streamMessageListenerContainerOptions); + + // 使用监听容器对象开始监听消费(使用的是手动确认方式) + streamMessageListenerContainer.receive(Consumer.from(RedisStreamUtils.GROUP_SMS_SEND, InetAddress.getLocalHost().getHostName()), + StreamOffset.create(RedisStreamUtils.KEY_SMS_SEND, ReadOffset.lastConsumed()), this.streamMessageListener); + + this.streamMessageListenerContainer = streamMessageListenerContainer; + // 启动监听 + this.streamMessageListenerContainer.start(); + + } + + @Override + public void destroy() throws Exception { + this.streamMessageListenerContainer.stop(); + } +} \ No newline at end of file diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendMessage.java new file mode 100644 index 000000000..a8aeff23f --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendMessage.java @@ -0,0 +1,16 @@ +package cn.iocoder.dashboard.modules.system.redis.stream.sms; + +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import lombok.Data; + +/** + * 部门数据刷新 Message + */ +@Data +public class SmsSendMessage { + + private SmsBody smsBody; + + private String targetPhone; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamConsumer.java new file mode 100644 index 000000000..0ab531b43 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamConsumer.java @@ -0,0 +1,43 @@ +package cn.iocoder.dashboard.modules.system.redis.stream.sms; + +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; +import cn.iocoder.dashboard.util.json.JsonUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.connection.stream.ObjectRecord; +import org.springframework.data.redis.stream.StreamListener; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 短信发送流消息监听器 + * + * @author zzf + * @date 2021/3/9 16:35 + */ +@Slf4j +@Component +public class SmsSendStreamConsumer implements StreamListener> { + + @Resource + private SysSmsChannelService smsChannelService; + + @Resource + private SysSmsQueryLogService smsQueryLogService; + + @Override + public void onMessage(ObjectRecord record) { + SmsSendMessage message = record.getValue(); + SmsBody body = message.getSmsBody(); + log.info("[onMessage][收到 发送短信 消息], content: " + JsonUtils.toJsonString(body)); + AbstractSmsClient smsClient = smsChannelService.getSmsClient(body.getTemplateCode()); + String templateApiId = smsChannelService.getSmsTemplateApiIdByCode(body.getTemplateCode()); + + SmsResult result = smsClient.send(templateApiId, body, message.getTargetPhone()); + smsQueryLogService.afterSendLog(body.getSmsLogId(), result); + } +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamProducer.java new file mode 100644 index 000000000..069534251 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamProducer.java @@ -0,0 +1,35 @@ +package cn.iocoder.dashboard.modules.system.redis.stream.sms; + +import cn.iocoder.dashboard.framework.redis.core.util.RedisStreamUtils; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 短信发送流消息监听器 + * + * @author zzf + * @date 2021/3/9 16:35 + */ +@Slf4j +@Component +public class SmsSendStreamProducer { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + /** + * 发送 {@link SmsSendMessage} 消息 + */ + public void sendSmsSendMessage(SmsBody smsBody, String targetPhone) { + SmsSendMessage message = new SmsSendMessage(); + message.setSmsBody(smsBody); + message.setTargetPhone(targetPhone); + + RedisStreamUtils.sendChannelMessage(stringRedisTemplate, message); + } + +} \ No newline at end of file diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java index d3ff381ef..caa16e94b 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java @@ -11,7 +11,7 @@ import cn.iocoder.dashboard.modules.system.convert.dept.SysDeptConvert; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.dept.SysDeptMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dept.SysDeptDO; import cn.iocoder.dashboard.modules.system.enums.dept.DeptIdEnum; -import cn.iocoder.dashboard.modules.system.mq.producer.dept.SysDeptProducer; +import cn.iocoder.dashboard.modules.system.redis.mq.producer.dept.SysDeptProducer; import cn.iocoder.dashboard.modules.system.service.dept.SysDeptService; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java index 6e8f02388..49e5beabf 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java @@ -13,7 +13,7 @@ import cn.iocoder.dashboard.modules.system.convert.dict.SysDictDataConvert; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.dict.SysDictDataMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictDataDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictTypeDO; -import cn.iocoder.dashboard.modules.system.mq.producer.dict.SysDictDataProducer; +import cn.iocoder.dashboard.modules.system.redis.mq.producer.dict.SysDictDataProducer; import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService; import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService; import com.google.common.collect.ImmutableTable; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java index 60a4015b5..31c0991c9 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java @@ -11,7 +11,7 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysMenuMappe import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; import cn.iocoder.dashboard.modules.system.enums.permission.MenuIdEnum; import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; -import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysMenuProducer; +import cn.iocoder.dashboard.modules.system.redis.mq.producer.permission.SysMenuProducer; import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; import cn.iocoder.dashboard.util.collection.CollectionUtils; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java index 3b3647fc4..5746357a6 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java @@ -11,7 +11,7 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMe import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleMenuDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysUserRoleDO; -import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysPermissionProducer; +import cn.iocoder.dashboard.modules.system.redis.mq.producer.permission.SysPermissionProducer; import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java index a40896b97..6fbb2bae8 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java @@ -15,7 +15,7 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysRoleMappe import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; import cn.iocoder.dashboard.modules.system.enums.permission.RoleCodeEnum; import cn.iocoder.dashboard.modules.system.enums.permission.SysRoleTypeEnum; -import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysRoleProducer; +import cn.iocoder.dashboard.modules.system.redis.mq.producer.permission.SysRoleProducer; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; import com.google.common.collect.ImmutableMap; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java index a2ebf13b2..3ce83fe78 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java @@ -2,12 +2,14 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO; +import javax.servlet.ServletRequest; import java.util.List; /** diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java index 7312e2355..e5ec2fa3c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java @@ -3,6 +3,7 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import java.util.List; @@ -16,16 +17,16 @@ public interface SysSmsQueryLogService { /** * 发送短信前的日志处理 * - * @param smsBody 短信内容 - * @param targetPhones 发送对象手机号集合 - * @param client 短信客户端 + * @param smsBody 短信内容 + * @param targetPhone 发送对象手机号 + * @param client 短信客户端 * @return 生成的日志id */ // TODO FROM 芋艿 to ZZF: async 是针对发送的方式,对于日志不一定需要关心。这样,短信日志,实际就发送前插入,发送后更新结果. // 这里只用于记录状态,毕竟异步可能推送失败,此时日志可记录该状态。 // TODO FROM 芋艿 to ZZF:短信日志,群发的情况,应该是每个手机一条哈。虽然是群发,但是可能部分成功,部分失败;对应到短信平台,实际也是多条。 - void beforeSendLog(SmsBody smsBody, List targetPhones, AbstractSmsClient client); + void beforeSendLog(SmsBody smsBody, String targetPhone, AbstractSmsClient client); /** * 发送消息后的日志处理 @@ -35,4 +36,5 @@ public interface SysSmsQueryLogService { */ void afterSendLog(Long logId, SmsResult result); + void updateSendLogByResultDetail(SmsResultDetail smsResultDetail); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java index 6d851d4f6..93a467d62 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java @@ -1,10 +1,12 @@ package cn.iocoder.dashboard.modules.system.service.sms; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ArrayUtil; import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import javax.servlet.ServletRequest; import java.util.Arrays; -import java.util.Collections; import java.util.List; /** @@ -22,7 +24,12 @@ public interface SysSmsService { * @param smsBody 消息内容 * @param targetPhones 发送对象手机号列表 */ - void send(SmsBody smsBody, List targetPhones); + default void send(SmsBody smsBody, List targetPhones) { + if (CollectionUtil.isEmpty(targetPhones)) { + return; + } + targetPhones.forEach(s -> this.send(smsBody, s)); + } /** * 发送消息 @@ -30,9 +37,7 @@ public interface SysSmsService { * @param smsBody 消息内容 * @param targetPhone 发送对象手机号 */ - default void send(SmsBody smsBody, String targetPhone) { - send(smsBody, Collections.singletonList(targetPhone)); - } + void send(SmsBody smsBody, String targetPhone); /** * 发送消息 @@ -41,14 +46,18 @@ public interface SysSmsService { * @param targetPhones 发送对象手机号数组 */ default void send(SmsBody smsBody, String... targetPhones) { + if (ArrayUtil.isEmpty(targetPhones)) { + return; + } send(smsBody, Arrays.asList(targetPhones)); } /** * 处理短信发送回调函数 * - * @param request 请求 + * @param request 请求 * @return 响应数据 */ Object smsSendCallbackHandle(ServletRequest request); + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java index 7264f550c..a08a7bb76 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java @@ -3,16 +3,15 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsQueryLogMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsQueryLogDO; import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; -import cn.iocoder.dashboard.util.json.JsonUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.List; /** * 短信请求日志服务实现类 @@ -27,14 +26,14 @@ public class SysSmsQueryLogServiceImpl implements SysSmsQueryLogService { private SysSmsQueryLogMapper logMapper; @Override - public void beforeSendLog(SmsBody smsBody, List targetPhones, AbstractSmsClient client) { + public void beforeSendLog(SmsBody smsBody, String targetPhone, AbstractSmsClient client) { SysSmsQueryLogDO smsLog = new SysSmsQueryLogDO(); SmsChannelProperty property = client.getProperty(); smsLog.setChannelCode(property.getCode()) .setChannelId(property.getId()) .setTemplateCode(smsBody.getTemplateCode()) - .setPhones(targetPhones) + .setPhone(targetPhone) .setContent(smsBody.getParams().toString()); smsLog.setSendStatus(SmsSendStatusEnum.ASYNC.getStatus()); @@ -46,14 +45,19 @@ public class SysSmsQueryLogServiceImpl implements SysSmsQueryLogService { public void afterSendLog(Long logId, SmsResult result) { SysSmsQueryLogDO smsLog = new SysSmsQueryLogDO(); smsLog.setId(logId); - if (result.getSuccess()) { - smsLog.setSendStatus(SmsSendStatusEnum.QUERY_SUCCESS.getStatus()); - smsLog.setSendResultParam(result.getSendResultParam()); - } else { - smsLog.setSendStatus(SmsSendStatusEnum.QUERY_FAIL.getStatus()); - smsLog.setRemark(result.getMessage()); - } + smsLog.setApiId(result.getApiId()); + smsLog.setSendStatus(SmsSendStatusEnum.QUERY_FAIL.getStatus()); + smsLog.setRemark(result.getCode() + ": " + result.getMessage()); logMapper.updateById(smsLog); } + @Override + public void updateSendLogByResultDetail(SmsResultDetail smsResultDetail) { + SysSmsQueryLogDO queryLogDO = new SysSmsQueryLogDO(); + queryLogDO.setSendStatus(smsResultDetail.getSendStatus()); + queryLogDO.setSendTime(smsResultDetail.getSendTime()); + queryLogDO.setRemark(smsResultDetail.getMessage()); + logMapper.updateByApiId(queryLogDO, smsResultDetail.getApiId()); + } + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java index 03ef5575d..c58ce5ca7 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java @@ -2,7 +2,6 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.hutool.core.collection.CollectionUtil; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.client.NeedQuerySendResultSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsQueryLogMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsSendLogMapper; @@ -62,7 +61,7 @@ public class SysSmsSendLogServiceImpl implements SysSmsSendLogService { updateQueryLog.setId(queryLog.getId()); // 只处理实现了获取发送结果方法的短信客户端,理论上这里都是满足条件的,以防万一加个判断。 - if (smsClient instanceof NeedQuerySendResultSmsClient) { + /*if (smsClient instanceof NeedQuerySendResultSmsClient) { //初始化点字段值 queryLog2SendLong(insertSendLog, queryLog); @@ -89,7 +88,7 @@ public class SysSmsSendLogServiceImpl implements SysSmsSendLogService { //理论上这里都是满足条件的,以防万一加个判断。 updateQueryLog.setSendStatus(SmsSendStatusEnum.QUERY_SEND_FAIL.getStatus()); smsQueryLogMapper.updateById(updateQueryLog); - } + }*/ updateQueryLog.setSendStatus(SmsSendStatusEnum.SEND_SUCCESS.getStatus()); updateQueryLog.setRemark(String.format("日志(id = %s)对应的客户端没有继承NeedQuerySendResultSmsClient, 不能获取短信结果。", queryLog.getId())); smsQueryLogMapper.updateById(updateQueryLog); diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index 81371e575..c679a8c81 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -2,15 +2,16 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.modules.system.mq.producer.sms.SmsProducer; +import cn.iocoder.dashboard.framework.sms.core.SmsClientFactory; +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; +import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendStreamProducer; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; -import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.List; +import javax.servlet.ServletRequest; /** * 短信日志Service实现类 @@ -28,15 +29,23 @@ public class SysSmsServiceImpl implements SysSmsService { private SysSmsQueryLogService logService; @Resource - private SmsProducer smsProducer; + private SmsSendStreamProducer smsProducer; + + @Resource + private SmsClientFactory smsClientFactory; @Override - public void send(SmsBody smsBody, List targetPhones) { + public void send(SmsBody smsBody, String targetPhone) { AbstractSmsClient client = channelService.getSmsClient(smsBody.getTemplateCode()); - logService.beforeSendLog(smsBody, targetPhones, client); - smsProducer.sendSmsSendMessage(smsBody, targetPhones); + logService.beforeSendLog(smsBody, targetPhone, client); + smsProducer.sendSmsSendMessage(smsBody, targetPhone); } - // TODO FROM 芋艿 to ZZF:可能要讨论下,对于短信发送来说,貌似只提供异步发送即可。对于业务来说,一定不能依赖短信的发送结果. + @Override + public Object smsSendCallbackHandle(ServletRequest request) { + SmsResultDetail smsResultDetail = smsClientFactory.getSmsResultDetailFromCallbackQuery(request); + logService.updateSendLogByResultDetail(smsResultDetail); + return smsResultDetail.getCallbackResponseBody(); + } }