Commit d3200910dbf9452a4ee5e58d4fdd5f4273ece513

Authored by YunaiV
1 parent d1271f8b

基于 Guava 实现 dict 字典数据的本地缓存

Showing 18 changed files with 184 additions and 289 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/cache/CacheUtils.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.common.util.cache;
  2 +
  3 +import com.google.common.cache.CacheBuilder;
  4 +import com.google.common.cache.CacheLoader;
  5 +import com.google.common.cache.LoadingCache;
  6 +
  7 +import java.time.Duration;
  8 +import java.util.concurrent.Executors;
  9 +
  10 +/**
  11 + * Cache 工具类
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +public class CacheUtils {
  16 +
  17 + public static <K, V> LoadingCache<K, V> buildAsyncReloadingCache(Duration duration, CacheLoader<K, V> loader) {
  18 + return CacheBuilder.newBuilder()
  19 + // 只阻塞当前数据加载线程,其他线程返回旧值
  20 + .refreshAfterWrite(duration)
  21 + // 通过 asyncReloading 实现全异步加载,包括 refreshAfterWrite 被阻塞的加载线程
  22 + .build(CacheLoader.asyncReloading(loader, Executors.newCachedThreadPool())); // TODO 芋艿:可能要思考下,未来要不要做成可配置
  23 + }
  24 +
  25 +}
yudao-framework/yudao-spring-boot-starter-biz-dict/pom.xml
@@ -26,5 +26,18 @@ @@ -26,5 +26,18 @@
26 <groupId>org.springframework.boot</groupId> 26 <groupId>org.springframework.boot</groupId>
27 <artifactId>spring-boot-starter</artifactId> 27 <artifactId>spring-boot-starter</artifactId>
28 </dependency> 28 </dependency>
  29 +
  30 + <!-- 业务组件 -->
  31 + <dependency>
  32 + <groupId>cn.iocoder.boot</groupId>
  33 + <artifactId>yudao-module-system-api</artifactId> <!-- 需要使用它,进行 Token 的校验 -->
  34 + <version>${revision}</version>
  35 + </dependency>
  36 +
  37 + <!-- 工具类相关 -->
  38 + <dependency>
  39 + <groupId>com.google.guava</groupId>
  40 + <artifactId>guava</artifactId>
  41 + </dependency>
29 </dependencies> 42 </dependencies>
30 </project> 43 </project>
yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/config/YudaoDictAutoConfiguration.java
1 package cn.iocoder.yudao.framework.dict.config; 1 package cn.iocoder.yudao.framework.dict.config;
2 2
3 -import cn.iocoder.yudao.framework.dict.core.service.DictDataFrameworkService;  
4 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; 3 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
  4 +import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
5 import org.springframework.context.annotation.Bean; 5 import org.springframework.context.annotation.Bean;
6 import org.springframework.context.annotation.Configuration; 6 import org.springframework.context.annotation.Configuration;
7 7
@@ -10,8 +10,8 @@ public class YudaoDictAutoConfiguration { @@ -10,8 +10,8 @@ public class YudaoDictAutoConfiguration {
10 10
11 @Bean 11 @Bean
12 @SuppressWarnings("InstantiationOfUtilityClass") 12 @SuppressWarnings("InstantiationOfUtilityClass")
13 - public DictFrameworkUtils dictUtils(DictDataFrameworkService service) {  
14 - DictFrameworkUtils.init(service); 13 + public DictFrameworkUtils dictUtils(DictDataApi dictDataApi) {
  14 + DictFrameworkUtils.init(dictDataApi);
15 return new DictFrameworkUtils(); 15 return new DictFrameworkUtils();
16 } 16 }
17 17
yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/core/package-info.java 0 → 100644
  1 +/**
  2 + * 占位
  3 + */
  4 +package cn.iocoder.yudao.framework.dict.core;
yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/core/service/DictDataFrameworkService.java deleted
1 -package cn.iocoder.yudao.framework.dict.core.service;  
2 -  
3 -import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;  
4 -  
5 -public interface DictDataFrameworkService {  
6 -  
7 - /**  
8 - * 获得指定的字典数据,从缓存中  
9 - *  
10 - * @param type 字典类型  
11 - * @param value 字典数据值  
12 - * @return 字典数据  
13 - */  
14 - DictDataRespDTO getDictDataFromCache(String type, String value);  
15 -  
16 - /**  
17 - * 解析获得指定的字典数据,从缓存中  
18 - *  
19 - * @param type 字典类型  
20 - * @param label 字典数据标签  
21 - * @return 字典数据  
22 - */  
23 - DictDataRespDTO parseDictDataFromCache(String type, String label);  
24 -  
25 -}  
yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtils.java
1 package cn.iocoder.yudao.framework.dict.core.util; 1 package cn.iocoder.yudao.framework.dict.core.util;
2 2
3 -import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;  
4 -import cn.iocoder.yudao.framework.dict.core.service.DictDataFrameworkService; 3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.framework.common.core.KeyValue;
  5 +import cn.iocoder.yudao.framework.common.util.cache.CacheUtils;
  6 +import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
  7 +import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
  8 +import com.google.common.cache.CacheLoader;
  9 +import com.google.common.cache.LoadingCache;
  10 +import lombok.SneakyThrows;
