mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 20:28:44 +08:00 
			
		
		
		
	短信渠道的本地缓存,使用 Job 轮询,替代 MQ 广播
This commit is contained in:
		@@ -6,6 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
 | 
			
		||||
import org.apache.ibatis.annotations.Mapper;
 | 
			
		||||
import org.apache.ibatis.annotations.Select;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
 | 
			
		||||
@Mapper
 | 
			
		||||
public interface SmsChannelMapper extends BaseMapperX<SmsChannelDO> {
 | 
			
		||||
@@ -18,4 +21,7 @@ public interface SmsChannelMapper extends BaseMapperX<SmsChannelDO> {
 | 
			
		||||
                .orderByDesc(SmsChannelDO::getId));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Select("SELECT COUNT(*) FROM system_sms_channel WHERE update_time > #{maxUpdateTime}")
 | 
			
		||||
    Long selectCountByUpdateTimeGt(LocalDateTime maxTime);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,29 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.mq.consumer.sms;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
 | 
			
		||||
import cn.iocoder.yudao.module.system.mq.message.sms.SmsChannelRefreshMessage;
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.sms.SmsChannelService;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 针对 {@link SmsChannelRefreshMessage} 的消费者
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
@Slf4j
 | 
			
		||||
public class SmsChannelRefreshConsumer extends AbstractChannelMessageListener<SmsChannelRefreshMessage> {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private SmsChannelService smsChannelService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onMessage(SmsChannelRefreshMessage message) {
 | 
			
		||||
        log.info("[onMessage][收到 SmsChannel 刷新消息]");
 | 
			
		||||
        smsChannelService.initLocalCache();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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 SmsChannelRefreshMessage extends AbstractChannelMessage {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getChannel() {
 | 
			
		||||
        return "system.sms-channel.refresh";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -2,7 +2,6 @@ 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 lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
@@ -23,14 +22,6 @@ public class SmsProducer {
 | 
			
		||||
    @Resource
 | 
			
		||||
    private RedisMQTemplate redisMQTemplate;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 发送 {@link SmsChannelRefreshMessage} 消息
 | 
			
		||||
     */
 | 
			
		||||
    public void sendSmsChannelRefreshMessage() {
 | 
			
		||||
        SmsChannelRefreshMessage message = new SmsChannelRefreshMessage();
 | 
			
		||||
        redisMQTemplate.send(message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 发送 {@link SmsSendMessage} 消息
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.service.sms;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
 | 
			
		||||
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
 | 
			
		||||
@@ -9,15 +10,20 @@ import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannel
 | 
			
		||||
import cn.iocoder.yudao.module.system.convert.sms.SmsChannelConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper;
 | 
			
		||||
import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.scheduling.annotation.Scheduled;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.PostConstruct;
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue;
 | 
			
		||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN;
 | 
			
		||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS;
 | 
			
		||||
 | 
			
		||||
@@ -30,6 +36,12 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNE
 | 
			
		||||
@Slf4j
 | 
			
		||||
public class SmsChannelServiceImpl implements SmsChannelService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 短信渠道列表的缓存
 | 
			
		||||
     */
 | 
			
		||||
    @Getter
 | 
			
		||||
    private volatile List<SmsChannelDO> channelCache = Collections.emptyList();
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private SmsClientFactory smsClientFactory;
 | 
			
		||||
 | 
			
		||||
@@ -39,9 +51,6 @@ public class SmsChannelServiceImpl implements SmsChannelService {
 | 
			
		||||
    @Resource
 | 
			
		||||
    private SmsTemplateService smsTemplateService;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private SmsProducer smsProducer;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @PostConstruct
 | 
			
		||||
    public void initLocalCache() {
 | 
			
		||||
@@ -52,6 +61,27 @@ public class SmsChannelServiceImpl implements SmsChannelService {
 | 
			
		||||
        // 第二步:构建缓存:创建或更新短信 Client
 | 
			
		||||
        List<SmsChannelProperties> propertiesList = SmsChannelConvert.INSTANCE.convertList02(channels);
 | 
			
		||||
        propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties));
 | 
			
		||||
        this.channelCache = channels;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通过定时任务轮询,刷新缓存
 | 
			
		||||
     *
 | 
			
		||||
     * 目的:多节点部署时,通过轮询”通知“所有节点,进行刷新
 | 
			
		||||
     */
 | 
			
		||||
    @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS)
 | 
			
		||||
    public void refreshLocalCache() {
 | 
			
		||||
        // 情况一:如果缓存里没有数据,则直接刷新缓存
 | 
			
		||||
        if (CollUtil.isEmpty(channelCache)) {
 | 
			
		||||
            initLocalCache();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存
 | 
			
		||||
        LocalDateTime maxTime = getMaxValue(channelCache, SmsChannelDO::getUpdateTime);
 | 
			
		||||
        if (smsChannelMapper.selectCountByUpdateTimeGt(maxTime) > 0) {
 | 
			
		||||
            initLocalCache();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -59,9 +89,9 @@ public class SmsChannelServiceImpl implements SmsChannelService {
 | 
			
		||||
        // 插入
 | 
			
		||||
        SmsChannelDO smsChannel = SmsChannelConvert.INSTANCE.convert(createReqVO);
 | 
			
		||||
        smsChannelMapper.insert(smsChannel);
 | 
			
		||||
        // 发送刷新消息
 | 
			
		||||
        smsProducer.sendSmsChannelRefreshMessage();
 | 
			
		||||
        // 返回
 | 
			
		||||
 | 
			
		||||
        // 刷新缓存
 | 
			
		||||
        initLocalCache();
 | 
			
		||||
        return smsChannel.getId();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -72,8 +102,9 @@ public class SmsChannelServiceImpl implements SmsChannelService {
 | 
			
		||||
        // 更新
 | 
			
		||||
        SmsChannelDO updateObj = SmsChannelConvert.INSTANCE.convert(updateReqVO);
 | 
			
		||||
        smsChannelMapper.updateById(updateObj);
 | 
			
		||||
        // 发送刷新消息
 | 
			
		||||
        smsProducer.sendSmsChannelRefreshMessage();
 | 
			
		||||
 | 
			
		||||
        // 刷新缓存
 | 
			
		||||
        initLocalCache();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -86,8 +117,9 @@ public class SmsChannelServiceImpl implements SmsChannelService {
 | 
			
		||||
        }
 | 
			
		||||
        // 删除
 | 
			
		||||
        smsChannelMapper.deleteById(id);
 | 
			
		||||
        // 发送刷新消息
 | 
			
		||||
        smsProducer.sendSmsChannelRefreshMessage();
 | 
			
		||||
 | 
			
		||||
        // 刷新缓存
 | 
			
		||||
        initLocalCache();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void validateSmsChannelExists(Long id) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user