Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
Y
yudao-cloud
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
hblj
yudao-cloud
Commits
6f8ca56e
提交
6f8ca56e
authored
12月 28, 2022
作者:
YunaiV
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
优化本地缓存的刷新实现,数据变更时,强制刷新
上级
81340a63
隐藏空白字符变更
内嵌
并排
正在显示
16 个修改的文件
包含
276 行增加
和
322 行删除
+276
-322
TenantIgnoreAspect.java
...r/yudao/framework/tenant/core/aop/TenantIgnoreAspect.java
+3
-0
TenantUtils.java
...iocoder/yudao/framework/tenant/core/util/TenantUtils.java
+16
-0
FileConfigServiceImpl.java
...udao/module/infra/service/file/FileConfigServiceImpl.java
+26
-39
FileConfigServiceImplTest.java
.../module/infra/service/file/FileConfigServiceImplTest.java
+1
-1
FileServiceTest.java
...oder/yudao/module/infra/service/file/FileServiceTest.java
+1
-1
SmsChannelRefreshConsumer.java
...ule/system/mq/consumer/sms/SmsChannelRefreshConsumer.java
+1
-1
DeptServiceImpl.java
...der/yudao/module/system/service/dept/DeptServiceImpl.java
+37
-41
OAuth2ClientServiceImpl.java
...module/system/service/oauth2/OAuth2ClientServiceImpl.java
+21
-27
MenuServiceImpl.java
...dao/module/system/service/permission/MenuServiceImpl.java
+26
-31
PermissionServiceImpl.java
...dule/system/service/permission/PermissionServiceImpl.java
+60
-82
RoleServiceImpl.java
...dao/module/system/service/permission/RoleServiceImpl.java
+25
-27
SensitiveWordServiceImpl.java
...ystem/service/sensitiveword/SensitiveWordServiceImpl.java
+29
-35
SmsChannelService.java
...er/yudao/module/system/service/sms/SmsChannelService.java
+1
-1
SmsChannelServiceImpl.java
...udao/module/system/service/sms/SmsChannelServiceImpl.java
+24
-31
PermissionServiceTest.java
...dule/system/service/permission/PermissionServiceTest.java
+4
-4
SmsChannelServiceTest.java
...udao/module/system/service/sms/SmsChannelServiceTest.java
+1
-1
没有找到文件。
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/TenantIgnoreAspect.java
浏览文件 @
6f8ca56e
package
cn
.
iocoder
.
yudao
.
framework
.
tenant
.
core
.
aop
;
import
cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder
;
import
cn.iocoder.yudao.framework.tenant.core.util.TenantUtils
;
import
lombok.extern.slf4j.Slf4j
;
import
org.aspectj.lang.ProceedingJoinPoint
;
import
org.aspectj.lang.annotation.Around
;
...
...
@@ -11,6 +12,8 @@ import org.aspectj.lang.annotation.Aspect;
* 例如说,一个定时任务,读取所有数据,进行处理。
* 又例如说,读取所有数据,进行缓存。
*
* 整体逻辑的实现,和 {@link TenantUtils#executeIgnore(Runnable)} 需要保持一致
*
* @author 芋道源码
*/
@Aspect
...
...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java
浏览文件 @
6f8ca56e
...
...
@@ -34,6 +34,22 @@ public class TenantUtils {
}
}
/**
* 忽略租户,执行对应的逻辑
*
* @param runnable 逻辑
*/
public
static
void
executeIgnore
(
Runnable
runnable
)
{
Boolean
oldIgnore
=
TenantContextHolder
.
isIgnore
();
try
{
TenantContextHolder
.
setIgnore
(
true
);
// 执行逻辑
runnable
.
run
();
}
finally
{
TenantContextHolder
.
setIgnore
(
oldIgnore
);
}
}
/**
* 使用指定租户,执行对应的逻辑
*
...
...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java
浏览文件 @
6f8ca56e
package
cn
.
iocoder
.
yudao
.
module
.
infra
.
service
.
file
;
import
cn.hutool.core.collection.CollUtil
;
import
cn.hutool.core.io.resource.ResourceUtil
;
import
cn.hutool.core.util.IdUtil
;
import
cn.iocoder.yudao.framework.common.pojo.PageResult
;
...
...
@@ -20,7 +19,6 @@ import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper;
import
cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer
;
import
lombok.Getter
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.context.annotation.Lazy
;
import
org.springframework.scheduling.annotation.Scheduled
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
...
...
@@ -79,20 +77,36 @@ public class FileConfigServiceImpl implements FileConfigService {
@Resource
private
Validator
validator
;
@Resource
@Lazy
// 注入自己,所以延迟加载
private
FileConfigService
self
;
@Override
@PostConstruct
public
void
initFileClients
()
{
// 获取文件配置,如果有更新
List
<
FileConfigDO
>
configs
=
loadFileConfigIfUpdate
(
maxUpdateTime
);
if
(
CollUtil
.
isEmpty
(
configs
))
{
initLocalCacheIfUpdate
(
null
);
}
@Scheduled
(
fixedDelay
=
SCHEDULER_PERIOD
,
initialDelay
=
SCHEDULER_PERIOD
)
public
void
schedulePeriodicRefresh
()
{
initLocalCacheIfUpdate
(
this
.
maxUpdateTime
);
}
/**
* 刷新本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
* 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
*/
private
void
initLocalCacheIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 第一步:基于 maxUpdateTime 判断缓存是否刷新。
// 如果没有增量的数据变化,则不进行本地缓存的刷新
if
(
maxUpdateTime
!=
null
&&
fileConfigMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
log
.
info
(
"[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]"
,
maxUpdateTime
);
return
;
}
List
<
FileConfigDO
>
configs
=
fileConfigMapper
.
selectList
();
log
.
info
(
"[initLocalCacheIfUpdate][缓存文件配置,数量为:{}]"
,
configs
.
size
());
//
创建或更新支付
Client
//
第二步:构建缓存。创建或更新文件
Client
configs
.
forEach
(
config
->
{
fileClientFactory
.
createOrUpdateFileClient
(
config
.
getId
(),
config
.
getStorage
(),
config
.
getConfig
());
// 如果是 master,进行设置
...
...
@@ -101,35 +115,8 @@ public class FileConfigServiceImpl implements FileConfigService {
}
});
// 写入缓存
maxUpdateTime
=
CollectionUtils
.
getMaxValue
(
configs
,
FileConfigDO:
:
getUpdateTime
);
log
.
info
(
"[initFileClients][初始化 FileConfig 数量为 {}]"
,
configs
.
size
());
}
@Scheduled
(
fixedDelay
=
SCHEDULER_PERIOD
,
initialDelay
=
SCHEDULER_PERIOD
)
public
void
schedulePeriodicRefresh
()
{
self
.
initFileClients
();
}
/**
* 如果文件配置发生变化,从数据库中获取最新的全量文件配置。
* 如果未发生变化,则返回空
*
* @param maxUpdateTime 当前文件配置的最大更新时间
* @return 文件配置列表
*/
private
List
<
FileConfigDO
>
loadFileConfigIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 第一步,判断是否要更新。
if
(
maxUpdateTime
==
null
)
{
// 如果更新时间为空,说明 DB 一定有新数据
log
.
info
(
"[loadFileConfigIfUpdate][首次加载全量文件配置]"
);
}
else
{
// 判断数据库中是否有更新的文件配置
if
(
fileConfigMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
return
null
;
}
log
.
info
(
"[loadFileConfigIfUpdate][增量加载全量文件配置]"
);
}
// 第二步,如果有更新,则从数据库加载所有文件配置
return
fileConfigMapper
.
selectList
();
// 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
this
.
maxUpdateTime
=
CollectionUtils
.
getMaxValue
(
configs
,
FileConfigDO:
:
getUpdateTime
);
}
@Override
...
...
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java
浏览文件 @
6f8ca56e
...
...
@@ -240,7 +240,7 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
// mock 获得 Client
FileClient
fileClient
=
mock
(
FileClient
.
class
);
when
(
fileClientFactory
.
getFileClient
(
eq
(
id
))).
thenReturn
(
fileClient
);
when
(
fileClient
.
upload
(
any
(),
any
())).
thenReturn
(
"https://www.iocoder.cn"
);
when
(
fileClient
.
upload
(
any
(),
any
()
,
any
()
)).
thenReturn
(
"https://www.iocoder.cn"
);
// 调用,并断言
assertEquals
(
"https://www.iocoder.cn"
,
fileConfigService
.
testFileConfig
(
id
));
...
...
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceTest.java
浏览文件 @
6f8ca56e
...
...
@@ -78,7 +78,7 @@ public class FileServiceTest extends BaseDbUnitTest {
FileClient
client
=
mock
(
FileClient
.
class
);
when
(
fileConfigService
.
getMasterFileClient
()).
thenReturn
(
client
);
String
url
=
randomString
();
when
(
client
.
upload
(
same
(
content
),
same
(
path
))).
thenReturn
(
url
);
when
(
client
.
upload
(
same
(
content
),
same
(
path
)
,
same
(
"image/jpeg"
)
)).
thenReturn
(
url
);
when
(
client
.
getId
()).
thenReturn
(
10L
);
String
name
=
"单测文件名"
;
// 调用
...
...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsChannelRefreshConsumer.java
浏览文件 @
6f8ca56e
...
...
@@ -23,7 +23,7 @@ public class SmsChannelRefreshConsumer {
@EventListener
public
void
execute
(
SmsChannelRefreshMessage
message
)
{
log
.
info
(
"[execute][收到 SmsChannel 刷新消息]"
);
smsChannelService
.
init
SmsClients
();
smsChannelService
.
init
LocalCache
();
}
}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java
浏览文件 @
6f8ca56e
...
...
@@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import
cn.iocoder.yudao.framework.common.enums.CommonStatusEnum
;
import
cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil
;
import
cn.iocoder.yudao.framework.common.util.collection.CollectionUtils
;
import
cn.iocoder.yudao.framework.tenant.core.
aop.TenantIgnore
;
import
cn.iocoder.yudao.framework.tenant.core.
util.TenantUtils
;
import
cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptCreateReqVO
;
import
cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO
;
import
cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO
;
...
...
@@ -17,7 +17,6 @@ import com.google.common.collect.ImmutableMap;
import
com.google.common.collect.ImmutableMultimap
;
import
com.google.common.collect.Multimap
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.context.annotation.Lazy
;
import
org.springframework.scheduling.annotation.Scheduled
;
import
org.springframework.stereotype.Service
;
import
org.springframework.validation.annotation.Validated
;
...
...
@@ -73,58 +72,55 @@ public class DeptServiceImpl implements DeptService {
@Resource
private
DeptProducer
deptProducer
;
@Resource
@Lazy
// 注入自己,所以延迟加载
private
DeptService
self
;
/**
* 初始化 {@link #parentDeptCache} 和 {@link #deptCache} 缓存
*/
@Override
@PostConstruct
@TenantIgnore
// 初始化缓存,无需租户过滤
public
synchronized
void
initLocalCache
()
{
// 获取部门列表,如果有更新
List
<
DeptDO
>
deptList
=
loadDeptIfUpdate
(
maxUpdateTime
);
if
(
CollUtil
.
isEmpty
(
deptList
))
{
return
;
}
// 构建缓存
ImmutableMap
.
Builder
<
Long
,
DeptDO
>
builder
=
ImmutableMap
.
builder
();
ImmutableMultimap
.
Builder
<
Long
,
DeptDO
>
parentBuilder
=
ImmutableMultimap
.
builder
();
deptList
.
forEach
(
sysRoleDO
->
{
builder
.
put
(
sysRoleDO
.
getId
(),
sysRoleDO
);
parentBuilder
.
put
(
sysRoleDO
.
getParentId
(),
sysRoleDO
);
});
// 设置缓存
deptCache
=
builder
.
build
();
parentDeptCache
=
parentBuilder
.
build
();
maxUpdateTime
=
CollectionUtils
.
getMaxValue
(
deptList
,
DeptDO:
:
getUpdateTime
);
log
.
info
(
"[initLocalCache][初始化 Dept 数量为 {}]"
,
deptList
.
size
());
initLocalCacheIfUpdate
(
null
);
}
@Scheduled
(
fixedDelay
=
SCHEDULER_PERIOD
,
initialDelay
=
SCHEDULER_PERIOD
)
public
void
schedulePeriodicRefresh
()
{
self
.
initLocalCache
(
);
initLocalCacheIfUpdate
(
this
.
maxUpdateTime
);
}
/**
* 如果部门发生变化,从数据库中获取最新的全量部门。
* 如果未发生变化,则返回空
* 刷新本地缓存
*
* @param maxUpdateTime 当前部门的最大更新时间
* @return 部门列表
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
* 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
*/
protected
List
<
DeptDO
>
loadDeptIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 第一步,判断是否要更新。
if
(
maxUpdateTime
==
null
)
{
// 如果更新时间为空,说明 DB 一定有新数据
log
.
info
(
"[loadMenuIfUpdate][首次加载全量部门]"
);
}
else
{
// 判断数据库中是否有更新的部门
if
(
deptMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
return
null
;
private
void
initLocalCacheIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 注意:忽略自动多租户,因为要全局初始化缓存
TenantUtils
.
executeIgnore
(()
->
{
// 第一步:基于 maxUpdateTime 判断缓存是否刷新。
// 如果没有增量的数据变化,则不进行本地缓存的刷新
if
(
maxUpdateTime
!=
null
&&
deptMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
log
.
info
(
"[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]"
,
maxUpdateTime
);
return
;
}
log
.
info
(
"[loadMenuIfUpdate][增量加载全量部门]"
);
}
// 第二步,如果有更新,则从数据库加载所有部门
return
deptMapper
.
selectList
();
List
<
DeptDO
>
depts
=
deptMapper
.
selectList
();
log
.
info
(
"[initLocalCacheIfUpdate][缓存部门,数量为:{}]"
,
depts
.
size
());
// 第二步:构建缓存。创建或更新支付 Client
// 构建缓存
ImmutableMap
.
Builder
<
Long
,
DeptDO
>
builder
=
ImmutableMap
.
builder
();
ImmutableMultimap
.
Builder
<
Long
,
DeptDO
>
parentBuilder
=
ImmutableMultimap
.
builder
();
depts
.
forEach
(
sysRoleDO
->
{
builder
.
put
(
sysRoleDO
.
getId
(),
sysRoleDO
);
parentBuilder
.
put
(
sysRoleDO
.
getParentId
(),
sysRoleDO
);
});
// 设置缓存
deptCache
=
builder
.
build
();
parentDeptCache
=
parentBuilder
.
build
();
// 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
this
.
maxUpdateTime
=
CollectionUtils
.
getMaxValue
(
depts
,
DeptDO:
:
getUpdateTime
);
});
}
@Override
...
...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java
浏览文件 @
6f8ca56e
...
...
@@ -25,7 +25,6 @@ import javax.annotation.PostConstruct;
import
javax.annotation.Resource
;
import
java.time.LocalDateTime
;
import
java.util.Collection
;
import
java.time.LocalDateTime
;
import
java.util.List
;
import
java.util.Map
;
...
...
@@ -77,42 +76,37 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService {
@Override
@PostConstruct
public
void
initLocalCache
()
{
// 获取客户端列表,如果有更新
List
<
OAuth2ClientDO
>
tenantList
=
loadOAuth2ClientIfUpdate
(
maxUpdateTime
);
if
(
CollUtil
.
isEmpty
(
tenantList
))
{
return
;
}
// 写入缓存
clientCache
=
convertMap
(
tenantList
,
OAuth2ClientDO:
:
getClientId
);
maxUpdateTime
=
getMaxValue
(
tenantList
,
OAuth2ClientDO:
:
getUpdateTime
);
log
.
info
(
"[initLocalCache][初始化 OAuth2Client 数量为 {}]"
,
tenantList
.
size
());
initLocalCacheIfUpdate
(
null
);
}
@Scheduled
(
fixedDelay
=
SCHEDULER_PERIOD
,
initialDelay
=
SCHEDULER_PERIOD
)
public
void
schedulePeriodicRefresh
()
{
initLocalCache
(
);
initLocalCache
IfUpdate
(
this
.
maxUpdateTime
);
}
/**
* 如果客户端发生变化,从数据库中获取最新的全量客户端。
* 如果未发生变化,则返回空
* 刷新本地缓存
*
* @param maxUpdateTime 当前客户端的最大更新时间
* @return 客户端列表
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
* 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
*/
private
List
<
OAuth2ClientDO
>
loadOAuth2ClientIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 第一步,判断是否要更新。
if
(
maxUpdateTime
==
null
)
{
// 如果更新时间为空,说明 DB 一定有新数据
log
.
info
(
"[loadOAuth2ClientIfUpdate][首次加载全量客户端]"
);
}
else
{
// 判断数据库中是否有更新的客户端
if
(
oauth2ClientMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
return
null
;
}
log
.
info
(
"[loadOAuth2ClientIfUpdate][增量加载全量客户端]"
);
private
void
initLocalCacheIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 第一步:基于 maxUpdateTime 判断缓存是否刷新。
// 如果没有增量的数据变化,则不进行本地缓存的刷新
if
(
maxUpdateTime
!=
null
&&
oauth2ClientMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
log
.
info
(
"[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]"
,
maxUpdateTime
);
return
;
}
// 第二步,如果有更新,则从数据库加载所有客户端
return
oauth2ClientMapper
.
selectList
();
List
<
OAuth2ClientDO
>
clients
=
oauth2ClientMapper
.
selectList
();
log
.
info
(
"[initLocalCacheIfUpdate][缓存 OAuth2 客户端,数量为:{}]"
,
clients
.
size
());
// 第二步:构建缓存。
clientCache
=
convertMap
(
clients
,
OAuth2ClientDO:
:
getClientId
);
// 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
this
.
maxUpdateTime
=
getMaxValue
(
clients
,
OAuth2ClientDO:
:
getUpdateTime
);
}
@Override
...
...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java
浏览文件 @
6f8ca56e
...
...
@@ -86,13 +86,33 @@ public class MenuServiceImpl implements MenuService {
@Override
@PostConstruct
public
synchronized
void
initLocalCache
()
{
// 获取菜单列表,如果有更新
List
<
MenuDO
>
menuList
=
this
.
loadMenuIfUpdate
(
maxUpdateTime
);
if
(
CollUtil
.
isEmpty
(
menuList
))
{
initLocalCacheIfUpdate
(
null
);
}
@Scheduled
(
fixedDelay
=
SCHEDULER_PERIOD
,
initialDelay
=
SCHEDULER_PERIOD
)
public
void
schedulePeriodicRefresh
()
{
initLocalCacheIfUpdate
(
this
.
maxUpdateTime
);
}
/**
* 刷新本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
* 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
*/
private
void
initLocalCacheIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 第一步:基于 maxUpdateTime 判断缓存是否刷新。
// 如果没有增量的数据变化,则不进行本地缓存的刷新
if
(
maxUpdateTime
!=
null
&&
menuMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
log
.
info
(
"[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]"
,
maxUpdateTime
);
return
;
}
List
<
MenuDO
>
menuList
=
menuMapper
.
selectList
();
log
.
info
(
"[initLocalCacheIfUpdate][缓存菜单,数量为:{}]"
,
menuList
.
size
());
//
构建缓存
//
第二步:构建缓存。
ImmutableMap
.
Builder
<
Long
,
MenuDO
>
menuCacheBuilder
=
ImmutableMap
.
builder
();
ImmutableMultimap
.
Builder
<
String
,
MenuDO
>
permMenuCacheBuilder
=
ImmutableMultimap
.
builder
();
menuList
.
forEach
(
menuDO
->
{
...
...
@@ -103,34 +123,9 @@ public class MenuServiceImpl implements MenuService {
});
menuCache
=
menuCacheBuilder
.
build
();
permissionMenuCache
=
permMenuCacheBuilder
.
build
();
maxUpdateTime
=
CollectionUtils
.
getMaxValue
(
menuList
,
MenuDO:
:
getUpdateTime
);
log
.
info
(
"[initLocalCache][缓存菜单,数量为:{}]"
,
menuList
.
size
());
}
@Scheduled
(
fixedDelay
=
SCHEDULER_PERIOD
,
initialDelay
=
SCHEDULER_PERIOD
)
public
void
schedulePeriodicRefresh
()
{
initLocalCache
();
}
/**
* 如果菜单发生变化,从数据库中获取最新的全量菜单。
* 如果未发生变化,则返回空
*
* @param maxUpdateTime 当前菜单的最大更新时间
* @return 菜单列表
*/
private
List
<
MenuDO
>
loadMenuIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 第一步,判断是否要更新。
if
(
maxUpdateTime
==
null
)
{
// 如果更新时间为空,说明 DB 一定有新数据
log
.
info
(
"[loadMenuIfUpdate][首次加载全量菜单]"
);
}
else
{
// 判断数据库中是否有更新的菜单
if
(
menuMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
return
null
;
}
log
.
info
(
"[loadMenuIfUpdate][增量加载全量菜单]"
);
}
// 第二步,如果有更新,则从数据库加载所有菜单
return
menuMapper
.
selectList
();
// 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
this
.
maxUpdateTime
=
CollectionUtils
.
getMaxValue
(
menuList
,
MenuDO:
:
getUpdateTime
);
}
@Override
...
...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java
浏览文件 @
6f8ca56e
...
...
@@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import
cn.iocoder.yudao.framework.common.util.json.JsonUtils
;
import
cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission
;
import
cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore
;
import
cn.iocoder.yudao.framework.tenant.core.util.TenantUtils
;
import
cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO
;
import
cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO
;
import
cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO
;
...
...
@@ -31,7 +32,6 @@ import com.google.common.collect.Sets;
import
lombok.Getter
;
import
lombok.Setter
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.context.annotation.Lazy
;
import
org.springframework.scheduling.annotation.Scheduled
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
...
...
@@ -126,106 +126,84 @@ public class PermissionServiceImpl implements PermissionService {
@Resource
private
PermissionProducer
permissionProducer
;
@Resource
@Lazy
// 注入自己,所以延迟加载
private
PermissionService
self
;
@Override
@PostConstruct
@TenantIgnore
// 初始化缓存,无需租户过滤
public
void
initLocalCache
()
{
initUserRoleLocalCache
();
initRoleMenuLocalCache
();
}
/**
* 初始化 {@link #roleMenuCache} 和 {@link #menuRoleCache} 缓存
*/
@VisibleForTesting
void
initRoleMenuLocalCache
()
{
// 获取角色与菜单的关联列表,如果有更新
List
<
RoleMenuDO
>
roleMenuList
=
loadRoleMenuIfUpdate
(
roleMenuMaxUpdateTime
);
if
(
CollUtil
.
isEmpty
(
roleMenuList
))
{
return
;
}
// 初始化 roleMenuCache 和 menuRoleCache 缓存
ImmutableMultimap
.
Builder
<
Long
,
Long
>
roleMenuCacheBuilder
=
ImmutableMultimap
.
builder
();
ImmutableMultimap
.
Builder
<
Long
,
Long
>
menuRoleCacheBuilder
=
ImmutableMultimap
.
builder
();
roleMenuList
.
forEach
(
roleMenuDO
->
{
roleMenuCacheBuilder
.
put
(
roleMenuDO
.
getRoleId
(),
roleMenuDO
.
getMenuId
());
menuRoleCacheBuilder
.
put
(
roleMenuDO
.
getMenuId
(),
roleMenuDO
.
getRoleId
());
});
roleMenuCache
=
roleMenuCacheBuilder
.
build
();
menuRoleCache
=
menuRoleCacheBuilder
.
build
();
roleMenuMaxUpdateTime
=
getMaxValue
(
roleMenuList
,
RoleMenuDO:
:
getUpdateTime
);
log
.
info
(
"[initRoleMenuLocalCache][初始化角色与菜单的关联数量为 {}]"
,
roleMenuList
.
size
());
}
/**
* 初始化 {@link #userRoleCache} 缓存
*/
@VisibleForTesting
void
initUserRoleLocalCache
()
{
// 获取用户与角色的关联列表,如果有更新
List
<
UserRoleDO
>
userRoleList
=
loadUserRoleIfUpdate
(
userRoleMaxUpdateTime
);
if
(
CollUtil
.
isEmpty
(
userRoleList
))
{
return
;
}
// 初始化 userRoleCache 缓存
ImmutableMultimap
.
Builder
<
Long
,
Long
>
userRoleCacheBuilder
=
ImmutableMultimap
.
builder
();
userRoleList
.
forEach
(
userRoleDO
->
userRoleCacheBuilder
.
put
(
userRoleDO
.
getUserId
(),
userRoleDO
.
getRoleId
()));
userRoleCache
=
CollectionUtils
.
convertMultiMap2
(
userRoleList
,
UserRoleDO:
:
getUserId
,
UserRoleDO:
:
getRoleId
);
userRoleMaxUpdateTime
=
getMaxValue
(
userRoleList
,
UserRoleDO:
:
getUpdateTime
);
log
.
info
(
"[initUserRoleLocalCache][初始化用户与角色的关联数量为 {}]"
,
userRoleList
.
size
());
initLocalCacheIfUpdateForRoleMenu
(
null
);
initLocalCacheIfUpdateForUserRole
(
null
);
}
@Scheduled
(
fixedDelay
=
SCHEDULER_PERIOD
,
initialDelay
=
SCHEDULER_PERIOD
)
public
void
schedulePeriodicRefresh
()
{
self
.
initLocalCache
();
initLocalCacheIfUpdateForRoleMenu
(
this
.
roleMenuMaxUpdateTime
);
initLocalCacheIfUpdateForUserRole
(
this
.
userRoleMaxUpdateTime
);
}
/**
* 如果角色与菜单的关联发生变化,从数据库中获取最新的全量角色与菜单的关联。
* 如果未发生变化,则返回空
* 刷新 RoleMenu 本地缓存
*
* @param maxUpdateTime 当前角色与菜单的关联的最大更新时间
* @return 角色与菜单的关联列表
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
* 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
*/
protected
List
<
RoleMenuDO
>
loadRoleMenuIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 第一步,判断是否要更新。
if
(
maxUpdateTime
==
null
)
{
// 如果更新时间为空,说明 DB 一定有新数据
log
.
info
(
"[loadRoleMenuIfUpdate][首次加载全量角色与菜单的关联]"
);
}
else
{
// 判断数据库中是否有更新的角色与菜单的关联
if
(
roleMenuMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
return
null
;
@VisibleForTesting
void
initLocalCacheIfUpdateForRoleMenu
(
LocalDateTime
maxUpdateTime
)
{
// 注意:忽略自动多租户,因为要全局初始化缓存
TenantUtils
.
executeIgnore
(()
->
{
// 第一步:基于 maxUpdateTime 判断缓存是否刷新。
// 如果没有增量的数据变化,则不进行本地缓存的刷新
if
(
maxUpdateTime
!=
null
&&
roleMenuMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
log
.
info
(
"[initLocalCacheIfUpdateForRoleMenu][数据未发生变化({}),本地缓存不刷新]"
,
maxUpdateTime
);
return
;
}
log
.
info
(
"[loadRoleMenuIfUpdate][增量加载全量角色与菜单的关联]"
);
}
// 第二步,如果有更新,则从数据库加载所有角色与菜单的关联
return
roleMenuMapper
.
selectList
();
List
<
RoleMenuDO
>
roleMenus
=
roleMenuMapper
.
selectList
();
log
.
info
(
"[initLocalCacheIfUpdateForRoleMenu][缓存角色与菜单,数量为:{}]"
,
roleMenus
.
size
());
// 第二步:构建缓存。
ImmutableMultimap
.
Builder
<
Long
,
Long
>
roleMenuCacheBuilder
=
ImmutableMultimap
.
builder
();
ImmutableMultimap
.
Builder
<
Long
,
Long
>
menuRoleCacheBuilder
=
ImmutableMultimap
.
builder
();
roleMenus
.
forEach
(
roleMenuDO
->
{
roleMenuCacheBuilder
.
put
(
roleMenuDO
.
getRoleId
(),
roleMenuDO
.
getMenuId
());
menuRoleCacheBuilder
.
put
(
roleMenuDO
.
getMenuId
(),
roleMenuDO
.
getRoleId
());
});
roleMenuCache
=
roleMenuCacheBuilder
.
build
();
menuRoleCache
=
menuRoleCacheBuilder
.
build
();
// 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
this
.
roleMenuMaxUpdateTime
=
getMaxValue
(
roleMenus
,
RoleMenuDO:
:
getUpdateTime
);
});
}
/**
* 如果用户与角色的关联发生变化,从数据库中获取最新的全量用户与角色的关联。
* 如果未发生变化,则返回空
* 刷新 UserRole 本地缓存
*
* @param maxUpdateTime 当前角色与菜单的关联的最大更新时间
* @return 角色与菜单的关联列表
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
* 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
*/
protected
List
<
UserRoleDO
>
loadUserRoleIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 第一步,判断是否要更新。
if
(
maxUpdateTime
==
null
)
{
// 如果更新时间为空,说明 DB 一定有新数据
log
.
info
(
"[loadUserRoleIfUpdate][首次加载全量用户与角色的关联]"
);
}
else
{
// 判断数据库中是否有更新的用户与角色的关联
if
(
userRoleMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
return
null
;
@VisibleForTesting
void
initLocalCacheIfUpdateForUserRole
(
LocalDateTime
maxUpdateTime
)
{
// 注意:忽略自动多租户,因为要全局初始化缓存
TenantUtils
.
executeIgnore
(()
->
{
// 第一步:基于 maxUpdateTime 判断缓存是否刷新。
// 如果没有增量的数据变化,则不进行本地缓存的刷新
if
(
maxUpdateTime
!=
null
&&
userRoleMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
log
.
info
(
"[initLocalCacheIfUpdateForUserRole][数据未发生变化({}),本地缓存不刷新]"
,
maxUpdateTime
);
return
;
}
log
.
info
(
"[loadUserRoleIfUpdate][增量加载全量用户与角色的关联]"
);
}
// 第二步,如果有更新,则从数据库加载所有用户与角色的关联
return
userRoleMapper
.
selectList
();
List
<
UserRoleDO
>
userRoles
=
userRoleMapper
.
selectList
();
log
.
info
(
"[initLocalCacheIfUpdateForUserRole][缓存用户与角色,数量为:{}]"
,
userRoles
.
size
());
// 第二步:构建缓存。
ImmutableMultimap
.
Builder
<
Long
,
Long
>
userRoleCacheBuilder
=
ImmutableMultimap
.
builder
();
userRoles
.
forEach
(
userRoleDO
->
userRoleCacheBuilder
.
put
(
userRoleDO
.
getUserId
(),
userRoleDO
.
getRoleId
()));
userRoleCache
=
CollectionUtils
.
convertMultiMap2
(
userRoles
,
UserRoleDO:
:
getUserId
,
UserRoleDO:
:
getRoleId
);
// 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
this
.
userRoleMaxUpdateTime
=
getMaxValue
(
userRoles
,
UserRoleDO:
:
getUpdateTime
);
});
}
@Override
...
...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java
浏览文件 @
6f8ca56e
...
...
@@ -7,6 +7,7 @@ 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.tenant.core.aop.TenantIgnore
;
import
cn.iocoder.yudao.framework.tenant.core.util.TenantUtils
;
import
cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO
;
import
cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO
;
import
cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO
;
...
...
@@ -86,44 +87,41 @@ public class RoleServiceImpl implements RoleService {
*/
@Override
@PostConstruct
@TenantIgnore
// 忽略自动多租户,全局初始化缓存
public
void
initLocalCache
()
{
// 获取角色列表,如果有更新
List
<
RoleDO
>
roleList
=
loadRoleIfUpdate
(
maxUpdateTime
);
if
(
CollUtil
.
isEmpty
(
roleList
))
{
return
;
}
// 写入缓存
roleCache
=
CollectionUtils
.
convertMap
(
roleList
,
RoleDO:
:
getId
);
maxUpdateTime
=
CollectionUtils
.
getMaxValue
(
roleList
,
RoleDO:
:
getUpdateTime
);
log
.
info
(
"[initLocalCache][初始化 Role 数量为 {}]"
,
roleList
.
size
());
initLocalCacheIfUpdate
(
null
);
}
@Scheduled
(
fixedDelay
=
SCHEDULER_PERIOD
,
initialDelay
=
SCHEDULER_PERIOD
)
public
void
schedulePeriodicRefresh
()
{
self
.
initLocalCache
(
);
initLocalCacheIfUpdate
(
this
.
maxUpdateTime
);
}
/**
* 如果角色发生变化,从数据库中获取最新的全量角色。
* 如果未发生变化,则返回空
* 刷新本地缓存
*
* @param maxUpdateTime 当前角色的最大更新时间
* @return 角色列表
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
* 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
*/
private
List
<
RoleDO
>
loadRoleIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 第一步,判断是否要更新。
if
(
maxUpdateTime
==
null
)
{
// 如果更新时间为空,说明 DB 一定有新数据
log
.
info
(
"[loadRoleIfUpdate][首次加载全量角色]"
);
}
else
{
// 判断数据库中是否有更新的角色
if
(
roleMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
return
null
;
private
void
initLocalCacheIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 注意:忽略自动多租户,因为要全局初始化缓存
TenantUtils
.
executeIgnore
(()
->
{
// 第一步:基于 maxUpdateTime 判断缓存是否刷新。
// 如果没有增量的数据变化,则不进行本地缓存的刷新
if
(
maxUpdateTime
!=
null
&&
roleMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
log
.
info
(
"[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]"
,
maxUpdateTime
);
return
;
}
log
.
info
(
"[loadRoleIfUpdate][增量加载全量角色]"
);
}
// 第二步,如果有更新,则从数据库加载所有角色
return
roleMapper
.
selectList
();
List
<
RoleDO
>
roleList
=
roleMapper
.
selectList
();
log
.
info
(
"[initLocalCacheIfUpdate][缓存角色,数量为:{}]"
,
roleList
.
size
());
// 第二步:构建缓存。
roleCache
=
CollectionUtils
.
convertMap
(
roleList
,
RoleDO:
:
getId
);
// 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
this
.
maxUpdateTime
=
CollectionUtils
.
getMaxValue
(
roleList
,
RoleDO:
:
getUpdateTime
);
});
}
@Override
...
...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImpl.java
浏览文件 @
6f8ca56e
...
...
@@ -84,21 +84,42 @@ public class SensitiveWordServiceImpl implements SensitiveWordService {
@Override
@PostConstruct
public
void
initLocalCache
()
{
// 获取敏感词列表,如果有更新
List
<
SensitiveWordDO
>
sensitiveWordList
=
loadSensitiveWordIfUpdate
(
maxUpdateTime
);
if
(
CollUtil
.
isEmpty
(
sensitiveWordList
))
{
initLocalCacheIfUpdate
(
null
);
}
@Scheduled
(
fixedDelay
=
SCHEDULER_PERIOD
,
initialDelay
=
SCHEDULER_PERIOD
)
public
void
schedulePeriodicRefresh
()
{
initLocalCacheIfUpdate
(
this
.
maxUpdateTime
);
}
/**
* 刷新本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
* 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
*/
private
void
initLocalCacheIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 第一步:基于 maxUpdateTime 判断缓存是否刷新。
// 如果没有增量的数据变化,则不进行本地缓存的刷新
if
(
maxUpdateTime
!=
null
&&
sensitiveWordMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
log
.
info
(
"[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]"
,
maxUpdateTime
);
return
;
}
List
<
SensitiveWordDO
>
sensitiveWords
=
sensitiveWordMapper
.
selectList
();
log
.
info
(
"[initLocalCacheIfUpdate][缓存敏感词,数量为:{}]"
,
sensitiveWords
.
size
());
// 第二步:构建缓存。
// 写入 sensitiveWordTagsCache 缓存
Set
<
String
>
tags
=
new
HashSet
<>();
sensitiveWord
List
.
forEach
(
word
->
tags
.
addAll
(
word
.
getTags
()));
sensitiveWord
s
.
forEach
(
word
->
tags
.
addAll
(
word
.
getTags
()));
sensitiveWordTagsCache
=
tags
;
// 写入 defaultSensitiveWordTrie、tagSensitiveWordTries 缓存
initSensitiveWordTrie
(
sensitiveWord
List
);
// 写入 maxUpdateTime 最大更新时间
maxUpdateTime
=
CollectionUtils
.
getMaxValue
(
sensitiveWordList
,
SensitiveWordDO:
:
getUpdateTime
);
log
.
info
(
"[initLocalCache][初始化 敏感词 数量为 {}]"
,
sensitiveWordList
.
size
()
);
initSensitiveWordTrie
(
sensitiveWord
s
);
// 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
this
.
maxUpdateTime
=
CollectionUtils
.
getMaxValue
(
sensitiveWords
,
SensitiveWordDO:
:
getUpdateTime
);
}
private
void
initSensitiveWordTrie
(
List
<
SensitiveWordDO
>
wordDOs
)
{
...
...
@@ -122,33 +143,6 @@ public class SensitiveWordServiceImpl implements SensitiveWordService {
this
.
tagSensitiveWordTries
=
tagSensitiveWordTries
;
}
@Scheduled
(
fixedDelay
=
SCHEDULER_PERIOD
,
initialDelay
=
SCHEDULER_PERIOD
)
public
void
schedulePeriodicRefresh
()
{
initLocalCache
();
}
/**
* 如果敏感词发生变化,从数据库中获取最新的全量敏感词。
* 如果未发生变化,则返回空
*
* @param maxUpdateTime 当前敏感词的最大更新时间
* @return 敏感词列表
*/
private
List
<
SensitiveWordDO
>
loadSensitiveWordIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 第一步,判断是否要更新。
// 如果更新时间为空,说明 DB 一定有新数据
if
(
maxUpdateTime
==
null
)
{
log
.
info
(
"[loadSensitiveWordIfUpdate][首次加载全量敏感词]"
);
}
else
{
// 判断数据库中是否有更新的敏感词
if
(
sensitiveWordMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
return
null
;
}
log
.
info
(
"[loadSensitiveWordIfUpdate][增量加载全量敏感词]"
);
}
// 第二步,如果有更新,则从数据库加载所有敏感词
return
sensitiveWordMapper
.
selectList
();
}
@Override
public
Long
createSensitiveWord
(
SensitiveWordCreateReqVO
createReqVO
)
{
// 校验唯一性
...
...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelService.java
浏览文件 @
6f8ca56e
...
...
@@ -21,7 +21,7 @@ public interface SmsChannelService {
/**
* 初始化短信客户端
*/
void
init
SmsClients
();
void
init
LocalCache
();
/**
* 创建短信渠道
...
...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceImpl.java
浏览文件 @
6f8ca56e
...
...
@@ -23,6 +23,7 @@ import java.time.LocalDateTime;
import
java.util.List
;
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,7 +31,6 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNE
* 短信渠道Service实现类
*
* @author zzf
* @date 2021/1/25 9:25
*/
@Service
@Slf4j
...
...
@@ -61,46 +61,39 @@ public class SmsChannelServiceImpl implements SmsChannelService {
@Override
@PostConstruct
public
void
initSmsClients
()
{
// 获取短信渠道,如果有更新
List
<
SmsChannelDO
>
smsChannels
=
this
.
loadSmsChannelIfUpdate
(
maxUpdateTime
);
if
(
CollUtil
.
isEmpty
(
smsChannels
))
{
return
;
}
// 创建或更新短信 Client
List
<
SmsChannelProperties
>
propertiesList
=
SmsChannelConvert
.
INSTANCE
.
convertList02
(
smsChannels
);
propertiesList
.
forEach
(
properties
->
smsClientFactory
.
createOrUpdateSmsClient
(
properties
));
// 写入缓存
maxUpdateTime
=
CollectionUtils
.
getMaxValue
(
smsChannels
,
SmsChannelDO:
:
getUpdateTime
);
log
.
info
(
"[initSmsClients][初始化 SmsChannel 数量为 {}]"
,
smsChannels
.
size
());
public
void
initLocalCache
()
{
initLocalCacheIfUpdate
(
null
);
}
@Scheduled
(
fixedDelay
=
SCHEDULER_PERIOD
,
initialDelay
=
SCHEDULER_PERIOD
)
public
void
schedulePeriodicRefresh
()
{
init
SmsClients
(
);
init
LocalCacheIfUpdate
(
this
.
maxUpdateTime
);
}
/**
* 如果短信渠道发生变化,从数据库中获取最新的全量短信渠道。
* 如果未发生变化,则返回空
* 刷新本地缓存
*
* @param maxUpdateTime 当前短信渠道的最大更新时间
* @return 短信渠道列表
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
* 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
*/
private
List
<
SmsChannelDO
>
loadSmsChannelIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 第一步,判断是否要更新。
if
(
maxUpdateTime
==
null
)
{
// 如果更新时间为空,说明 DB 一定有新数据
log
.
info
(
"[loadSmsChannelIfUpdate][首次加载全量短信渠道]"
);
}
else
{
// 判断数据库中是否有更新的短信渠道
if
(
smsChannelMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
return
null
;
}
log
.
info
(
"[loadSmsChannelIfUpdate][增量加载全量短信渠道]"
);
private
void
initLocalCacheIfUpdate
(
LocalDateTime
maxUpdateTime
)
{
// 第一步:基于 maxUpdateTime 判断缓存是否刷新。
// 如果没有增量的数据变化,则不进行本地缓存的刷新
if
(
maxUpdateTime
!=
null
&&
smsChannelMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
log
.
info
(
"[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]"
,
maxUpdateTime
);
return
;
}
// 第二步,如果有更新,则从数据库加载所有短信渠道
return
smsChannelMapper
.
selectList
();
List
<
SmsChannelDO
>
channels
=
smsChannelMapper
.
selectList
();
log
.
info
(
"[initLocalCacheIfUpdate][缓存短信渠道,数量为:{}]"
,
channels
.
size
());
// 第二步:构建缓存。创建或更新短信 Client
List
<
SmsChannelProperties
>
propertiesList
=
SmsChannelConvert
.
INSTANCE
.
convertList02
(
channels
);
propertiesList
.
forEach
(
properties
->
smsClientFactory
.
createOrUpdateSmsClient
(
properties
));
// 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
this
.
maxUpdateTime
=
getMaxValue
(
channels
,
SmsChannelDO:
:
getUpdateTime
);
}
@Override
...
...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java
浏览文件 @
6f8ca56e
...
...
@@ -71,7 +71,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
private
PermissionProducer
permissionProducer
;
@Test
public
void
testInit
RoleMenuLocalCache
()
{
public
void
testInit
LocalCacheIfUpdateForRoleMenu
()
{
// mock 数据
RoleMenuDO
roleMenuDO01
=
randomPojo
(
RoleMenuDO
.
class
,
o
->
o
.
setRoleId
(
1L
).
setMenuId
(
10L
));
roleMenuMapper
.
insert
(
roleMenuDO01
);
...
...
@@ -79,7 +79,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
roleMenuMapper
.
insert
(
roleMenuDO02
);
// 调用
permissionService
.
init
RoleMenuLocalCache
(
);
permissionService
.
init
LocalCacheIfUpdateForRoleMenu
(
null
);
// 断言 roleMenuCache 缓存
assertEquals
(
1
,
permissionService
.
getRoleMenuCache
().
keySet
().
size
());
assertEquals
(
asList
(
10L
,
20L
),
permissionService
.
getRoleMenuCache
().
get
(
1L
));
...
...
@@ -93,7 +93,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
}
@Test
public
void
testInit
UserRoleLocalCach
e
()
{
public
void
testInit
LocalCacheIfUpdateForUserRol
e
()
{
// mock 数据
UserRoleDO
userRoleDO01
=
randomPojo
(
UserRoleDO
.
class
,
o
->
o
.
setUserId
(
1L
).
setRoleId
(
10L
));
userRoleMapper
.
insert
(
userRoleDO01
);
...
...
@@ -101,7 +101,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
userRoleMapper
.
insert
(
roleMenuDO02
);
// 调用
permissionService
.
init
UserRoleLocalCache
(
);
permissionService
.
init
LocalCacheIfUpdateForUserRole
(
null
);
// 断言 roleMenuCache 缓存
assertEquals
(
1
,
permissionService
.
getUserRoleCache
().
size
());
assertEquals
(
asSet
(
10L
,
20L
),
permissionService
.
getUserRoleCache
().
get
(
1L
));
...
...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceTest.java
浏览文件 @
6f8ca56e
...
...
@@ -57,7 +57,7 @@ public class SmsChannelServiceTest extends BaseDbUnitTest {
smsChannelMapper
.
insert
(
smsChannelDO02
);
// 调用
smsChannelService
.
init
SmsClients
();
smsChannelService
.
init
LocalCache
();
// 校验 maxUpdateTime 属性
LocalDateTime
maxUpdateTime
=
(
LocalDateTime
)
BeanUtil
.
getFieldValue
(
smsChannelService
,
"maxUpdateTime"
);
assertEquals
(
max
(
smsChannelDO01
.
getUpdateTime
(),
smsChannelDO02
.
getUpdateTime
()),
maxUpdateTime
);
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论