Commit 1ecbe5aa6132b5e7c6b2af31020e1c730b499e43
1 parent
545e9d2a
增加角色的本地缓存刷新
Showing
12 changed files
with
166 additions
and
20 deletions
src/main/java/cn/iocoder/dashboard/framework/mybatis/core/mapper/BaseMapperX.java
| @@ -4,10 +4,13 @@ import cn.iocoder.dashboard.common.pojo.PageParam; | @@ -4,10 +4,13 @@ import cn.iocoder.dashboard.common.pojo.PageParam; | ||
| 4 | import cn.iocoder.dashboard.common.pojo.PageResult; | 4 | import cn.iocoder.dashboard.common.pojo.PageResult; |
| 5 | import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils; | 5 | import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils; |
| 6 | import com.baomidou.mybatisplus.core.conditions.Wrapper; | 6 | import com.baomidou.mybatisplus.core.conditions.Wrapper; |
| 7 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||
| 7 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; | 8 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| 8 | import com.baomidou.mybatisplus.core.metadata.IPage; | 9 | import com.baomidou.mybatisplus.core.metadata.IPage; |
| 9 | import org.apache.ibatis.annotations.Param; | 10 | import org.apache.ibatis.annotations.Param; |
| 10 | 11 | ||
| 12 | +import java.util.List; | ||
| 13 | + | ||
| 11 | /** | 14 | /** |
| 12 | * 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力 | 15 | * 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力 |
| 13 | */ | 16 | */ |
| @@ -21,4 +24,8 @@ public interface BaseMapperX<T> extends BaseMapper<T> { | @@ -21,4 +24,8 @@ public interface BaseMapperX<T> extends BaseMapper<T> { | ||
| 21 | return new PageResult<>(mpPage.getRecords(), mpPage.getTotal()); | 24 | return new PageResult<>(mpPage.getRecords(), mpPage.getTotal()); |
| 22 | } | 25 | } |
| 23 | 26 | ||
| 27 | + default List<T> selectList() { | ||
| 28 | + return selectList(new QueryWrapper<>()); | ||
| 29 | + } | ||
| 30 | + | ||
| 24 | } | 31 | } |
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/permission/SysMenuMapper.java
| 1 | package cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission; | 1 | package cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX; | ||
| 3 | import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX; | 4 | import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX; |
| 4 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.menu.SysMenuListReqVO; | 5 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.menu.SysMenuListReqVO; |
| 5 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; | 6 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; |
| 6 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | 7 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| 7 | -import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 8 | import org.apache.ibatis.annotations.Mapper; | 8 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 9 | ||
| 10 | import java.util.Date; | 10 | import java.util.Date; |
| 11 | import java.util.List; | 11 | import java.util.List; |
| 12 | 12 | ||
| 13 | @Mapper | 13 | @Mapper |
| 14 | -public interface SysMenuMapper extends BaseMapper<SysMenuDO> { | 14 | +public interface SysMenuMapper extends BaseMapperX<SysMenuDO> { |
| 15 | 15 | ||
| 16 | default SysMenuDO selectByParentIdAndName(Long parentId, String name) { | 16 | default SysMenuDO selectByParentIdAndName(Long parentId, String name) { |
| 17 | return selectOne(new QueryWrapper<SysMenuDO>().eq("parent_id", parentId) | 17 | return selectOne(new QueryWrapper<SysMenuDO>().eq("parent_id", parentId) |
| @@ -27,10 +27,6 @@ public interface SysMenuMapper extends BaseMapper<SysMenuDO> { | @@ -27,10 +27,6 @@ public interface SysMenuMapper extends BaseMapper<SysMenuDO> { | ||
| 27 | .eqIfPresent("status", reqVO.getStatus())); | 27 | .eqIfPresent("status", reqVO.getStatus())); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | - default List<SysMenuDO> selectList() { | ||
| 31 | - return selectList(new QueryWrapper<>()); | ||
| 32 | - } | ||
| 33 | - | ||
| 34 | default boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime) { | 30 | default boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime) { |
| 35 | return selectOne(new QueryWrapper<SysMenuDO>().select("id") | 31 | return selectOne(new QueryWrapper<SysMenuDO>().select("id") |
| 36 | .gt("update_time", maxUpdateTime).last("LIMIT 1")) != null; | 32 | .gt("update_time", maxUpdateTime).last("LIMIT 1")) != null; |
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/permission/SysRoleMapper.java
| 1 | package cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission; | 1 | package cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX; | ||
| 3 | import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX; | 4 | import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX; |
| 4 | import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils; | 5 | import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils; |
| 5 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRoleExportReqVO; | 6 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRoleExportReqVO; |
| 6 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRolePageReqVO; | 7 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRolePageReqVO; |
| 7 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; | 8 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; |
| 8 | -import com.baomidou.mybatisplus.core.mapper.BaseMapper; | 9 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| 9 | import com.baomidou.mybatisplus.core.metadata.IPage; | 10 | import com.baomidou.mybatisplus.core.metadata.IPage; |
| 10 | import org.apache.ibatis.annotations.Mapper; | 11 | import org.apache.ibatis.annotations.Mapper; |
| 11 | import org.springframework.lang.Nullable; | 12 | import org.springframework.lang.Nullable; |
| 12 | 13 | ||
| 13 | import java.util.Collection; | 14 | import java.util.Collection; |
| 15 | +import java.util.Date; | ||
| 14 | import java.util.List; | 16 | import java.util.List; |
| 15 | 17 | ||
| 16 | @Mapper | 18 | @Mapper |
| 17 | -public interface SysRoleMapper extends BaseMapper<SysRoleDO> { | 19 | +public interface SysRoleMapper extends BaseMapperX<SysRoleDO> { |
| 18 | 20 | ||
| 19 | default IPage<SysRoleDO> selectPage(SysRolePageReqVO reqVO) { | 21 | default IPage<SysRoleDO> selectPage(SysRolePageReqVO reqVO) { |
| 20 | return selectPage(MyBatisUtils.buildPage(reqVO), | 22 | return selectPage(MyBatisUtils.buildPage(reqVO), |
| @@ -43,4 +45,9 @@ public interface SysRoleMapper extends BaseMapper<SysRoleDO> { | @@ -43,4 +45,9 @@ public interface SysRoleMapper extends BaseMapper<SysRoleDO> { | ||
| 43 | return selectList(new QueryWrapperX<SysRoleDO>().in("status", statuses)); | 45 | return selectList(new QueryWrapperX<SysRoleDO>().in("status", statuses)); |
| 44 | } | 46 | } |
| 45 | 47 | ||
| 48 | + default boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime) { | ||
| 49 | + return selectOne(new QueryWrapper<SysRoleDO>().select("id") | ||
| 50 | + .gt("update_time", maxUpdateTime).last("LIMIT 1")) != null; | ||
| 51 | + } | ||
| 52 | + | ||
| 46 | } | 53 | } |
src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleRefreshConsumer.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.system.mq.consumer.permission; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; | ||
| 4 | +import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleRefreshMessage; | ||
| 5 | +import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; | ||
| 6 | +import lombok.extern.slf4j.Slf4j; | ||
| 7 | +import org.springframework.stereotype.Component; | ||
| 8 | + | ||
| 9 | +import javax.annotation.Resource; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * 针对 {@link SysRoleRefreshMessage} 的消费者 | ||
| 13 | + * | ||
| 14 | + * @author 芋道源码 | ||
| 15 | + */ | ||
| 16 | +@Component | ||
| 17 | +@Slf4j | ||
| 18 | +public class SysRoleRefreshConsumer extends AbstractChannelMessageListener<SysRoleRefreshMessage> { | ||
| 19 | + | ||
| 20 | + @Resource | ||
| 21 | + private SysRoleService roleService; | ||
| 22 | + | ||
| 23 | + @Override | ||
| 24 | + public void onMessage(SysRoleRefreshMessage message) { | ||
| 25 | + log.info("[onMessage][收到 Role 刷新消息]"); | ||
| 26 | + roleService.initLocalCache(); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | +} |
src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleRefreshMessage.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.system.mq.message.permission; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * 角色数据刷新 Message | ||
| 8 | + */ | ||
| 9 | +@Data | ||
| 10 | +public class SysRoleRefreshMessage implements ChannelMessage { | ||
| 11 | + | ||
| 12 | + @Override | ||
| 13 | + public String getChannel() { | ||
| 14 | + return "system.role.refresh"; | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | +} |
src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysRoleProducer.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.system.mq.producer.permission; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; | ||
| 4 | +import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleRefreshMessage; | ||
| 5 | +import org.springframework.data.redis.core.StringRedisTemplate; | ||
| 6 | +import org.springframework.stereotype.Component; | ||
| 7 | + | ||
| 8 | +import javax.annotation.Resource; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * Role 角色相关消息的 Producer | ||
| 12 | + */ | ||
| 13 | +@Component | ||
| 14 | +public class SysRoleProducer { | ||
| 15 | + | ||
| 16 | + @Resource | ||
| 17 | + private StringRedisTemplate stringRedisTemplate; | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * 发送 {@link SysRoleRefreshMessage} 消息 | ||
| 21 | + */ | ||
| 22 | + public void sendRoleRefreshMessage() { | ||
| 23 | + SysRoleRefreshMessage message = new SysRoleRefreshMessage(); | ||
| 24 | + RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | +} |
src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java
| @@ -88,7 +88,7 @@ public class SysDeptServiceImpl implements SysDeptService { | @@ -88,7 +88,7 @@ public class SysDeptServiceImpl implements SysDeptService { | ||
| 88 | parentDeptCache = parentBuilder.build(); | 88 | parentDeptCache = parentBuilder.build(); |
| 89 | assert deptList.size() > 0; // 断言,避免告警 | 89 | assert deptList.size() > 0; // 断言,避免告警 |
| 90 | maxUpdateTime = deptList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); | 90 | maxUpdateTime = deptList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); |
| 91 | - log.info("[init][初始化 Dept 数量为 {}]", deptList.size()); | 91 | + log.info("[initLocalCache][初始化 Dept 数量为 {}]", deptList.size()); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) | 94 | @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) |
| @@ -201,7 +201,6 @@ public class SysDeptServiceImpl implements SysDeptService { | @@ -201,7 +201,6 @@ public class SysDeptServiceImpl implements SysDeptService { | ||
| 201 | // 删除部门 | 201 | // 删除部门 |
| 202 | deptMapper.deleteById(id); | 202 | deptMapper.deleteById(id); |
| 203 | // TODO 需要处理下与角色的数据权限关联,等做数据权限一起处理下 | 203 | // TODO 需要处理下与角色的数据权限关联,等做数据权限一起处理下 |
| 204 | - | ||
| 205 | // 发送刷新消息 | 204 | // 发送刷新消息 |
| 206 | deptProducer.sendDeptRefreshMessage(); | 205 | deptProducer.sendDeptRefreshMessage(); |
| 207 | } | 206 | } |
src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java
| @@ -100,7 +100,7 @@ public class SysDictDataServiceImpl implements SysDictDataService { | @@ -100,7 +100,7 @@ public class SysDictDataServiceImpl implements SysDictDataService { | ||
| 100 | valueDictDataCache = valueDictDataBuilder.build(); | 100 | valueDictDataCache = valueDictDataBuilder.build(); |
| 101 | assert dataList.size() > 0; // 断言,避免告警 | 101 | assert dataList.size() > 0; // 断言,避免告警 |
| 102 | maxUpdateTime = dataList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); | 102 | maxUpdateTime = dataList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); |
| 103 | - log.info("[init][缓存字典数据,数量为:{}]", dataList.size()); | 103 | + log.info("[initLocalCache][缓存字典数据,数量为:{}]", dataList.size()); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) | 106 | @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/SysRoleService.java
| @@ -20,9 +20,9 @@ import java.util.Set; | @@ -20,9 +20,9 @@ import java.util.Set; | ||
| 20 | public interface SysRoleService { | 20 | public interface SysRoleService { |
| 21 | 21 | ||
| 22 | /** | 22 | /** |
| 23 | - * 初始化 | 23 | + * 初始化角色的本地缓存 |
| 24 | */ | 24 | */ |
| 25 | - void init(); | 25 | + void initLocalCache(); |
| 26 | 26 | ||
| 27 | /** | 27 | /** |
| 28 | * 获得角色,从缓存中 | 28 | * 获得角色,从缓存中 |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java
| @@ -98,7 +98,7 @@ public class SysMenuServiceImpl implements SysMenuService { | @@ -98,7 +98,7 @@ public class SysMenuServiceImpl implements SysMenuService { | ||
| 98 | permMenuCache = permMenuCacheBuilder.build(); | 98 | permMenuCache = permMenuCacheBuilder.build(); |
| 99 | assert menuList.size() > 0; // 断言,避免告警 | 99 | assert menuList.size() > 0; // 断言,避免告警 |
| 100 | maxUpdateTime = menuList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); | 100 | maxUpdateTime = menuList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); |
| 101 | - log.info("[init][缓存菜单,数量为:{}]", menuList.size()); | 101 | + log.info("[initLocalCache][缓存菜单,数量为:{}]", menuList.size()); |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) | 104 | @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java
| @@ -78,7 +78,7 @@ public class SysPermissionServiceImpl implements SysPermissionService { | @@ -78,7 +78,7 @@ public class SysPermissionServiceImpl implements SysPermissionService { | ||
| 78 | }); | 78 | }); |
| 79 | roleMenuCache = roleMenuCacheBuilder.build(); | 79 | roleMenuCache = roleMenuCacheBuilder.build(); |
| 80 | menuRoleCache = menuRoleCacheBuilder.build(); | 80 | menuRoleCache = menuRoleCacheBuilder.build(); |
| 81 | - log.info("[init][初始化角色与菜单的关联数量为 {}]", roleMenuList.size()); | 81 | + log.info("[initLocalCache][初始化角色与菜单的关联数量为 {}]", roleMenuList.size()); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | @Override | 84 | @Override |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java
| 1 | package cn.iocoder.dashboard.modules.system.service.permission.impl; | 1 | package cn.iocoder.dashboard.modules.system.service.permission.impl; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.hutool.core.collection.CollectionUtil; | 4 | import cn.hutool.core.collection.CollectionUtil; |
| 4 | import cn.iocoder.dashboard.common.enums.CommonStatusEnum; | 5 | import cn.iocoder.dashboard.common.enums.CommonStatusEnum; |
| 5 | import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil; | 6 | import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil; |
| 6 | import cn.iocoder.dashboard.common.pojo.PageResult; | 7 | import cn.iocoder.dashboard.common.pojo.PageResult; |
| 8 | +import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; | ||
| 7 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRoleCreateReqVO; | 9 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRoleCreateReqVO; |
| 8 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRoleExportReqVO; | 10 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRoleExportReqVO; |
| 9 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRolePageReqVO; | 11 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRolePageReqVO; |
| @@ -13,14 +15,18 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysRoleMappe | @@ -13,14 +15,18 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysRoleMappe | ||
| 13 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; | 15 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; |
| 14 | import cn.iocoder.dashboard.modules.system.enums.permission.RoleCodeEnum; | 16 | import cn.iocoder.dashboard.modules.system.enums.permission.RoleCodeEnum; |
| 15 | import cn.iocoder.dashboard.modules.system.enums.permission.SysRoleTypeEnum; | 17 | import cn.iocoder.dashboard.modules.system.enums.permission.SysRoleTypeEnum; |
| 18 | +import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysRoleProducer; | ||
| 16 | import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; | 19 | import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; |
| 17 | import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; | 20 | import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; |
| 18 | import com.baomidou.mybatisplus.core.metadata.IPage; | 21 | import com.baomidou.mybatisplus.core.metadata.IPage; |
| 19 | import com.google.common.collect.ImmutableMap; | 22 | import com.google.common.collect.ImmutableMap; |
| 20 | import lombok.extern.slf4j.Slf4j; | 23 | import lombok.extern.slf4j.Slf4j; |
| 21 | import org.springframework.lang.Nullable; | 24 | import org.springframework.lang.Nullable; |
| 25 | +import org.springframework.scheduling.annotation.Scheduled; | ||
| 22 | import org.springframework.stereotype.Service; | 26 | import org.springframework.stereotype.Service; |
| 23 | import org.springframework.transaction.annotation.Transactional; | 27 | import org.springframework.transaction.annotation.Transactional; |
| 28 | +import org.springframework.transaction.support.TransactionSynchronization; | ||
| 29 | +import org.springframework.transaction.support.TransactionSynchronizationManager; | ||
| 24 | import org.springframework.util.StringUtils; | 30 | import org.springframework.util.StringUtils; |
| 25 | 31 | ||
| 26 | import javax.annotation.PostConstruct; | 32 | import javax.annotation.PostConstruct; |
| @@ -40,12 +46,22 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; | @@ -40,12 +46,22 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; | ||
| 40 | public class SysRoleServiceImpl implements SysRoleService { | 46 | public class SysRoleServiceImpl implements SysRoleService { |
| 41 | 47 | ||
| 42 | /** | 48 | /** |
| 49 | + * 定时执行 {@link #schedulePeriodicRefresh()} 的周期 | ||
| 50 | + * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高 | ||
| 51 | + */ | ||
| 52 | + private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; | ||
| 53 | + | ||
| 54 | + /** | ||
| 43 | * 角色缓存 | 55 | * 角色缓存 |
| 44 | * key:角色编号 {@link SysRoleDO#getId()} | 56 | * key:角色编号 {@link SysRoleDO#getId()} |
| 45 | * | 57 | * |
| 46 | * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | 58 | * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 |
| 47 | */ | 59 | */ |
| 48 | private volatile Map<Long, SysRoleDO> roleCache; | 60 | private volatile Map<Long, SysRoleDO> roleCache; |
| 61 | + /** | ||
| 62 | + * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新 | ||
| 63 | + */ | ||
| 64 | + private volatile Date maxUpdateTime; | ||
| 49 | 65 | ||
| 50 | @Resource | 66 | @Resource |
| 51 | private SysPermissionService permissionService; | 67 | private SysPermissionService permissionService; |
| @@ -53,19 +69,54 @@ public class SysRoleServiceImpl implements SysRoleService { | @@ -53,19 +69,54 @@ public class SysRoleServiceImpl implements SysRoleService { | ||
| 53 | @Resource | 69 | @Resource |
| 54 | private SysRoleMapper roleMapper; | 70 | private SysRoleMapper roleMapper; |
| 55 | 71 | ||
| 72 | + @Resource | ||
| 73 | + private SysRoleProducer roleProducer; | ||
| 74 | + | ||
| 56 | /** | 75 | /** |
| 57 | * 初始化 {@link #roleCache} 缓存 | 76 | * 初始化 {@link #roleCache} 缓存 |
| 58 | */ | 77 | */ |
| 59 | @Override | 78 | @Override |
| 60 | @PostConstruct | 79 | @PostConstruct |
| 61 | - public void init() { | ||
| 62 | - // 从数据库中读取 | ||
| 63 | - List<SysRoleDO> roleDOList = roleMapper.selectList(null); | 80 | + public void initLocalCache() { |
| 81 | + // 获取菜单列表,如果有更新 | ||
| 82 | + List<SysRoleDO> roleList = this.loadRoleIfUpdate(maxUpdateTime); | ||
| 83 | + if (CollUtil.isEmpty(roleList)) { | ||
| 84 | + return; | ||
| 85 | + } | ||
| 86 | + | ||
| 64 | // 写入缓存 | 87 | // 写入缓存 |
| 65 | ImmutableMap.Builder<Long, SysRoleDO> builder = ImmutableMap.builder(); | 88 | ImmutableMap.Builder<Long, SysRoleDO> builder = ImmutableMap.builder(); |
| 66 | - roleDOList.forEach(sysRoleDO -> builder.put(sysRoleDO.getId(), sysRoleDO)); | 89 | + roleList.forEach(sysRoleDO -> builder.put(sysRoleDO.getId(), sysRoleDO)); |
| 67 | roleCache = builder.build(); | 90 | roleCache = builder.build(); |
| 68 | - log.info("[init][初始化 Role 数量为 {}]", roleDOList.size()); | 91 | + assert roleList.size() > 0; // 断言,避免告警 |
| 92 | + maxUpdateTime = roleList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); | ||
| 93 | + log.info("[initLocalCache][初始化 Role 数量为 {}]", roleList.size()); | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) | ||
| 97 | + public void schedulePeriodicRefresh() { | ||
| 98 | + initLocalCache(); | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + /** | ||
| 102 | + * 如果菜单发生变化,从数据库中获取最新的全量菜单。 | ||
| 103 | + * 如果未发生变化,则返回空 | ||
| 104 | + * | ||
| 105 | + * @param maxUpdateTime 当前菜单的最大更新时间 | ||
| 106 | + * @return 菜单列表 | ||
| 107 | + */ | ||
| 108 | + private List<SysRoleDO> loadRoleIfUpdate(Date maxUpdateTime) { | ||
| 109 | + // 第一步,判断是否要更新。 | ||
| 110 | + if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 | ||
| 111 | + log.info("[loadRoleIfUpdate][首次加载全量菜单]"); | ||
| 112 | + } else { // 判断数据库中是否有更新的菜单 | ||
| 113 | + if (!roleMapper.selectExistsByUpdateTimeAfter(maxUpdateTime)) { | ||
| 114 | + return null; | ||
| 115 | + } | ||
| 116 | + log.info("[loadRoleIfUpdate][增量加载全量菜单]"); | ||
| 117 | + } | ||
| 118 | + // 第二步,如果有更新,则从数据库加载所有菜单 | ||
| 119 | + return roleMapper.selectList(); | ||
| 69 | } | 120 | } |
| 70 | 121 | ||
| 71 | @Override | 122 | @Override |
| @@ -104,6 +155,8 @@ public class SysRoleServiceImpl implements SysRoleService { | @@ -104,6 +155,8 @@ public class SysRoleServiceImpl implements SysRoleService { | ||
| 104 | role.setType(SysRoleTypeEnum.CUSTOM.getType()); | 155 | role.setType(SysRoleTypeEnum.CUSTOM.getType()); |
| 105 | role.setStatus(CommonStatusEnum.ENABLE.getStatus()); | 156 | role.setStatus(CommonStatusEnum.ENABLE.getStatus()); |
| 106 | roleMapper.insert(role); | 157 | roleMapper.insert(role); |
| 158 | + // 发送刷新消息 | ||
| 159 | + roleProducer.sendRoleRefreshMessage(); | ||
| 107 | // 返回 | 160 | // 返回 |
| 108 | return role.getId(); | 161 | return role.getId(); |
| 109 | } | 162 | } |
| @@ -117,6 +170,8 @@ public class SysRoleServiceImpl implements SysRoleService { | @@ -117,6 +170,8 @@ public class SysRoleServiceImpl implements SysRoleService { | ||
| 117 | // 更新到数据库 | 170 | // 更新到数据库 |
| 118 | SysRoleDO updateObject = SysRoleConvert.INSTANCE.convert(reqVO); | 171 | SysRoleDO updateObject = SysRoleConvert.INSTANCE.convert(reqVO); |
| 119 | roleMapper.updateById(updateObject); | 172 | roleMapper.updateById(updateObject); |
| 173 | + // 发送刷新消息 | ||
| 174 | + roleProducer.sendRoleRefreshMessage(); | ||
| 120 | } | 175 | } |
| 121 | 176 | ||
| 122 | @Override | 177 | @Override |
| @@ -128,6 +183,15 @@ public class SysRoleServiceImpl implements SysRoleService { | @@ -128,6 +183,15 @@ public class SysRoleServiceImpl implements SysRoleService { | ||
| 128 | roleMapper.deleteById(id); | 183 | roleMapper.deleteById(id); |
| 129 | // 删除相关数据 | 184 | // 删除相关数据 |
| 130 | permissionService.processRoleDeleted(id); | 185 | permissionService.processRoleDeleted(id); |
| 186 | + // 发送刷新消息. 注意,需要事务提交后,在进行发送刷新消息。不然 db 还未提交,结果缓存先刷新了 | ||
| 187 | + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { | ||
| 188 | + | ||
| 189 | + @Override | ||
| 190 | + public void afterCommit() { | ||
| 191 | + roleProducer.sendRoleRefreshMessage(); | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + }); | ||
| 131 | } | 195 | } |
| 132 | 196 | ||
| 133 | @Override | 197 | @Override |