Commit 48fd4972da171f10c6ac2012f05fea58a5e86562
1 parent
ab800aa8
sms 缓存,使用 guava 替代 job 扫描,目的:提升启动速度,加快缓存失效
Showing
7 changed files
with
164 additions
and
104 deletions
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/sms/SmsChannelConvert.java
| ... | ... | @@ -32,8 +32,8 @@ public interface SmsChannelConvert { |
| 32 | 32 | |
| 33 | 33 | PageResult<SmsChannelRespVO> convertPage(PageResult<SmsChannelDO> page); |
| 34 | 34 | |
| 35 | - List<SmsChannelProperties> convertList02(List<SmsChannelDO> list); | |
| 36 | - | |
| 37 | 35 | List<SmsChannelSimpleRespVO> convertList03(List<SmsChannelDO> list); |
| 38 | 36 | |
| 37 | + SmsChannelProperties convert02(SmsChannelDO channel); | |
| 38 | + | |
| 39 | 39 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsChannelMapper.java
| ... | ... | @@ -6,9 +6,6 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 6 | 6 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; |
| 7 | 7 | import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; |
| 8 | 8 | import org.apache.ibatis.annotations.Mapper; |
| 9 | -import org.apache.ibatis.annotations.Select; | |
| 10 | - | |
| 11 | -import java.time.LocalDateTime; | |
| 12 | 9 | |
| 13 | 10 | @Mapper |
| 14 | 11 | public interface SmsChannelMapper extends BaseMapperX<SmsChannelDO> { |
| ... | ... | @@ -21,7 +18,8 @@ public interface SmsChannelMapper extends BaseMapperX<SmsChannelDO> { |
| 21 | 18 | .orderByDesc(SmsChannelDO::getId)); |
| 22 | 19 | } |
| 23 | 20 | |
| 24 | - @Select("SELECT COUNT(*) FROM system_sms_channel WHERE update_time > #{maxUpdateTime}") | |
| 25 | - Long selectCountByUpdateTimeGt(LocalDateTime maxTime); | |
| 21 | + default SmsChannelDO selectByCode(String code) { | |
| 22 | + return selectOne(SmsChannelDO::getCode, code); | |
| 23 | + } | |
| 26 | 24 | |
| 27 | 25 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelService.java
| 1 | 1 | package cn.iocoder.yudao.module.system.service.sms; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | +import cn.iocoder.yudao.framework.sms.core.client.SmsClient; | |
| 4 | 5 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelCreateReqVO; |
| 5 | 6 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; |
| 6 | 7 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelUpdateReqVO; |
| ... | ... | @@ -13,16 +14,11 @@ import java.util.List; |
| 13 | 14 | * 短信渠道 Service 接口 |
| 14 | 15 | * |
| 15 | 16 | * @author zzf |
| 16 | - * @date 2021/1/25 9:24 | |
| 17 | + * @since 2021/1/25 9:24 | |
| 17 | 18 | */ |
| 18 | 19 | public interface SmsChannelService { |
| 19 | 20 | |
| 20 | 21 | /** |
| 21 | - * 初始化短信客户端 | |
| 22 | - */ | |
| 23 | - void initLocalCache(); | |
| 24 | - | |
| 25 | - /** | |
| 26 | 22 | * 创建短信渠道 |
| 27 | 23 | * |
| 28 | 24 | * @param createReqVO 创建信息 |
| ... | ... | @@ -67,4 +63,20 @@ public interface SmsChannelService { |
| 67 | 63 | */ |
| 68 | 64 | PageResult<SmsChannelDO> getSmsChannelPage(SmsChannelPageReqVO pageReqVO); |
| 69 | 65 | |
| 66 | + /** | |
| 67 | + * 获得短信客户端 | |
| 68 | + * | |
| 69 | + * @param id 编号 | |
| 70 | + * @return 短信客户端 | |
| 71 | + */ | |
| 72 | + SmsClient getSmsClient(Long id); | |
| 73 | + | |
| 74 | + /** | |
| 75 | + * 获得短信客户端 | |
| 76 | + * | |
| 77 | + * @param code 编码 | |
| 78 | + * @return 短信客户端 | |
| 79 | + */ | |
| 80 | + SmsClient getSmsClient(String code); | |
| 81 | + | |
| 70 | 82 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.system.service.sms; |
| 2 | 2 | |
| 3 | -import cn.hutool.core.collection.CollUtil; | |
| 3 | +import cn.hutool.core.util.StrUtil; | |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | +import cn.iocoder.yudao.framework.common.util.cache.CacheUtils; | |
| 6 | +import cn.iocoder.yudao.framework.sms.core.client.SmsClient; | |
| 5 | 7 | import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; |
| 6 | 8 | import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; |
| 7 | 9 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelCreateReqVO; |
| ... | ... | @@ -10,20 +12,18 @@ import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannel |
| 10 | 12 | import cn.iocoder.yudao.module.system.convert.sms.SmsChannelConvert; |
| 11 | 13 | import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; |
| 12 | 14 | import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper; |
| 15 | +import com.google.common.cache.CacheLoader; | |
| 16 | +import com.google.common.cache.LoadingCache; | |
| 13 | 17 | import lombok.Getter; |
| 18 | +import lombok.SneakyThrows; | |
| 14 | 19 | import lombok.extern.slf4j.Slf4j; |
| 15 | -import org.springframework.scheduling.annotation.Scheduled; | |
| 16 | 20 | import org.springframework.stereotype.Service; |
| 17 | 21 | |
| 18 | -import javax.annotation.PostConstruct; | |
| 19 | 22 | import javax.annotation.Resource; |
| 20 | -import java.time.LocalDateTime; | |
| 21 | -import java.util.Collections; | |
| 23 | +import java.time.Duration; | |
| 22 | 24 | import java.util.List; |
| 23 | -import java.util.concurrent.TimeUnit; | |
| 24 | 25 | |
| 25 | 26 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 26 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue; | |
| 27 | 27 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN; |
| 28 | 28 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS; |
| 29 | 29 | |
| ... | ... | @@ -37,10 +37,44 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNE |
| 37 | 37 | public class SmsChannelServiceImpl implements SmsChannelService { |
| 38 | 38 | |
| 39 | 39 | /** |
| 40 | - * 短信渠道列表的缓存 | |
| 40 | + * {@link SmsClient} 缓存,通过它异步刷新 smsClientFactory | |
| 41 | 41 | */ |
| 42 | 42 | @Getter |
| 43 | - private volatile List<SmsChannelDO> channelCache = Collections.emptyList(); | |
| 43 | + private final LoadingCache<Long, SmsClient> idClientCache = CacheUtils.buildAsyncReloadingCache(Duration.ofSeconds(10L), | |
| 44 | + new CacheLoader<Long, SmsClient>() { | |
| 45 | + | |
| 46 | + @Override | |
| 47 | + public SmsClient load(Long id) { | |
| 48 | + // 查询,然后尝试刷新 | |
| 49 | + SmsChannelDO channel = smsChannelMapper.selectById(id); | |
| 50 | + if (channel != null) { | |
| 51 | + SmsChannelProperties properties = SmsChannelConvert.INSTANCE.convert02(channel); | |
| 52 | + smsClientFactory.createOrUpdateSmsClient(properties); | |
| 53 | + } | |
| 54 | + return smsClientFactory.getSmsClient(id); | |
| 55 | + } | |
| 56 | + | |
| 57 | + }); | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * {@link SmsClient} 缓存,通过它异步刷新 smsClientFactory | |
| 61 | + */ | |
| 62 | + @Getter | |
| 63 | + private final LoadingCache<String, SmsClient> codeClientCache = CacheUtils.buildAsyncReloadingCache(Duration.ofSeconds(60L), | |
| 64 | + new CacheLoader<String, SmsClient>() { | |
| 65 | + | |
| 66 | + @Override | |
| 67 | + public SmsClient load(String code) { | |
| 68 | + // 查询,然后尝试刷新 | |
| 69 | + SmsChannelDO channel = smsChannelMapper.selectByCode(code); | |
| 70 | + if (channel != null) { | |
| 71 | + SmsChannelProperties properties = SmsChannelConvert.INSTANCE.convert02(channel); | |
| 72 | + smsClientFactory.createOrUpdateSmsClient(properties); | |
| 73 | + } | |
| 74 | + return smsClientFactory.getSmsClient(code); | |
| 75 | + } | |
| 76 | + | |
| 77 | + }); | |
| 44 | 78 | |
| 45 | 79 | @Resource |
| 46 | 80 | private SmsClientFactory smsClientFactory; |
| ... | ... | @@ -52,65 +86,32 @@ public class SmsChannelServiceImpl implements SmsChannelService { |
| 52 | 86 | private SmsTemplateService smsTemplateService; |
| 53 | 87 | |
| 54 | 88 | @Override |
| 55 | - @PostConstruct | |
| 56 | - public void initLocalCache() { | |
| 57 | - // 第一步:查询数据 | |
| 58 | - List<SmsChannelDO> channels = smsChannelMapper.selectList(); | |
| 59 | - log.info("[initLocalCache][缓存短信渠道,数量为:{}]", channels.size()); | |
| 60 | - | |
| 61 | - // 第二步:构建缓存:创建或更新短信 Client | |
| 62 | - List<SmsChannelProperties> propertiesList = SmsChannelConvert.INSTANCE.convertList02(channels); | |
| 63 | - propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties)); | |
| 64 | - this.channelCache = channels; | |
| 65 | - } | |
| 66 | - | |
| 67 | - /** | |
| 68 | - * 通过定时任务轮询,刷新缓存 | |
| 69 | - * | |
| 70 | - * 目的:多节点部署时,通过轮询”通知“所有节点,进行刷新 | |
| 71 | - */ | |
| 72 | - @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS) | |
| 73 | - public void refreshLocalCache() { | |
| 74 | - // 情况一:如果缓存里没有数据,则直接刷新缓存 | |
| 75 | - if (CollUtil.isEmpty(channelCache)) { | |
| 76 | - initLocalCache(); | |
| 77 | - return; | |
| 78 | - } | |
| 79 | - | |
| 80 | - // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存 | |
| 81 | - LocalDateTime maxTime = getMaxValue(channelCache, SmsChannelDO::getUpdateTime); | |
| 82 | - if (smsChannelMapper.selectCountByUpdateTimeGt(maxTime) > 0) { | |
| 83 | - initLocalCache(); | |
| 84 | - } | |
| 85 | - } | |
| 86 | - | |
| 87 | - @Override | |
| 88 | 89 | public Long createSmsChannel(SmsChannelCreateReqVO createReqVO) { |
| 89 | 90 | // 插入 |
| 90 | - SmsChannelDO smsChannel = SmsChannelConvert.INSTANCE.convert(createReqVO); | |
| 91 | - smsChannelMapper.insert(smsChannel); | |
| 91 | + SmsChannelDO channel = SmsChannelConvert.INSTANCE.convert(createReqVO); | |
| 92 | + smsChannelMapper.insert(channel); | |
| 92 | 93 | |
| 93 | - // 刷新缓存 | |
| 94 | - initLocalCache(); | |
| 95 | - return smsChannel.getId(); | |
| 94 | + // 清空缓存 | |
| 95 | + clearCache(channel.getId(), null); | |
| 96 | + return channel.getId(); | |
| 96 | 97 | } |
| 97 | 98 | |
| 98 | 99 | @Override |
| 99 | 100 | public void updateSmsChannel(SmsChannelUpdateReqVO updateReqVO) { |
| 100 | 101 | // 校验存在 |
| 101 | - validateSmsChannelExists(updateReqVO.getId()); | |
| 102 | + SmsChannelDO channel = validateSmsChannelExists(updateReqVO.getId()); | |
| 102 | 103 | // 更新 |
| 103 | 104 | SmsChannelDO updateObj = SmsChannelConvert.INSTANCE.convert(updateReqVO); |
| 104 | 105 | smsChannelMapper.updateById(updateObj); |
| 105 | 106 | |
| 106 | - // 刷新缓存 | |
| 107 | - initLocalCache(); | |
| 107 | + // 清空缓存 | |
| 108 | + clearCache(updateReqVO.getId(), channel.getCode()); | |
| 108 | 109 | } |
| 109 | 110 | |
| 110 | 111 | @Override |
| 111 | 112 | public void deleteSmsChannel(Long id) { |
| 112 | 113 | // 校验存在 |
| 113 | - validateSmsChannelExists(id); | |
| 114 | + SmsChannelDO channel = validateSmsChannelExists(id); | |
| 114 | 115 | // 校验是否有在使用该账号的模版 |
| 115 | 116 | if (smsTemplateService.countByChannelId(id) > 0) { |
| 116 | 117 | throw exception(SMS_CHANNEL_HAS_CHILDREN); |
| ... | ... | @@ -118,14 +119,28 @@ public class SmsChannelServiceImpl implements SmsChannelService { |
| 118 | 119 | // 删除 |
| 119 | 120 | smsChannelMapper.deleteById(id); |
| 120 | 121 | |
| 121 | - // 刷新缓存 | |
| 122 | - initLocalCache(); | |
| 122 | + // 清空缓存 | |
| 123 | + clearCache(id, channel.getCode()); | |
| 124 | + } | |
| 125 | + | |
| 126 | + /** | |
| 127 | + * 清空指定渠道编号的缓存 | |
| 128 | + * | |
| 129 | + * @param id 渠道编号 | |
| 130 | + */ | |
| 131 | + private void clearCache(Long id, String code) { | |
| 132 | + idClientCache.invalidate(id); | |
| 133 | + if (StrUtil.isNotEmpty(code)) { | |
| 134 | + codeClientCache.invalidate(code); | |
| 135 | + } | |
| 123 | 136 | } |
| 124 | 137 | |
| 125 | - private void validateSmsChannelExists(Long id) { | |
| 126 | - if (smsChannelMapper.selectById(id) == null) { | |
| 138 | + private SmsChannelDO validateSmsChannelExists(Long id) { | |
| 139 | + SmsChannelDO channel = smsChannelMapper.selectById(id); | |
| 140 | + if (channel == null) { | |
| 127 | 141 | throw exception(SMS_CHANNEL_NOT_EXISTS); |
| 128 | 142 | } |
| 143 | + return channel; | |
| 129 | 144 | } |
| 130 | 145 | |
| 131 | 146 | @Override |
| ... | ... | @@ -143,4 +158,14 @@ public class SmsChannelServiceImpl implements SmsChannelService { |
| 143 | 158 | return smsChannelMapper.selectPage(pageReqVO); |
| 144 | 159 | } |
| 145 | 160 | |
| 161 | + @Override | |
| 162 | + public SmsClient getSmsClient(Long id) { | |
| 163 | + return idClientCache.getUnchecked(id); | |
| 164 | + } | |
| 165 | + | |
| 166 | + @Override | |
| 167 | + public SmsClient getSmsClient(String code) { | |
| 168 | + return codeClientCache.getUnchecked(code); | |
| 169 | + } | |
| 170 | + | |
| 146 | 171 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImpl.java
| ... | ... | @@ -8,7 +8,6 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 8 | 8 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 9 | 9 | import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; |
| 10 | 10 | import cn.iocoder.yudao.framework.sms.core.client.SmsClient; |
| 11 | -import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; | |
| 12 | 11 | import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; |
| 13 | 12 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 14 | 13 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; |
| ... | ... | @@ -50,9 +49,6 @@ public class SmsSendServiceImpl implements SmsSendService { |
| 50 | 49 | private SmsLogService smsLogService; |
| 51 | 50 | |
| 52 | 51 | @Resource |
| 53 | - private SmsClientFactory smsClientFactory; | |
| 54 | - | |
| 55 | - @Resource | |
| 56 | 52 | private SmsProducer smsProducer; |
| 57 | 53 | |
| 58 | 54 | @Override |
| ... | ... | @@ -95,7 +91,6 @@ public class SmsSendServiceImpl implements SmsSendService { |
| 95 | 91 | // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志 |
| 96 | 92 | Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()) |
| 97 | 93 | && CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus()); |
| 98 | - ; | |
| 99 | 94 | String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams); |
| 100 | 95 | Long sendLogId = smsLogService.createSmsLog(mobile, userId, userType, isSend, template, content, templateParams); |
| 101 | 96 | |
| ... | ... | @@ -132,7 +127,7 @@ public class SmsSendServiceImpl implements SmsSendService { |
| 132 | 127 | /** |
| 133 | 128 | * 将参数模板,处理成有序的 KeyValue 数组 |
| 134 | 129 | * <p> |
| 135 | - * 原因是,部分短信平台并不是使用 key 作为参数,而是数组下标,例如说腾讯云 https://cloud.tencent.com/document/product/382/39023 | |
| 130 | + * 原因是,部分短信平台并不是使用 key 作为参数,而是数组下标,例如说 <a href="https://cloud.tencent.com/document/product/382/39023">腾讯云</a> | |
| 136 | 131 | * |
| 137 | 132 | * @param template 短信模板 |
| 138 | 133 | * @param templateParams 原始参数 |
| ... | ... | @@ -160,7 +155,7 @@ public class SmsSendServiceImpl implements SmsSendService { |
| 160 | 155 | @Override |
| 161 | 156 | public void doSendSms(SmsSendMessage message) { |
| 162 | 157 | // 获得渠道对应的 SmsClient 客户端 |
| 163 | - SmsClient smsClient = smsClientFactory.getSmsClient(message.getChannelId()); | |
| 158 | + SmsClient smsClient = smsChannelService.getSmsClient(message.getChannelId()); | |
| 164 | 159 | Assert.notNull(smsClient, "短信客户端({}) 不存在", message.getChannelId()); |
| 165 | 160 | // 发送短信 |
| 166 | 161 | SmsCommonResult<SmsSendRespDTO> sendResult = smsClient.sendSms(message.getLogId(), message.getMobile(), |
| ... | ... | @@ -173,7 +168,7 @@ public class SmsSendServiceImpl implements SmsSendService { |
| 173 | 168 | @Override |
| 174 | 169 | public void receiveSmsStatus(String channelCode, String text) throws Throwable { |
| 175 | 170 | // 获得渠道对应的 SmsClient 客户端 |
| 176 | - SmsClient smsClient = smsClientFactory.getSmsClient(channelCode); | |
| 171 | + SmsClient smsClient = smsChannelService.getSmsClient(channelCode); | |
| 177 | 172 | Assert.notNull(smsClient, "短信客户端({}) 不存在", channelCode); |
| 178 | 173 | // 解析内容 |
| 179 | 174 | List<SmsReceiveRespDTO> receiveResults = smsClient.parseSmsReceiveStatus(text); | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceTest.java
| ... | ... | @@ -2,11 +2,14 @@ package cn.iocoder.yudao.module.system.service.sms; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | +import cn.iocoder.yudao.framework.sms.core.client.SmsClient; | |
| 5 | 6 | import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; |
| 7 | +import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; | |
| 6 | 8 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 7 | 9 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelCreateReqVO; |
| 8 | 10 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; |
| 9 | 11 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelUpdateReqVO; |
| 12 | +import cn.iocoder.yudao.module.system.convert.sms.SmsChannelConvert; | |
| 10 | 13 | import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; |
| 11 | 14 | import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper; |
| 12 | 15 | import org.junit.jupiter.api.Test; |
| ... | ... | @@ -19,7 +22,8 @@ import java.util.List; |
| 19 | 22 | import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; |
| 20 | 23 | import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; |
| 21 | 24 | import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; |
| 22 | -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; | |
| 25 | +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; | |
| 26 | +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; | |
| 23 | 27 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; |
| 24 | 28 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN; |
| 25 | 29 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS; |
| ... | ... | @@ -42,27 +46,6 @@ public class SmsChannelServiceTest extends BaseDbUnitTest { |
| 42 | 46 | private SmsTemplateService smsTemplateService; |
| 43 | 47 | |
| 44 | 48 | @Test |
| 45 | - public void testInitLocalCache_success() { | |
| 46 | - // mock 数据 | |
| 47 | - SmsChannelDO smsChannelDO01 = randomPojo(SmsChannelDO.class); | |
| 48 | - smsChannelMapper.insert(smsChannelDO01); | |
| 49 | - SmsChannelDO smsChannelDO02 = randomPojo(SmsChannelDO.class); | |
| 50 | - smsChannelMapper.insert(smsChannelDO02); | |
| 51 | - | |
| 52 | - // 调用 | |
| 53 | - smsChannelService.initLocalCache(); | |
| 54 | - // 校验调用 | |
| 55 | - verify(smsClientFactory, times(1)).createOrUpdateSmsClient( | |
| 56 | - argThat(properties -> isPojoEquals(smsChannelDO01, properties))); | |
| 57 | - verify(smsClientFactory, times(1)).createOrUpdateSmsClient( | |
| 58 | - argThat(properties -> isPojoEquals(smsChannelDO02, properties))); | |
| 59 | - // 断言 channelCache 缓存 | |
| 60 | - assertEquals(2, smsChannelService.getChannelCache().size()); | |
| 61 | - assertPojoEquals(smsChannelDO01, smsChannelService.getChannelCache().get(0)); | |
| 62 | - assertPojoEquals(smsChannelDO02, smsChannelService.getChannelCache().get(1)); | |
| 63 | - } | |
| 64 | - | |
| 65 | - @Test | |
| 66 | 49 | public void testCreateSmsChannel_success() { |
| 67 | 50 | // 准备参数 |
| 68 | 51 | SmsChannelCreateReqVO reqVO = randomPojo(SmsChannelCreateReqVO.class, o -> o.setStatus(randomCommonStatus())); |
| ... | ... | @@ -74,6 +57,9 @@ public class SmsChannelServiceTest extends BaseDbUnitTest { |
| 74 | 57 | // 校验记录的属性是否正确 |
| 75 | 58 | SmsChannelDO smsChannel = smsChannelMapper.selectById(smsChannelId); |
| 76 | 59 | assertPojoEquals(reqVO, smsChannel); |
| 60 | + // 断言 cache | |
| 61 | + assertNull(smsChannelService.getIdClientCache().getIfPresent(smsChannel.getId())); | |
| 62 | + assertNull(smsChannelService.getCodeClientCache().getIfPresent(smsChannel.getCode())); | |
| 77 | 63 | } |
| 78 | 64 | |
| 79 | 65 | @Test |
| ... | ... | @@ -93,6 +79,9 @@ public class SmsChannelServiceTest extends BaseDbUnitTest { |
| 93 | 79 | // 校验是否更新正确 |
| 94 | 80 | SmsChannelDO smsChannel = smsChannelMapper.selectById(reqVO.getId()); // 获取最新的 |
| 95 | 81 | assertPojoEquals(reqVO, smsChannel); |
| 82 | + // 断言 cache | |
| 83 | + assertNull(smsChannelService.getIdClientCache().getIfPresent(smsChannel.getId())); | |
| 84 | + assertNull(smsChannelService.getCodeClientCache().getIfPresent(smsChannel.getCode())); | |
| 96 | 85 | } |
| 97 | 86 | |
| 98 | 87 | @Test |
| ... | ... | @@ -116,6 +105,9 @@ public class SmsChannelServiceTest extends BaseDbUnitTest { |
| 116 | 105 | smsChannelService.deleteSmsChannel(id); |
| 117 | 106 | // 校验数据不存在了 |
| 118 | 107 | assertNull(smsChannelMapper.selectById(id)); |
| 108 | + // 断言 cache | |
| 109 | + assertNull(smsChannelService.getIdClientCache().getIfPresent(dbSmsChannel.getId())); | |
| 110 | + assertNull(smsChannelService.getCodeClientCache().getIfPresent(dbSmsChannel.getCode())); | |
| 119 | 111 | } |
| 120 | 112 | |
| 121 | 113 | @Test |
| ... | ... | @@ -199,4 +191,46 @@ public class SmsChannelServiceTest extends BaseDbUnitTest { |
| 199 | 191 | assertPojoEquals(dbSmsChannel, pageResult.getList().get(0)); |
| 200 | 192 | } |
| 201 | 193 | |
| 194 | + @Test | |
| 195 | + public void testGetSmsClient_id() { | |
| 196 | + // mock 数据 | |
| 197 | + SmsChannelDO channel = randomPojo(SmsChannelDO.class); | |
| 198 | + smsChannelMapper.insert(channel); | |
| 199 | + // mock 参数 | |
| 200 | + Long id = channel.getId(); | |
| 201 | + // mock 方法 | |
| 202 | + SmsClient mockClient = mock(SmsClient.class); | |
| 203 | + when(smsClientFactory.getSmsClient(eq(id))).thenReturn(mockClient); | |
| 204 | + | |
| 205 | + // 调用 | |
| 206 | + SmsClient client = smsChannelService.getSmsClient(id); | |
| 207 | + // 断言 | |
| 208 | + assertSame(client, mockClient); | |
| 209 | + verify(smsClientFactory).createOrUpdateSmsClient(argThat(arg -> { | |
| 210 | + SmsChannelProperties properties = SmsChannelConvert.INSTANCE.convert02(channel); | |
| 211 | + return properties.equals(arg); | |
| 212 | + })); | |
| 213 | + } | |
| 214 | + | |
| 215 | + @Test | |
| 216 | + public void testGetSmsClient_code() { | |
| 217 | + // mock 数据 | |
| 218 | + SmsChannelDO channel = randomPojo(SmsChannelDO.class); | |
| 219 | + smsChannelMapper.insert(channel); | |
| 220 | + // mock 参数 | |
| 221 | + String code = channel.getCode(); | |
| 222 | + // mock 方法 | |
| 223 | + SmsClient mockClient = mock(SmsClient.class); | |
| 224 | + when(smsClientFactory.getSmsClient(eq(code))).thenReturn(mockClient); | |
| 225 | + | |
| 226 | + // 调用 | |
| 227 | + SmsClient client = smsChannelService.getSmsClient(code); | |
| 228 | + // 断言 | |
| 229 | + assertSame(client, mockClient); | |
| 230 | + verify(smsClientFactory).createOrUpdateSmsClient(argThat(arg -> { | |
| 231 | + SmsChannelProperties properties = SmsChannelConvert.INSTANCE.convert02(channel); | |
| 232 | + return properties.equals(arg); | |
| 233 | + })); | |
| 234 | + } | |
| 235 | + | |
| 202 | 236 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImplTest.java
| ... | ... | @@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.common.core.KeyValue; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 6 | 6 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 7 | 7 | import cn.iocoder.yudao.framework.sms.core.client.SmsClient; |
| 8 | -import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; | |
| 9 | 8 | import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; |
| 10 | 9 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 11 | 10 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; |
| ... | ... | @@ -52,9 +51,6 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { |
| 52 | 51 | @Mock |
| 53 | 52 | private SmsProducer smsProducer; |
| 54 | 53 | |
| 55 | - @Mock | |
| 56 | - private SmsClientFactory smsClientFactory; | |
| 57 | - | |
| 58 | 54 | @Test |
| 59 | 55 | public void testSendSingleSmsToAdmin() { |
| 60 | 56 | // 准备参数 |
| ... | ... | @@ -253,7 +249,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { |
| 253 | 249 | SmsSendMessage message = randomPojo(SmsSendMessage.class); |
| 254 | 250 | // mock SmsClientFactory 的方法 |
| 255 | 251 | SmsClient smsClient = spy(SmsClient.class); |
| 256 | - when(smsClientFactory.getSmsClient(eq(message.getChannelId()))).thenReturn(smsClient); | |
| 252 | + when(smsChannelService.getSmsClient(eq(message.getChannelId()))).thenReturn(smsClient); | |
| 257 | 253 | // mock SmsClient 的方法 |
| 258 | 254 | SmsCommonResult<SmsSendRespDTO> sendResult = randomPojo(SmsCommonResult.class, SmsSendRespDTO.class); |
| 259 | 255 | sendResult.setData(randomPojo(SmsSendRespDTO.class)); |
| ... | ... | @@ -275,7 +271,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { |
| 275 | 271 | String text = randomString(); |
| 276 | 272 | // mock SmsClientFactory 的方法 |
| 277 | 273 | SmsClient smsClient = spy(SmsClient.class); |
| 278 | - when(smsClientFactory.getSmsClient(eq(channelCode))).thenReturn(smsClient); | |
| 274 | + when(smsChannelService.getSmsClient(eq(channelCode))).thenReturn(smsClient); | |
| 279 | 275 | // mock SmsClient 的方法 |
| 280 | 276 | List<SmsReceiveRespDTO> receiveResults = randomPojoList(SmsReceiveRespDTO.class); |
| 281 | 277 | ... | ... |