Bladeren bron

缓存改造:SmsTemplate 使用 Redis 作为缓存

YunaiV 2 jaren geleden
bovenliggende
commit
68b49c6dd6

+ 8 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java

@@ -89,4 +89,12 @@ public interface RedisKeyConstants {
      * VALUE 数据格式:String 模版信息
      */
     String MAIL_TEMPLATE = "mail_template";
+
+    /**
+     * 短信模版的缓存
+     *
+     * KEY 格式:sms_template::{id}
+     * VALUE 数据格式:String 模版信息
+     */
+    String SMS_TEMPLATE = "sms_template";
 }

+ 0 - 29
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsTemplateRefreshConsumer.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.consumer.sms;
-
-import cn.iocoder.yudao.module.system.mq.message.sms.SmsTemplateRefreshMessage;
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.system.service.sms.SmsTemplateService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link SmsTemplateRefreshMessage} 的消费者
- *
- * @author 芋道源码
- */
-@Component
-@Slf4j
-public class SmsTemplateRefreshConsumer extends AbstractChannelMessageListener<SmsTemplateRefreshMessage> {
-
-    @Resource
-    private SmsTemplateService smsTemplateService;
-
-    @Override
-    public void onMessage(SmsTemplateRefreshMessage message) {
-        log.info("[onMessage][收到 SmsTemplate 刷新消息]");
-        smsTemplateService.initLocalCache();
-    }
-
-}

+ 0 - 21
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/sms/SmsTemplateRefreshMessage.java

@@ -1,21 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.message.sms;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-/**
- * 短信模板的数据刷新 Message
- *
- * @author 芋道源码
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-public class SmsTemplateRefreshMessage extends AbstractChannelMessage {
-
-    @Override
-    public String getChannel() {
-        return "system.sms-template.refresh";
-    }
-
-}

+ 1 - 10
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/sms/SmsProducer.java

@@ -1,10 +1,9 @@
 package cn.iocoder.yudao.module.system.mq.producer.sms;
 
 import cn.iocoder.yudao.framework.common.core.KeyValue;
+import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
 import cn.iocoder.yudao.module.system.mq.message.sms.SmsChannelRefreshMessage;
 import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage;
-import cn.iocoder.yudao.module.system.mq.message.sms.SmsTemplateRefreshMessage;
-import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 
@@ -32,14 +31,6 @@ public class SmsProducer {
         redisMQTemplate.send(message);
     }
 
-    /**
-     * 发送 {@link SmsTemplateRefreshMessage} 消息
-     */
-    public void sendSmsTemplateRefreshMessage() {
-        SmsTemplateRefreshMessage message = new SmsTemplateRefreshMessage();
-        redisMQTemplate.send(message);
-    }
-
     /**
      * 发送 {@link SmsSendMessage} 消息
      *

+ 15 - 35
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateService.java

@@ -16,40 +16,10 @@ import java.util.Map;
  * 短信模板 Service 接口
  *
  * @author zzf
- * @date 2021/1/25 9:24
+ * @since 2021/1/25 9:24
  */
 public interface SmsTemplateService {
 
-    /**
-     * 初始化短信模板的本地缓存
-     */
-    void initLocalCache();
-
-    /**
-     * 获得短信模板,从缓存中
-     *
-     * @param code 模板编码
-     * @return 短信模板
-     */
-    SmsTemplateDO getSmsTemplateByCodeFromCache(String code);
-
-    /**
-     * 格式化短信内容
-     *
-     * @param content 短信模板的内容
-     * @param params 内容的参数
-     * @return 格式化后的内容
-     */
-    String formatSmsTemplateContent(String content, Map<String, Object> params);
-
-    /**
-     * 获得短信模板
-     *
-     * @param code 模板编码
-     * @return 短信模板
-     */
-    SmsTemplateDO getSmsTemplateByCode(String code);
-
     /**
      * 创建短信模板
      *
@@ -81,12 +51,12 @@ public interface SmsTemplateService {
     SmsTemplateDO getSmsTemplate(Long id);
 
     /**
-     * 获得短信模板列表
+     * 获得短信模板,从缓存中
      *
-     * @param ids 编号
-     * @return 短信模板列表
+     * @param code 模板编码
+     * @return 短信模板
      */
-    List<SmsTemplateDO> getSmsTemplateList(Collection<Long> ids);
+    SmsTemplateDO getSmsTemplateByCodeFromCache(String code);
 
     /**
      * 获得短信模板分页
@@ -112,4 +82,14 @@ public interface SmsTemplateService {
      */
     Long countByChannelId(Long channelId);
 
+
+    /**
+     * 格式化短信内容
+     *
+     * @param content 短信模板的内容
+     * @param params 内容的参数
+     * @return 格式化后的内容
+     */
+    String formatSmsTemplateContent(String content, Map<String, Object> params);
+
 }