5 import lombok.extern.slf4j.Slf4j; 11 import lombok.extern.slf4j.Slf4j;
6 12
  13 +import java.time.Duration;
  14 +
7 /** 15 /**
8 * 字典工具类 16 * 字典工具类
  17 + *
  18 + * @author 芋道源码
9 */ 19 */
10 @Slf4j 20 @Slf4j
11 public class DictFrameworkUtils { 21 public class DictFrameworkUtils {
12 22
13 - private static DictDataFrameworkService service; 23 + private static DictDataApi dictDataApi;
  24 +
  25 + private static final DictDataRespDTO DICT_DATA_NULL = new DictDataRespDTO();
  26 +
  27 + /**
  28 + * 针对 {@link #getDictDataLabel(String, String)} 的缓存
  29 + */
  30 + private static final LoadingCache<KeyValue<String, String>, DictDataRespDTO> getDictDataCache = CacheUtils.buildAsyncReloadingCache(
  31 + Duration.ofMinutes(1L), // 过期时间 1 分钟
  32 + new CacheLoader<KeyValue<String, String>, DictDataRespDTO>() {
  33 +
  34 + @Override
  35 + public DictDataRespDTO load(KeyValue<String, String> key) {
  36 + return ObjectUtil.defaultIfNull(dictDataApi.getDictData(key.getKey(), key.getValue()), DICT_DATA_NULL);
  37 + }
  38 +
  39 + });
  40 +
  41 + /**
  42 + * 针对 {@link #parseDictDataValue(String, String)} 的缓存
  43 + */
  44 + private static final LoadingCache<KeyValue<String, String>, DictDataRespDTO> parseDictDataCache = CacheUtils.buildAsyncReloadingCache(
  45 + Duration.ofMinutes(1L), // 过期时间 1 分钟
  46 + new CacheLoader<KeyValue<String, String>, DictDataRespDTO>() {
  47 +
  48 + @Override
  49 + public DictDataRespDTO load(KeyValue<String, String> key) {
  50 + return ObjectUtil.defaultIfNull(dictDataApi.parseDictData(key.getKey(), key.getValue()), DICT_DATA_NULL);
  51 + }
  52 +
  53 + });
14 54
15 - public static void init(DictDataFrameworkService service) {  
16 - DictFrameworkUtils.service = service; 55 + public static void init(DictDataApi dictDataApi) {
  56 + DictFrameworkUtils.dictDataApi = dictDataApi;
17 log.info("[init][初始化 DictFrameworkUtils 成功]"); 57 log.info("[init][初始化 DictFrameworkUtils 成功]");
18 } 58 }
19 59
20 - public static DictDataRespDTO getDictDataFromCache(String type, String value) {  
21 - return service.getDictDataFromCache(type, value); 60 + @SneakyThrows
  61 + public static String getDictDataLabel(String dictType, String value) {
  62 + return getDictDataCache.get(new KeyValue<>(dictType, value)).getLabel();
22 } 63 }
23 64
24 - public static DictDataRespDTO parseDictDataFromCache(String type, String label) {  
25 - return service.parseDictDataFromCache(type, label); 65 + @SneakyThrows
  66 + public static String parseDictDataValue(String dictType, String label) {
  67 + return parseDictDataCache.get(new KeyValue<>(dictType, label)).getValue();
26 } 68 }
27 69
28 } 70 }
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/DictConvert.java
1 package cn.iocoder.yudao.framework.excel.core.convert; 1 package cn.iocoder.yudao.framework.excel.core.convert;
2 2
3 import cn.hutool.core.convert.Convert; 3 import cn.hutool.core.convert.Convert;
4 -import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;  
5 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; 4 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
6 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; 5 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
7 import com.alibaba.excel.converters.Converter; 6 import com.alibaba.excel.converters.Converter;
@@ -12,7 +11,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; @@ -12,7 +11,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
12 import lombok.extern.slf4j.Slf4j; 11 import lombok.extern.slf4j.Slf4j;
13 12
14 /** 13 /**
15 - * Excel {@link DictDataRespDTO} 数据字典转换器 14 + * Excel 数据字典转换器
16 * 15 *
17 * @author 芋道源码 16 * @author 芋道源码
18 */ 17 */
@@ -35,14 +34,14 @@ public class DictConvert implements Converter&lt;Object&gt; { @@ -35,14 +34,14 @@ public class DictConvert implements Converter&lt;Object&gt; {
35 // 使用字典解析 34 // 使用字典解析
36 String type = getType(contentProperty); 35 String type = getType(contentProperty);
37 String label = cellData.getStringValue(); 36 String label = cellData.getStringValue();
38 - DictDataRespDTO dictData = DictFrameworkUtils.parseDictDataFromCache(type, label);  
39 - if (dictData == null) { 37 + String value = DictFrameworkUtils.parseDictDataValue(type, label);
  38 + if (value == null) {
40 log.error("[convertToJavaData][type({}) 解析不掉 label({})]", type, label); 39 log.error("[convertToJavaData][type({}) 解析不掉 label({})]", type, label);
41 return null; 40 return null;
42 } 41 }
43 // 将 String 的 value 转换成对应的属性 42 // 将 String 的 value 转换成对应的属性
44 Class<?> fieldClazz = contentProperty.getField().getType(); 43 Class<?> fieldClazz = contentProperty.getField().getType();
45 - return Convert.convert(fieldClazz, dictData.getValue()); 44 + return Convert.convert(fieldClazz, value);
46 } 45 }
47 46
48 @Override 47 @Override
@@ -56,13 +55,13 @@ public class DictConvert implements Converter&lt;Object&gt; { @@ -56,13 +55,13 @@ public class DictConvert implements Converter&lt;Object&gt; {
56 // 使用字典格式化 55 // 使用字典格式化
57 String type = getType(contentProperty); 56 String type = getType(contentProperty);
58 String value = String.valueOf(object); 57 String value = String.valueOf(object);
59 - DictDataRespDTO dictData = DictFrameworkUtils.getDictDataFromCache(type, value);  
60 - if (dictData == null) { 58 + String label = DictFrameworkUtils.getDictDataLabel(type, value);
  59 + if (label == null) {
61 log.error("[convertToExcelData][type({}) 转换不了 label({})]", type, value); 60 log.error("[convertToExcelData][type({}) 转换不了 label({})]", type, value);
62 return new CellData<>(""); 61 return new CellData<>("");
63 } 62 }
64 // 生成 Excel 小表格 63 // 生成 Excel 小表格
65 - return new CellData<>(dictData.getLabel()); 64 + return new CellData<>(label);
66 } 65 }
67 66
68 private static String getType(ExcelContentProperty contentProperty) { 67 private static String getType(ExcelContentProperty contentProperty) {
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java
1 package cn.iocoder.yudao.module.system.api.dict; 1 package cn.iocoder.yudao.module.system.api.dict;
2 2
  3 +import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
  4 +
3 import java.util.Collection; 5 import java.util.Collection;
4 6
5 /** 7 /**
@@ -19,4 +21,22 @@ public interface DictDataApi { @@ -19,4 +21,22 @@ public interface DictDataApi {
19 */ 21 */
20 void validDictDatas(String dictType, Collection<String> values); 22 void validDictDatas(String dictType, Collection<String> values);
21 23
  24 + /**
  25 + * 获得指定的字典数据,从缓存中
  26 + *
  27 + * @param type 字典类型
  28 + * @param value 字典数据值
  29 + * @return 字典数据
  30 + */
  31 + DictDataRespDTO getDictData(String type, String value);
  32 +
  33 + /**
  34 + * 解析获得指定的字典数据,从缓存中
  35 + *
  36 + * @param type 字典类型
  37 + * @param label 字典数据标签
  38 + * @return 字典数据
  39 + */
  40 + DictDataRespDTO parseDictData(String type, String label);
  41 +
22 } 42 }
yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/core/dto/DictDataRespDTO.java renamed to yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/dto/DictDataRespDTO.java
1 -package cn.iocoder.yudao.framework.dict.core.dto; 1 +package cn.iocoder.yudao.module.system.api.dict.dto;
2 2
3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 import lombok.Data; 4 import lombok.Data;
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApiImpl.java
1 package cn.iocoder.yudao.module.system.api.dict; 1 package cn.iocoder.yudao.module.system.api.dict;
2 2
  3 +import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
  4 +import cn.iocoder.yudao.module.system.convert.dict.DictDataConvert;
  5 +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