+ 22 - 57
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java

@@ -4,7 +4,6 @@ import cn.hutool.core.util.ReUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
 import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
 import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
@@ -17,16 +16,15 @@ import cn.iocoder.yudao.module.system.convert.sms.SmsTemplateConvert;
 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
 import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsTemplateMapper;
-import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
+import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
 import com.google.common.annotations.VisibleForTesting;
-import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
 import org.springframework.util.Assert;
 
-import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
-import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -59,49 +57,6 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
     @Resource
     private SmsClientFactory smsClientFactory;
 
-    @Resource
-    private SmsProducer smsProducer;
-
-    /**
-     * 短信模板缓存
-     * key:短信模板编码 {@link SmsTemplateDO#getCode()}
-     *
-     * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
-     */
-    @Getter // 为了方便测试,这里提供 getter 方法
-    private volatile Map<String, SmsTemplateDO> smsTemplateCache;
-
-    @Override
-    @PostConstruct
-    public void initLocalCache() {
-        // 第一步:查询数据
-        List<SmsTemplateDO> smsTemplateList = smsTemplateMapper.selectList();
-        log.info("[initLocalCache][缓存短信模版,数量为:{}]", smsTemplateList.size());
-
-        // 第二步:构建缓存
-        smsTemplateCache = CollectionUtils.convertMap(smsTemplateList, SmsTemplateDO::getCode);
-    }
-
-    @Override
-    public SmsTemplateDO getSmsTemplateByCodeFromCache(String code) {
-        return smsTemplateCache.get(code);
-    }
-
-    @Override
-    public String formatSmsTemplateContent(String content, Map<String, Object> params) {
-        return StrUtil.format(content, params);
-    }
-
-    @Override
-    public SmsTemplateDO getSmsTemplateByCode(String code) {
-        return smsTemplateMapper.selectByCode(code);
-    }
-
-    @VisibleForTesting
-    public List<String> parseTemplateContentParams(String content) {
-        return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
-    }
-
     @Override
     public Long createSmsTemplate(SmsTemplateCreateReqVO createReqVO) {
         // 校验短信渠道
@@ -116,13 +71,13 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
         template.setParams(parseTemplateContentParams(template.getContent()));
         template.setChannelCode(channelDO.getCode());
         smsTemplateMapper.insert(template);
-        // 发送刷新消息
-        smsProducer.sendSmsTemplateRefreshMessage();
         // 返回
         return template.getId();
     }
 
     @Override
+    @CacheEvict(cacheNames = RedisKeyConstants.SMS_TEMPLATE,
+            allEntries = true) // allEntries 清空所有缓存,因为可能修改到 code 字段,不好清理
     public void updateSmsTemplate(SmsTemplateUpdateReqVO updateReqVO) {
         // 校验存在
         validateSmsTemplateExists(updateReqVO.getId());
@@ -138,18 +93,16 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
         updateObj.setParams(parseTemplateContentParams(updateObj.getContent()));
         updateObj.setChannelCode(channelDO.getCode());
         smsTemplateMapper.updateById(updateObj);
-        // 发送刷新消息
-        smsProducer.sendSmsTemplateRefreshMessage();
     }
 
     @Override
+    @CacheEvict(cacheNames = RedisKeyConstants.SMS_TEMPLATE,
+            allEntries = true) // allEntries 清空所有缓存,因为 id 不是直接的缓存 code,不好清理
     public void deleteSmsTemplate(Long id) {
         // 校验存在
         validateSmsTemplateExists(id);
         // 更新
         smsTemplateMapper.deleteById(id);
-        // 发送刷新消息
-        smsProducer.sendSmsTemplateRefreshMessage();
     }
 
     private void validateSmsTemplateExists(Long id) {
@@ -164,8 +117,10 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
     }
 
     @Override