3 import cn.iocoder.yudao.module.system.service.dict.DictDataService; 6 import cn.iocoder.yudao.module.system.service.dict.DictDataService;
4 import org.springframework.stereotype.Service; 7 import org.springframework.stereotype.Service;
5 8
@@ -22,4 +25,16 @@ public class DictDataApiImpl implements DictDataApi { @@ -22,4 +25,16 @@ public class DictDataApiImpl implements DictDataApi {
22 dictDataService.validDictDatas(dictType, values); 25 dictDataService.validDictDatas(dictType, values);
23 } 26 }
24 27
  28 + @Override
  29 + public DictDataRespDTO getDictData(String dictType, String value) {
  30 + DictDataDO dictData = dictDataService.getDictData(dictType, value);
  31 + return DictDataConvert.INSTANCE.convert02(dictData);
  32 + }
  33 +
  34 + @Override
  35 + public DictDataRespDTO parseDictData(String dictType, String label) {
  36 + DictDataDO dictData = dictDataService.parseDictData(dictType, label);
  37 + return DictDataConvert.INSTANCE.convert02(dictData);
  38 + }
  39 +
25 } 40 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/dict/DictDataConvert.java
1 package cn.iocoder.yudao.module.system.convert.dict; 1 package cn.iocoder.yudao.module.system.convert.dict;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
3 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.*; 5 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.*;
4 import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; 6 import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
5 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
6 -import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;  
7 import org.mapstruct.Mapper; 7 import org.mapstruct.Mapper;
8 import org.mapstruct.factory.Mappers; 8 import org.mapstruct.factory.Mappers;
9 9
@@ -29,6 +29,4 @@ public interface DictDataConvert { @@ -29,6 +29,4 @@ public interface DictDataConvert {
29 29
30 DictDataRespDTO convert02(DictDataDO bean); 30 DictDataRespDTO convert02(DictDataDO bean);
31 31
32 - List<DictDataRespDTO> convertList03(Collection<DictDataDO> list);  
33 -  
34 } 32 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dict/DictDataMapper.java
@@ -8,11 +8,9 @@ import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPage @@ -8,11 +8,9 @@ import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPage
8 import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; 8 import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
9 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 9 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
10 import org.apache.ibatis.annotations.Mapper; 10 import org.apache.ibatis.annotations.Mapper;
11 -import org.apache.ibatis.annotations.Select;  
12 11
13 import java.util.Arrays; 12 import java.util.Arrays;
14 import java.util.Collection; 13 import java.util.Collection;
15 -import java.util.Date;  
16 import java.util.List; 14 import java.util.List;
17 15
18 @Mapper 16 @Mapper
@@ -23,6 +21,11 @@ public interface DictDataMapper extends BaseMapperX&lt;DictDataDO&gt; { @@ -23,6 +21,11 @@ public interface DictDataMapper extends BaseMapperX&lt;DictDataDO&gt; {
23 .eq(DictDataDO::getValue, value)); 21 .eq(DictDataDO::getValue, value));
24 } 22 }
25 23
  24 + default DictDataDO selectByDictTypeAndLabel(String dictType, String label) {
  25 + return selectOne(new LambdaQueryWrapper<DictDataDO>().eq(DictDataDO::getDictType, dictType)
  26 + .eq(DictDataDO::getLabel, label));
  27 + }
  28 +