-    public List<SmsTemplateDO> getSmsTemplateList(Collection<Long> ids) {
-        return smsTemplateMapper.selectBatchIds(ids);
+    @Cacheable(cacheNames = RedisKeyConstants.SMS_TEMPLATE, key = "#code",
+            unless = "#result == null")
+    public SmsTemplateDO getSmsTemplateByCodeFromCache(String code) {
+        return smsTemplateMapper.selectByCode(code);
     }
 
     @Override
@@ -217,7 +172,7 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
      * @param apiTemplateId API 模板编号
      */
     @VisibleForTesting
-    public void validateApiTemplate(Long channelId, String apiTemplateId) {
+    void validateApiTemplate(Long channelId, String apiTemplateId) {
         // 获得短信模板
         SmsClient smsClient = smsClientFactory.getSmsClient(channelId);
         Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", channelId));
@@ -226,4 +181,14 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
         templateResult.checkError();
     }
 
+    @Override
+    public String formatSmsTemplateContent(String content, Map<String, Object> params) {
+        return StrUtil.format(content, params);
+    }
+
+    @VisibleForTesting
+    List<String> parseTemplateContentParams(String content) {
+        return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
+    }
+
 }

+ 0 - 24
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImplTest.java

@@ -7,14 +7,12 @@ import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccou
 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountUpdateReqVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper;
-import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.context.annotation.Import;
 
 import javax.annotation.Resource;
 import java.util.List;
-import java.util.Map;
 
 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
@@ -23,7 +21,6 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS;
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 /**
@@ -42,23 +39,6 @@ public class MailAccountServiceImplTest extends BaseDbUnitTest {
 
     @MockBean
     private MailTemplateService mailTemplateService;
-    @MockBean
-    private MailProducer mailProducer;
-
-    @Test
-    public void testInitLocalCache() {
-        MailAccountDO accountDO1 = randomPojo(MailAccountDO.class);
-        mailAccountMapper.insert(accountDO1);
-        MailAccountDO accountDO02 = randomPojo(MailAccountDO.class);
-        mailAccountMapper.insert(accountDO02);
-
-        // 调用
-        mailAccountService.initLocalCache();
-        // 断言 mailAccountCache 缓存
-        Map<Long, MailAccountDO> mailAccountCache = mailAccountService.getMailAccountCache();
-        assertPojoEquals(accountDO1, mailAccountCache.get(accountDO1.getId()));
-        assertPojoEquals(accountDO02, mailAccountCache.get(accountDO02.getId()));
-    }
 
     @Test
     public void testCreateMailAccount_success() {
@@ -72,7 +52,6 @@ public class MailAccountServiceImplTest extends BaseDbUnitTest {
         // 校验记录的属性是否正确
         MailAccountDO mailAccount = mailAccountMapper.selectById(mailAccountId);
         assertPojoEquals(reqVO, mailAccount);
-        verify(mailProducer).sendMailAccountRefreshMessage();
     }
 
     @Test
@@ -91,7 +70,6 @@ public class MailAccountServiceImplTest extends BaseDbUnitTest {
         // 校验是否更新正确
         MailAccountDO mailAccount = mailAccountMapper.selectById(reqVO.getId()); // 获取最新的
         assertPojoEquals(reqVO, mailAccount);
-        verify(mailProducer).sendMailAccountRefreshMessage();
     }
 
     @Test
@@ -117,7 +95,6 @@ public class MailAccountServiceImplTest extends BaseDbUnitTest {
         mailAccountService.deleteMailAccount(id);
        // 校验数据不存在了
        assertNull(mailAccountMapper.selectById(id));
-        verify(mailProducer).sendMailAccountRefreshMessage();
     }
 
     @Test
@@ -125,7 +102,6 @@ public class MailAccountServiceImplTest extends BaseDbUnitTest {
         // mock 数据
         MailAccountDO dbMailAccount = randomPojo(MailAccountDO.class);
         mailAccountMapper.insert(dbMailAccount);// @Sql: 先插入出一条存在的数据
-        mailAccountService.initLocalCache();
         // 准备参数
         Long id = dbMailAccount.getId();
 

+ 0 - 22
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImplTest.java

@@ -43,24 +43,6 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest {
     @Resource
     private MailTemplateMapper mailTemplateMapper;
 
-    @MockBean
-    private MailProducer mailProducer;
-
-    @Test
-    public void testInitLocalCache() {
-        MailTemplateDO templateDO01 = randomPojo(MailTemplateDO.class);
-        mailTemplateMapper.insert(templateDO01);
-        MailTemplateDO templateDO02 = randomPojo(MailTemplateDO.class);
-        mailTemplateMapper.insert(templateDO02);
-
-        // 调用
-        mailTemplateService.initLocalCache();
-        // 断言 mailTemplateCache 缓存
-        Map<String, MailTemplateDO> mailTemplateCache = mailTemplateService.getMailTemplateCache();
-        assertPojoEquals(templateDO01, mailTemplateCache.get(templateDO01.getCode()));
-        assertPojoEquals(templateDO02, mailTemplateCache.get(templateDO02.getCode()));
-    }
-
     @Test
     public void testCreateMailTemplate_success() {
         // 准备参数
@@ -73,7 +55,6 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest {
         // 校验记录的属性是否正确
         MailTemplateDO mailTemplate = mailTemplateMapper.selectById(mailTemplateId);
         assertPojoEquals(reqVO, mailTemplate);
-        verify(mailProducer).sendMailTemplateRefreshMessage();
     }
 
     @Test
@@ -91,7 +72,6 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest {
         // 校验是否更新正确
         MailTemplateDO mailTemplate = mailTemplateMapper.selectById(reqVO.getId()); // 获取最新的
         assertPojoEquals(reqVO, mailTemplate);
-        verify(mailProducer).sendMailTemplateRefreshMessage();
     }
 
     @Test
@@ -115,7 +95,6 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest {
         mailTemplateService.deleteMailTemplate(id);
         // 校验数据不存在了
         assertNull(mailTemplateMapper.selectById(id));
-        verify(mailProducer).sendMailTemplateRefreshMessage();
     }
 
     @Test
@@ -199,7 +178,6 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest {
         // mock 数据
         MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class);
         mailTemplateMapper.insert(dbMailTemplate);
-        mailTemplateService.initLocalCache();
         // 准备参数
         String code = dbMailTemplate.getCode();
 

+ 0 - 25
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java

@@ -55,25 +55,6 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
     private SmsClientFactory smsClientFactory;
     @MockBean
     private SmsClient smsClient;
-    @MockBean
-    private SmsProducer smsProducer;
-
-    @Test
-    void testInitLocalCache() {
-        // mock 数据
-        SmsTemplateDO smsTemplate01 = randomSmsTemplateDO();
-        smsTemplateMapper.insert(smsTemplate01);
-        SmsTemplateDO smsTemplate02 = randomSmsTemplateDO();
-        smsTemplateMapper.insert(smsTemplate02);
-
-        // 调用
-        smsTemplateService.initLocalCache();
-        // 断言 deptCache 缓存
-        Map<String, SmsTemplateDO> smsTemplateCache = smsTemplateService.getSmsTemplateCache();
-        assertEquals(2, smsTemplateCache.size());
-        assertPojoEquals(smsTemplate01, smsTemplateCache.get(smsTemplate01.getCode()));
-        assertPojoEquals(smsTemplate02, smsTemplateCache.get(smsTemplate02.getCode()));
-    }
 
     @Test
     public void testParseTemplateContentParams() {
@@ -116,8 +97,6 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
         assertPojoEquals(reqVO, smsTemplate);
         assertEquals(Lists.newArrayList("operation", "code"), smsTemplate.getParams());
         assertEquals(channelDO.getCode(), smsTemplate.getChannelCode());
-        // 校验调用
-        verify(smsProducer, times(1)).sendSmsTemplateRefreshMessage();
     }
 
     @Test
@@ -151,8 +130,6 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
         assertPojoEquals(reqVO, smsTemplate);
         assertEquals(Lists.newArrayList("operation", "code"), smsTemplate.getParams());
         assertEquals(channelDO.getCode(), smsTemplate.getChannelCode());
-        // 校验调用
-        verify(smsProducer, times(1)).sendSmsTemplateRefreshMessage();
     }
 
     @Test
@@ -176,8 +153,6 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
         smsTemplateService.deleteSmsTemplate(id);
        // 校验数据不存在了
        assertNull(smsTemplateMapper.selectById(id));
-        // 校验调用
-        verify(smsProducer, times(1)).sendSmsTemplateRefreshMessage();
     }
 
     @Test

+ 1 - 0
yudao-server/src/main/resources/application.yaml

@@ -195,6 +195,7 @@ yudao:
       - notify_template
       - mail_account
       - mail_template
+      - sms_template
   sms-code: # 短信验证码相关的配置项
     expire-times: 10m
     send-frequency: 1m