26 default List<DictDataDO> selectByDictTypeAndValues(String dictType, Collection<String> values) { 29 default List<DictDataDO> selectByDictTypeAndValues(String dictType, Collection<String> values) {
27 return selectList(new LambdaQueryWrapper<DictDataDO>().eq(DictDataDO::getDictType, dictType) 30 return selectList(new LambdaQueryWrapper<DictDataDO>().eq(DictDataDO::getDictType, dictType)
28 .in(DictDataDO::getValue, values)); 31 .in(DictDataDO::getValue, values));
@@ -46,7 +49,4 @@ public interface DictDataMapper extends BaseMapperX&lt;DictDataDO&gt; { @@ -46,7 +49,4 @@ public interface DictDataMapper extends BaseMapperX&lt;DictDataDO&gt; {
46 .eqIfPresent(DictDataDO::getStatus, reqVO.getStatus())); 49 .eqIfPresent(DictDataDO::getStatus, reqVO.getStatus()));
47 } 50 }
48 51
49 - @Select("SELECT COUNT(*) FROM system_dict_data WHERE update_time > #{maxUpdateTime}")  
50 - Long selectCountByUpdateTimeGt(Date maxUpdateTime);  
51 -  
52 } 52 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/dict/DictDataRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.system.mq.consumer.dict;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
4 -import cn.iocoder.yudao.module.system.mq.message.dict.DictDataRefreshMessage;  
5 -import cn.iocoder.yudao.module.system.service.dict.DictDataService;  
6 -import lombok.extern.slf4j.Slf4j;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 针对 {@link DictDataRefreshMessage} 的消费者  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Component  
17 -@Slf4j  
18 -public class DictDataRefreshConsumer extends AbstractChannelMessageListener<DictDataRefreshMessage> {  
19 -  
20 - @Resource  
21 - private DictDataService dictDataService;  
22 -  
23 - @Override  
24 - public void onMessage(DictDataRefreshMessage message) {  
25 - log.info("[onMessage][收到 DictData 刷新消息]");  
26 - dictDataService.initLocalCache();  
27 - }  
28 -  
29 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/dict/DictDataRefreshMessage.java deleted
1 -package cn.iocoder.yudao.module.system.mq.message.dict;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;  
4 -import lombok.Data;  
5 -import lombok.EqualsAndHashCode;  
6 -  
7 -/**  
8 - * 字典数据数据刷新 Message  
9 - */  
10 -@Data  
11 -@EqualsAndHashCode(callSuper = true)  
12 -public class DictDataRefreshMessage extends AbstractChannelMessage {  
13 -  
14 - @Override  
15 - public String getChannel() {  
16 - return "system.dict-data.refresh";  
17 - }  
18 -  
19 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/dict/DictDataProducer.java deleted
1 -package cn.iocoder.yudao.module.system.mq.producer.dict;  
2 -  
3 -import cn.iocoder.yudao.module.system.mq.message.dict.DictDataRefreshMessage;  
4 -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;  
5 -import org.springframework.stereotype.Component;  
6 -  
7 -import javax.annotation.Resource;  
8 -  
9 -/**  
10 - * DictData 字典数据相关消息的 Producer  
11 - */  
12 -@Component  
13 -public class DictDataProducer {  
14 -  
15 - @Resource  
16 - private RedisMQTemplate redisMQTemplate;  
17 -  
18 - /**  
19 - * 发送 {@link DictDataRefreshMessage} 消息  
20 - */  
21 - public void sendDictDataRefreshMessage() {  
22 - DictDataRefreshMessage message = new DictDataRefreshMessage();  
23 - redisMQTemplate.send(message);  
24 - }  
25 -  
26 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataService.java
1 package cn.iocoder.yudao.module.system.service.dict; 1 package cn.iocoder.yudao.module.system.service.dict;
2 2
3 -import cn.iocoder.yudao.framework.dict.core.service.DictDataFrameworkService;  
4 -import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;  
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataCreateReqVO; 4 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataCreateReqVO;
7 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataExportReqVO; 5 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataExportReqVO;
8 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO; 6 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO;
9 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataUpdateReqVO; 7 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataUpdateReqVO;
  8 +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
10 9
11 import java.util.Collection; 10 import java.util.Collection;
12 import java.util.List; 11 import java.util.List;
@@ -16,12 +15,7 @@ import java.util.List; @@ -16,12 +15,7 @@ import java.util.List;
16 * 15 *
17 * @author ruoyi 16 * @author ruoyi
18 */ 17 */
19 -public interface DictDataService extends DictDataFrameworkService {  
20 -  
21 - /**  
22 - * 初始化字典数据的本地缓存  
23 - */  
24 - void initLocalCache(); 18 +public interface DictDataService {
25 19
26 /** 20 /**
27 * 创建字典数据 21 * 创建字典数据
@@ -94,4 +88,21 @@ public interface DictDataService extends DictDataFrameworkService { @@ -94,4 +88,21 @@ public interface DictDataService extends DictDataFrameworkService {
94 */ 88 */
95 void validDictDatas(String dictType, Collection<String> values); 89 void validDictDatas(String dictType, Collection<String> values);
96 90
  91 + /**
  92 + * 获得指定的字典数据
  93 + *
  94 + * @param dictType 字典类型
  95 + * @param value 字典数据值
  96 + * @return 字典数据
  97 + */
  98 + DictDataDO getDictData(String dictType, String value);
  99 +
  100 + /**
  101 + * 解析获得指定的字典数据,从缓存中
  102 + *
  103 + * @param dictType 字典类型
  104 + * @param label 字典数据标签
  105 + * @return 字典数据
  106 + */
  107 + DictDataDO parseDictData(String dictType, String label);
97 } 108 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImpl.java
@@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil; @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
7 -import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;  
8 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataCreateReqVO; 7 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataCreateReqVO;
9 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataExportReqVO; 8 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataExportReqVO;
10 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO; 9 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO;
@@ -13,20 +12,15 @@ import cn.iocoder.yudao.module.system.convert.dict.DictDataConvert; @@ -13,20 +12,15 @@ import cn.iocoder.yudao.module.system.convert.dict.DictDataConvert;
13 import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; 12 import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
14 import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO; 13 import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO;
15 import cn.iocoder.yudao.module.system.dal.mysql.dict.DictDataMapper; 14 import cn.iocoder.yudao.module.system.dal.mysql.dict.DictDataMapper;
16 -import cn.iocoder.yudao.module.system.mq.producer.dict.DictDataProducer;  
17 import com.google.common.annotations.VisibleForTesting; 15 import com.google.common.annotations.VisibleForTesting;
18 -import com.google.common.collect.ImmutableMap;  
19 -import com.google.common.collect.ImmutableTable;  
20 import lombok.extern.slf4j.Slf4j; 16 import lombok.extern.slf4j.Slf4j;
21 -import org.springframework.scheduling.annotation.Scheduled;  
22 import org.springframework.stereotype.Service; 17 import org.springframework.stereotype.Service;
23 18
24 -import javax.annotation.PostConstruct;  
25 import javax.annotation.Resource; 19 import javax.annotation.Resource;
26 import java.util.Collection; 20 import java.util.Collection;
27 import java.util.Comparator; 21 import java.util.Comparator;
28 -import java.util.Date;  
29 import java.util.List; 22 import java.util.List;
  23 +import java.util.Map;
30 24
31 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 25 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
32 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; 26 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
@@ -47,88 +41,12 @@ public class DictDataServiceImpl implements DictDataService { @@ -47,88 +41,12 @@ public class DictDataServiceImpl implements DictDataService {
47 .comparing(DictDataDO::getDictType) 41 .comparing(DictDataDO::getDictType)
48 .thenComparingInt(DictDataDO::getSort); 42 .thenComparingInt(DictDataDO::getSort);
49 43
50 - /**  
51 - * 定时执行 {@link #schedulePeriodicRefresh()} 的周期  
52 - * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高  
53 - */  
54 - private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;  
55 -  
56 @Resource 44 @Resource
57 private DictTypeService dictTypeService; 45 private DictTypeService dictTypeService;
58 46
59 @Resource 47 @Resource
60 private DictDataMapper dictDataMapper; 48 private DictDataMapper dictDataMapper;
61 49
62 - @Resource  
63 - private DictDataProducer dictDataProducer;  
64 -  
65 - /**  
66 - * 字典数据缓存,第二个 key 使用 label  
67 - *  
68 - * key1:字典类型 dictType  
69 - * key2:字典标签 label  
70 - */  
71 - private ImmutableTable<String, String, DictDataDO> labelDictDataCache;  
72 - /**  
73 - * 字典数据缓存,第二个 key 使用 value  
74 - *  
75 - * key1:字典类型 dictType  
76 - * key2:字典值 value  
77 - */  
78 - private ImmutableTable<String, String, DictDataDO> valueDictDataCache;  
79 - /**  
80 - * 缓存字典数据的最大更新时间,用于后续的增量轮询,判断是否有更新  
81 - */  
82 - private volatile Date maxUpdateTime;  
83 -  
84 - @Override  
85 - @PostConstruct  
86 - public synchronized void initLocalCache() {  
87 - // 获取字典数据列表,如果有更新  
88 - List<DictDataDO> dataList = loadDictDataIfUpdate(maxUpdateTime);  
89 - if (CollUtil.isEmpty(dataList)) {  
90 - return;  
91 - }  
92 -  
93 - // 构建缓存  
94 - ImmutableTable.Builder<String, String, DictDataDO> labelDictDataBuilder = ImmutableTable.builder();  
95 - ImmutableTable.Builder<String, String, DictDataDO> valueDictDataBuilder = ImmutableTable.builder();  
96 - dataList.forEach(dictData -> {  
97 - labelDictDataBuilder.put(dictData.getDictType(), dictData.getLabel(), dictData);  
98 - valueDictDataBuilder.put(dictData.getDictType(), dictData.getValue(), dictData);  
99 - });  
100 - labelDictDataCache = labelDictDataBuilder.build();  
101 - valueDictDataCache = valueDictDataBuilder.build();  
102 - maxUpdateTime = CollectionUtils.getMaxValue(dataList, DictDataDO::getUpdateTime);  
103 - log.info("[initLocalCache][缓存字典数据,数量为:{}]", dataList.size());  
104 - }  
105 -  
106 - /**  
107 - * 如果字典数据发生变化,从数据库中获取最新的全量字典数据。  
108 - * 如果未发生变化,则返回空  
109 - *  
110 - * @param maxUpdateTime 当前字典数据的最大更新时间  
111 - * @return 字典数据列表  
112 - */  
113 - private List<DictDataDO> loadDictDataIfUpdate(Date maxUpdateTime) {  
114 - // 第一步,判断是否要更新。  
115 - if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据  
116 - log.info("[loadDictDataIfUpdate][首次加载全量字典数据]");  
117 - } else { // 判断数据库中是否有更新的字典数据  
118 - if (dictDataMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {  
119 - return null;  
120 - }  
121 - log.info("[loadDictDataIfUpdate][增量加载全量字典数据]");  
122 - }  
123 - // 第二步,如果有更新,则从数据库加载所有字典数据  
124 - return dictDataMapper.selectList();  
125 - }  
126 -  
127 - @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)  
128 - public void schedulePeriodicRefresh() {  
129 - initLocalCache();  
130 - }  
131 -  
132 @Override 50 @Override
133 public List<DictDataDO> getDictDatas() { 51 public List<DictDataDO> getDictDatas() {
134 List<DictDataDO> list = dictDataMapper.selectList(); 52 List<DictDataDO> list = dictDataMapper.selectList();
@@ -154,16 +72,6 @@ public class DictDataServiceImpl implements DictDataService { @@ -154,16 +72,6 @@ public class DictDataServiceImpl implements DictDataService {
154 } 72 }
155 73
156 @Override 74 @Override
157 - public DictDataRespDTO getDictDataFromCache(String type, String value) {  
158 - return DictDataConvert.INSTANCE.convert02(valueDictDataCache.get(type, value));  
159 - }  
160 -  
161 - @Override  
162 - public DictDataRespDTO parseDictDataFromCache(String type, String label) {  
163 - return DictDataConvert.INSTANCE.convert02(labelDictDataCache.get(type, label));  
164 - }  
165 -  
166 - @Override  
167 public Long createDictData(DictDataCreateReqVO reqVO) { 75 public Long createDictData(DictDataCreateReqVO reqVO) {
168 // 校验正确性 76 // 校验正确性
169 checkCreateOrUpdate(null, reqVO.getValue(), reqVO.getDictType()); 77 checkCreateOrUpdate(null, reqVO.getValue(), reqVO.getDictType());
@@ -171,9 +79,6 @@ public class DictDataServiceImpl implements DictDataService { @@ -171,9 +79,6 @@ public class DictDataServiceImpl implements DictDataService {
171 // 插入字典类型 79 // 插入字典类型
172 DictDataDO dictData = DictDataConvert.INSTANCE.convert(reqVO); 80 DictDataDO dictData = DictDataConvert.INSTANCE.convert(reqVO);
173 dictDataMapper.insert(dictData); 81 dictDataMapper.insert(dictData);
174 -  
175 - // 发送刷新消息  
176 - dictDataProducer.sendDictDataRefreshMessage();  
177 return dictData.getId(); 82 return dictData.getId();
178 } 83 }
179 84
@@ -185,9 +90,6 @@ public class DictDataServiceImpl implements DictDataService { @@ -185,9 +90,6 @@ public class DictDataServiceImpl implements DictDataService {
185 // 更新字典类型 90 // 更新字典类型
186 DictDataDO updateObj = DictDataConvert.INSTANCE.convert(reqVO); 91 DictDataDO updateObj = DictDataConvert.INSTANCE.convert(reqVO);
187 dictDataMapper.updateById(updateObj); 92 dictDataMapper.updateById(updateObj);
188 -  
189 - // 发送刷新消息  
190 - dictDataProducer.sendDictDataRefreshMessage();  
191 } 93 }
192 94
193 @Override 95 @Override
@@ -197,9 +99,6 @@ public class DictDataServiceImpl implements DictDataService { @@ -197,9 +99,6 @@ public class DictDataServiceImpl implements DictDataService {
197 99
198 // 删除字典数据 100 // 删除字典数据
199 dictDataMapper.deleteById(id); 101 dictDataMapper.deleteById(id);
200 -  
201 - // 发送刷新消息  
202 - dictDataProducer.sendDictDataRefreshMessage();  
203 } 102 }
204 103
205 @Override 104 @Override
@@ -259,7 +158,8 @@ public class DictDataServiceImpl implements DictDataService { @@ -259,7 +158,8 @@ public class DictDataServiceImpl implements DictDataService {
259 if (CollUtil.isEmpty(values)) { 158 if (CollUtil.isEmpty(values)) {
260 return; 159 return;
261 } 160 }
262 - ImmutableMap<String, DictDataDO> dictDataMap = valueDictDataCache.row(dictType); 161 + Map<String, DictDataDO> dictDataMap = CollectionUtils.convertMap(
  162 + dictDataMapper.selectByDictTypeAndValues(dictType, values), DictDataDO::getValue);
263 // 校验 163 // 校验
264 values.forEach(value -> { 164 values.forEach(value -> {
265 DictDataDO dictData = dictDataMap.get(value); 165 DictDataDO dictData = dictDataMap.get(value);
@@ -272,4 +172,14 @@ public class DictDataServiceImpl implements DictDataService { @@ -272,4 +172,14 @@ public class DictDataServiceImpl implements DictDataService {
272 }); 172 });
273 } 173 }
274 174
  175 + @Override
  176 + public DictDataDO getDictData(String dictType, String value) {
  177 + return dictDataMapper.selectByDictTypeAndValue(dictType, value);
  178 + }
  179 +
  180 + @Override
  181 + public DictDataDO parseDictData(String dictType, String label) {
  182 + return dictDataMapper.selectByDictTypeAndLabel(dictType, label);
  183 + }
  184 +
275 } 185 }
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceTest.java
1 package cn.iocoder.yudao.module.system.service.dict; 1 package cn.iocoder.yudao.module.system.service.dict;
2 2
3 -import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;  
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
  6 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  7 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
6 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataCreateReqVO; 8 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataCreateReqVO;
7 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataExportReqVO; 9 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataExportReqVO;
8 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO; 10 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO;
9 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataUpdateReqVO; 11 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataUpdateReqVO;
  12 +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
10 import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO; 13 import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO;
11 import cn.iocoder.yudao.module.system.dal.mysql.dict.DictDataMapper; 14 import cn.iocoder.yudao.module.system.dal.mysql.dict.DictDataMapper;
12 -import cn.iocoder.yudao.module.system.mq.producer.dict.DictDataProducer;  
13 -import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;  
14 -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;  
15 -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;  
16 -import com.google.common.collect.ImmutableTable;  
17 import org.junit.jupiter.api.Test; 15 import org.junit.jupiter.api.Test;
18 import org.springframework.boot.test.mock.mockito.MockBean; 16 import org.springframework.boot.test.mock.mockito.MockBean;
19 import org.springframework.context.annotation.Import; 17 import org.springframework.context.annotation.Import;
20 18
21 import javax.annotation.Resource; 19 import javax.annotation.Resource;
22 -import java.util.Date;  
23 import java.util.List; 20 import java.util.List;
24 import java.util.function.Consumer; 21 import java.util.function.Consumer;
25 22
26 -import static cn.hutool.core.bean.BeanUtil.getFieldValue;  
27 -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;  
28 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; 23 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
29 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; 24 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
30 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; 25 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  26 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
31 import static org.junit.jupiter.api.Assertions.*; 27 import static org.junit.jupiter.api.Assertions.*;
32 import static org.mockito.ArgumentMatchers.eq; 28 import static org.mockito.ArgumentMatchers.eq;
33 -import static org.mockito.Mockito.*; 29 +import static org.mockito.Mockito.when;
34 30
35 @Import(DictDataServiceImpl.class) 31 @Import(DictDataServiceImpl.class)
36 public class DictDataServiceTest extends BaseDbUnitTest { 32 public class DictDataServiceTest extends BaseDbUnitTest {
@@ -42,39 +38,6 @@ public class DictDataServiceTest extends BaseDbUnitTest { @@ -42,39 +38,6 @@ public class DictDataServiceTest extends BaseDbUnitTest {
42 private DictDataMapper dictDataMapper; 38 private DictDataMapper dictDataMapper;
43 @MockBean 39 @MockBean
44 private DictTypeService dictTypeService; 40 private DictTypeService dictTypeService;
45 - @MockBean  
46 - private DictDataProducer dictDataProducer;  
47 -  
48 - /**  
49 - * 测试加载到新的字典数据的情况  
50 - */  
51 - @Test  
52 - @SuppressWarnings("unchecked")  
53 - public void testInitLocalCache() {  
54 - // mock 数据  
55 - DictDataDO dictData01 = randomDictDataDO();  
56 - dictDataMapper.insert(dictData01);  
57 - DictDataDO dictData02 = randomDictDataDO();  
58 - dictDataMapper.insert(dictData02);  
59 -  
60 - // 调用  
61 - dictDataService.initLocalCache();  
62 - // 断言 labelDictDataCache 缓存  
63 - ImmutableTable<String, String, DictDataDO> labelDictDataCache =  
64 - (ImmutableTable<String, String, DictDataDO>) getFieldValue(dictDataService, "labelDictDataCache");  
65 - assertEquals(2, labelDictDataCache.size());  
66 - assertPojoEquals(dictData01, labelDictDataCache.get(dictData01.getDictType(), dictData01.getLabel()));  
67 - assertPojoEquals(dictData02, labelDictDataCache.get(dictData02.getDictType(), dictData02.getLabel()));  
68 - // 断言 valueDictDataCache 缓存  
69 - ImmutableTable<String, String, DictDataDO> valueDictDataCache =  
70 - (ImmutableTable<String, String, DictDataDO>) getFieldValue(dictDataService, "valueDictDataCache");  
71 - assertEquals(2, valueDictDataCache.size());  
72 - assertPojoEquals(dictData01, valueDictDataCache.get(dictData01.getDictType(), dictData01.getValue()));  
73 - assertPojoEquals(dictData02, valueDictDataCache.get(dictData02.getDictType(), dictData02.getValue()));  
74 - // 断言 maxUpdateTime 缓存  
75 - Date maxUpdateTime = (Date) getFieldValue(dictDataService, "maxUpdateTime");  
76 - assertEquals(ObjectUtils.max(dictData01.getUpdateTime(), dictData02.getUpdateTime()), maxUpdateTime);  
77 - }  
78 41
79 @Test 42 @Test
80 public void testGetDictDataPage() { 43 public void testGetDictDataPage() {
@@ -148,8 +111,6 @@ public class DictDataServiceTest extends BaseDbUnitTest { @@ -148,8 +111,6 @@ public class DictDataServiceTest extends BaseDbUnitTest {
148 // 校验记录的属性是否正确 111 // 校验记录的属性是否正确
149 DictDataDO dictData = dictDataMapper.selectById(dictDataId); 112 DictDataDO dictData = dictDataMapper.selectById(dictDataId);
150 assertPojoEquals(reqVO, dictData); 113 assertPojoEquals(reqVO, dictData);
151 - // 校验调用  
152 - verify(dictDataProducer, times(1)).sendDictDataRefreshMessage();  
153 } 114 }
154 115
155 @Test 116 @Test
@@ -170,8 +131,6 @@ public class DictDataServiceTest extends BaseDbUnitTest { @@ -170,8 +131,6 @@ public class DictDataServiceTest extends BaseDbUnitTest {
170 // 校验是否更新正确 131 // 校验是否更新正确
171 DictDataDO dictData = dictDataMapper.selectById(reqVO.getId()); // 获取最新的 132 DictDataDO dictData = dictDataMapper.selectById(reqVO.getId()); // 获取最新的
172 assertPojoEquals(reqVO, dictData); 133 assertPojoEquals(reqVO, dictData);
173 - // 校验调用  
174 - verify(dictDataProducer, times(1)).sendDictDataRefreshMessage();  
175 } 134 }
176 135
177 @Test 136 @Test
@@ -186,8 +145,6 @@ public class DictDataServiceTest extends BaseDbUnitTest { @@ -186,8 +145,6 @@ public class DictDataServiceTest extends BaseDbUnitTest {
186 dictDataService.deleteDictData(id); 145 dictDataService.deleteDictData(id);
187 // 校验数据不存在了 146 // 校验数据不存在了
188 assertNull(dictDataMapper.selectById(id)); 147 assertNull(dictDataMapper.selectById(id));
189 - // 校验调用  
190 - verify(dictDataProducer, times(1)).sendDictDataRefreshMessage();  
191 } 148 }
192 149
193 @Test 150 @Test