Commit 49b4eedfc0ca13bfb0c4fdfab952b0574c754153
1 parent
97db4586
增加 UserRole 的缓存,完善权限相关的单元测试
Showing
8 changed files
with
451 additions
and
64 deletions
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java
| @@ -93,7 +93,7 @@ public class AuthController { | @@ -93,7 +93,7 @@ public class AuthController { | ||
| 93 | return null; | 93 | return null; |
| 94 | } | 94 | } |
| 95 | // 获得角色列表 | 95 | // 获得角色列表 |
| 96 | - Set<Long> roleIds = permissionService.getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus())); | 96 | + Set<Long> roleIds = permissionService.getUserRoleIdsFromCache(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus())); |
| 97 | List<RoleDO> roleList = roleService.getRolesFromCache(roleIds); | 97 | List<RoleDO> roleList = roleService.getRolesFromCache(roleIds); |
| 98 | // 获得菜单列表 | 98 | // 获得菜单列表 |
| 99 | List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds, | 99 | List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds, |
| @@ -107,7 +107,7 @@ public class AuthController { | @@ -107,7 +107,7 @@ public class AuthController { | ||
| 107 | @ApiOperation("获得登录用户的菜单列表") | 107 | @ApiOperation("获得登录用户的菜单列表") |
| 108 | public CommonResult<List<AuthMenuRespVO>> getMenus() { | 108 | public CommonResult<List<AuthMenuRespVO>> getMenus() { |
| 109 | // 获得角色列表 | 109 | // 获得角色列表 |
| 110 | - Set<Long> roleIds = permissionService.getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus())); | 110 | + Set<Long> roleIds = permissionService.getUserRoleIdsFromCache(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus())); |
| 111 | // 获得用户拥有的菜单列表 | 111 | // 获得用户拥有的菜单列表 |
| 112 | List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds, | 112 | List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds, |
| 113 | SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型 | 113 | SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型 |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/UserRoleMapper.java
| @@ -4,8 +4,10 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | @@ -4,8 +4,10 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 4 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO; | 4 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO; |
| 5 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | 5 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| 6 | import org.apache.ibatis.annotations.Mapper; | 6 | import org.apache.ibatis.annotations.Mapper; |
| 7 | +import org.apache.ibatis.annotations.Select; | ||
| 7 | 8 | ||
| 8 | import java.util.Collection; | 9 | import java.util.Collection; |
| 10 | +import java.util.Date; | ||
| 9 | import java.util.List; | 11 | import java.util.List; |
| 10 | 12 | ||
| 11 | @Mapper | 13 | @Mapper |
| @@ -36,4 +38,8 @@ public interface UserRoleMapper extends BaseMapperX<UserRoleDO> { | @@ -36,4 +38,8 @@ public interface UserRoleMapper extends BaseMapperX<UserRoleDO> { | ||
| 36 | default List<UserRoleDO> selectListByRoleIds(Collection<Long> roleIds) { | 38 | default List<UserRoleDO> selectListByRoleIds(Collection<Long> roleIds) { |
| 37 | return selectList(UserRoleDO::getRoleId, roleIds); | 39 | return selectList(UserRoleDO::getRoleId, roleIds); |
| 38 | } | 40 | } |
| 41 | + | ||
| 42 | + @Select("SELECT COUNT(*) FROM system_user_role WHERE update_time > #{maxUpdateTime}") | ||
| 43 | + Long selectCountByUpdateTimeGt(Date maxUpdateTime); | ||
| 44 | + | ||
| 39 | } | 45 | } |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/permission/UserRoleRefreshConsumer.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.mq.consumer.permission; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener; | ||
| 4 | +import cn.iocoder.yudao.module.system.mq.message.permission.UserRoleRefreshMessage; | ||
| 5 | +import cn.iocoder.yudao.module.system.service.permission.PermissionService; | ||
| 6 | +import lombok.extern.slf4j.Slf4j; | ||
| 7 | +import org.springframework.stereotype.Component; | ||
| 8 | + | ||
| 9 | +import javax.annotation.Resource; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * 针对 {@link UserRoleRefreshMessage} 的消费者 | ||
| 13 | + * | ||
| 14 | + * @author 芋道源码 | ||
| 15 | + */ | ||
| 16 | +@Component | ||
| 17 | +@Slf4j | ||
| 18 | +public class UserRoleRefreshConsumer extends AbstractChannelMessageListener<UserRoleRefreshMessage> { | ||
| 19 | + | ||
| 20 | + @Resource | ||
| 21 | + private PermissionService permissionService; | ||
| 22 | + | ||
| 23 | + @Override | ||
| 24 | + public void onMessage(UserRoleRefreshMessage message) { | ||
| 25 | + log.info("[onMessage][收到 User 与 Role 的关联刷新消息]"); | ||
| 26 | + permissionService.initLocalCache(); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | +} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/permission/UserRoleRefreshMessage.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.mq.message.permission; | ||
| 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 | + * @author 芋道源码 | ||
| 11 | + */ | ||
| 12 | +@Data | ||
| 13 | +@EqualsAndHashCode(callSuper = true) | ||
| 14 | +public class UserRoleRefreshMessage extends AbstractChannelMessage { | ||
| 15 | + | ||
| 16 | + @Override | ||
| 17 | + public String getChannel() { | ||
| 18 | + return "system.user-role.refresh"; | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | +} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/permission/PermissionProducer.java
| @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.mq.producer.permission; | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.mq.producer.permission; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.system.mq.message.permission.RoleMenuRefreshMessage; | 3 | import cn.iocoder.yudao.module.system.mq.message.permission.RoleMenuRefreshMessage; |
| 4 | import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; | 4 | import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; |
| 5 | +import cn.iocoder.yudao.module.system.mq.message.permission.UserRoleRefreshMessage; | ||
| 5 | import org.springframework.stereotype.Component; | 6 | import org.springframework.stereotype.Component; |
| 6 | 7 | ||
| 7 | import javax.annotation.Resource; | 8 | import javax.annotation.Resource; |
| @@ -23,4 +24,12 @@ public class PermissionProducer { | @@ -23,4 +24,12 @@ public class PermissionProducer { | ||
| 23 | redisMQTemplate.send(message); | 24 | redisMQTemplate.send(message); |
| 24 | } | 25 | } |
| 25 | 26 | ||
| 27 | + /** | ||
| 28 | + * 发送 {@link UserRoleRefreshMessage} 消息 | ||
| 29 | + */ | ||
| 30 | + public void sendUserRoleRefreshMessage() { | ||
| 31 | + UserRoleRefreshMessage message = new UserRoleRefreshMessage(); | ||
| 32 | + redisMQTemplate.send(message); | ||
| 33 | + } | ||
| 34 | + | ||
| 26 | } | 35 | } |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionService.java
| @@ -37,13 +37,13 @@ public interface PermissionService extends SecurityPermissionFrameworkService, D | @@ -37,13 +37,13 @@ public interface PermissionService extends SecurityPermissionFrameworkService, D | ||
| 37 | Collection<Integer> menusStatuses); | 37 | Collection<Integer> menusStatuses); |
| 38 | 38 | ||
| 39 | /** | 39 | /** |
| 40 | - * 获得用户拥有的角色编号集合 | 40 | + * 获得用户拥有的角色编号集合,从缓存中获取 |
| 41 | * | 41 | * |
| 42 | * @param userId 用户编号 | 42 | * @param userId 用户编号 |
| 43 | * @param roleStatuses 角色状态集合. 允许为空,为空时不过滤 | 43 | * @param roleStatuses 角色状态集合. 允许为空,为空时不过滤 |
| 44 | * @return 角色编号集合 | 44 | * @return 角色编号集合 |
| 45 | */ | 45 | */ |
| 46 | - Set<Long> getUserRoleIds(Long userId, @Nullable Collection<Integer> roleStatuses); | 46 | + Set<Long> getUserRoleIdsFromCache(Long userId, @Nullable Collection<Integer> roleStatuses); |
| 47 | 47 | ||
| 48 | /** | 48 | /** |
| 49 | * 获得角色拥有的菜单编号集合 | 49 | * 获得角色拥有的菜单编号集合 |
| @@ -54,6 +54,14 @@ public interface PermissionService extends SecurityPermissionFrameworkService, D | @@ -54,6 +54,14 @@ public interface PermissionService extends SecurityPermissionFrameworkService, D | ||
| 54 | Set<Long> getRoleMenuIds(Long roleId); | 54 | Set<Long> getRoleMenuIds(Long roleId); |
| 55 | 55 | ||
| 56 | /** | 56 | /** |
| 57 | + * 获得拥有多个角色的用户编号集合 | ||
| 58 | + * | ||
| 59 | + * @param roleIds 角色编号集合 | ||
| 60 | + * @return 用户编号集合 | ||
| 61 | + */ | ||
| 62 | + Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds); | ||
| 63 | + | ||
| 64 | + /** | ||
| 57 | * 设置角色菜单 | 65 | * 设置角色菜单 |
| 58 | * | 66 | * |
| 59 | * @param roleId 角色编号 | 67 | * @param roleId 角色编号 |
| @@ -70,14 +78,6 @@ public interface PermissionService extends SecurityPermissionFrameworkService, D | @@ -70,14 +78,6 @@ public interface PermissionService extends SecurityPermissionFrameworkService, D | ||
| 70 | Set<Long> getUserRoleIdListByUserId(Long userId); | 78 | Set<Long> getUserRoleIdListByUserId(Long userId); |
| 71 | 79 | ||
| 72 | /** | 80 | /** |
| 73 | - * 获得拥有某个角色的用户编号集合 | ||
| 74 | - * | ||
| 75 | - * @param roleId 角色编号 | ||
| 76 | - * @return 用户编号集合 | ||
| 77 | - */ | ||
| 78 | - Set<Long> getUserRoleIdListByRoleId(Long roleId); | ||
| 79 | - | ||
| 80 | - /** | ||
| 81 | * 设置用户角色 | 81 | * 设置用户角色 |
| 82 | * | 82 | * |
| 83 | * @param userId 角色编号 | 83 | * @param userId 角色编号 |
| @@ -115,12 +115,4 @@ public interface PermissionService extends SecurityPermissionFrameworkService, D | @@ -115,12 +115,4 @@ public interface PermissionService extends SecurityPermissionFrameworkService, D | ||
| 115 | */ | 115 | */ |
| 116 | void processUserDeleted(Long userId); | 116 | void processUserDeleted(Long userId); |
| 117 | 117 | ||
| 118 | - /** | ||
| 119 | - * 获得拥有多个角色的用户编号集合 | ||
| 120 | - * | ||
| 121 | - * @param roleIds 角色编号集合 | ||
| 122 | - * @return 用户编号集合 | ||
| 123 | - */ | ||
| 124 | - Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds); | ||
| 125 | - | ||
| 126 | } | 118 | } |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java
| @@ -23,10 +23,13 @@ import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; | @@ -23,10 +23,13 @@ import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; | ||
| 23 | import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer; | 23 | import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer; |
| 24 | import cn.iocoder.yudao.module.system.service.dept.DeptService; | 24 | import cn.iocoder.yudao.module.system.service.dept.DeptService; |
| 25 | import cn.iocoder.yudao.module.system.service.user.AdminUserService; | 25 | import cn.iocoder.yudao.module.system.service.user.AdminUserService; |
| 26 | +import com.google.common.annotations.VisibleForTesting; | ||
| 26 | import com.google.common.base.Suppliers; | 27 | import com.google.common.base.Suppliers; |
| 27 | import com.google.common.collect.ImmutableMultimap; | 28 | import com.google.common.collect.ImmutableMultimap; |
| 28 | import com.google.common.collect.Multimap; | 29 | import com.google.common.collect.Multimap; |
| 29 | import com.google.common.collect.Sets; | 30 | import com.google.common.collect.Sets; |
| 31 | +import lombok.Getter; | ||
| 32 | +import lombok.Setter; | ||
| 30 | import lombok.extern.slf4j.Slf4j; | 33 | import lombok.extern.slf4j.Slf4j; |
| 31 | import org.springframework.context.annotation.Lazy; | 34 | import org.springframework.context.annotation.Lazy; |
| 32 | import org.springframework.scheduling.annotation.Scheduled; | 35 | import org.springframework.scheduling.annotation.Scheduled; |
| @@ -40,6 +43,8 @@ import javax.annotation.Resource; | @@ -40,6 +43,8 @@ import javax.annotation.Resource; | ||
| 40 | import java.util.*; | 43 | import java.util.*; |
| 41 | import java.util.function.Supplier; | 44 | import java.util.function.Supplier; |
| 42 | 45 | ||
| 46 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | ||
| 47 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue; | ||
| 43 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 48 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 44 | import static java.util.Collections.singleton; | 49 | import static java.util.Collections.singleton; |
| 45 | 50 | ||
| @@ -65,6 +70,8 @@ public class PermissionServiceImpl implements PermissionService { | @@ -65,6 +70,8 @@ public class PermissionServiceImpl implements PermissionService { | ||
| 65 | * | 70 | * |
| 66 | * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | 71 | * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 |
| 67 | */ | 72 | */ |
| 73 | + @Getter | ||
| 74 | + @Setter // 单元测试 | ||
| 68 | private volatile Multimap<Long, Long> roleMenuCache; | 75 | private volatile Multimap<Long, Long> roleMenuCache; |
| 69 | /** | 76 | /** |
| 70 | * 菜单编号与角色编号的缓存映射 | 77 | * 菜单编号与角色编号的缓存映射 |
| @@ -73,11 +80,29 @@ public class PermissionServiceImpl implements PermissionService { | @@ -73,11 +80,29 @@ public class PermissionServiceImpl implements PermissionService { | ||
| 73 | * | 80 | * |
| 74 | * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | 81 | * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 |
| 75 | */ | 82 | */ |
| 83 | + @Getter | ||
| 76 | private volatile Multimap<Long, Long> menuRoleCache; | 84 | private volatile Multimap<Long, Long> menuRoleCache; |
| 77 | /** | 85 | /** |
| 78 | - * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新 | 86 | + * 缓存 RoleMenu 的最大更新时间,用于后续的增量轮询,判断是否有更新 |
| 79 | */ | 87 | */ |
| 80 | - private volatile Date maxUpdateTime; | 88 | + @Getter |
| 89 | + private volatile Date roleMenuMaxUpdateTime; | ||
| 90 | + | ||
| 91 | + /** | ||
| 92 | + * 用户编号与角色编号的缓存映射 | ||
| 93 | + * key:用户编号 | ||
| 94 | + * value:角色编号的数组 | ||
| 95 | + * | ||
| 96 | + * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | ||
| 97 | + */ | ||
| 98 | + @Getter | ||
| 99 | + @Setter // 单元测试需要 | ||
| 100 | + private volatile Map<Long, Set<Long>> userRoleCache; | ||
| 101 | + /** | ||
| 102 | + * 缓存 UserRole 的最大更新时间,用于后续的增量轮询,判断是否有更新 | ||
| 103 | + */ | ||
| 104 | + @Getter | ||
| 105 | + private volatile Date userRoleMaxUpdateTime; | ||
| 81 | 106 | ||
| 82 | @Resource | 107 | @Resource |
| 83 | private RoleMenuMapper roleMenuMapper; | 108 | private RoleMenuMapper roleMenuMapper; |
| @@ -104,15 +129,21 @@ public class PermissionServiceImpl implements PermissionService { | @@ -104,15 +129,21 @@ public class PermissionServiceImpl implements PermissionService { | ||
| 104 | @Lazy // 注入自己,所以延迟加载 | 129 | @Lazy // 注入自己,所以延迟加载 |
| 105 | private PermissionService self; | 130 | private PermissionService self; |
| 106 | 131 | ||
| 107 | - /** | ||
| 108 | - * 初始化 {@link #roleMenuCache} 和 {@link #menuRoleCache} 缓存 | ||
| 109 | - */ | ||
| 110 | @Override | 132 | @Override |
| 111 | @PostConstruct | 133 | @PostConstruct |
| 112 | @TenantIgnore // 初始化缓存,无需租户过滤 | 134 | @TenantIgnore // 初始化缓存,无需租户过滤 |
| 113 | public void initLocalCache() { | 135 | public void initLocalCache() { |
| 136 | + initUserRoleLocalCache(); | ||
| 137 | + initRoleMenuLocalCache(); | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + /** | ||
| 141 | + * 初始化 {@link #roleMenuCache} 和 {@link #menuRoleCache} 缓存 | ||
| 142 | + */ | ||
| 143 | + @VisibleForTesting | ||
| 144 | + void initRoleMenuLocalCache() { | ||
| 114 | // 获取角色与菜单的关联列表,如果有更新 | 145 | // 获取角色与菜单的关联列表,如果有更新 |
| 115 | - List<RoleMenuDO> roleMenuList = loadRoleMenuIfUpdate(maxUpdateTime); | 146 | + List<RoleMenuDO> roleMenuList = loadRoleMenuIfUpdate(roleMenuMaxUpdateTime); |
| 116 | if (CollUtil.isEmpty(roleMenuList)) { | 147 | if (CollUtil.isEmpty(roleMenuList)) { |
| 117 | return; | 148 | return; |
| 118 | } | 149 | } |
| @@ -126,8 +157,27 @@ public class PermissionServiceImpl implements PermissionService { | @@ -126,8 +157,27 @@ public class PermissionServiceImpl implements PermissionService { | ||
| 126 | }); | 157 | }); |
| 127 | roleMenuCache = roleMenuCacheBuilder.build(); | 158 | roleMenuCache = roleMenuCacheBuilder.build(); |
| 128 | menuRoleCache = menuRoleCacheBuilder.build(); | 159 | menuRoleCache = menuRoleCacheBuilder.build(); |
| 129 | - maxUpdateTime = CollectionUtils.getMaxValue(roleMenuList, RoleMenuDO::getUpdateTime); | ||
| 130 | - log.info("[initLocalCache][初始化角色与菜单的关联数量为 {}]", roleMenuList.size()); | 160 | + roleMenuMaxUpdateTime = getMaxValue(roleMenuList, RoleMenuDO::getUpdateTime); |
| 161 | + log.info("[initRoleMenuLocalCache][初始化角色与菜单的关联数量为 {}]", roleMenuList.size()); | ||
| 162 | + } | ||
| 163 | + | ||
| 164 | + /** | ||
| 165 | + * 初始化 {@link #userRoleCache} 缓存 | ||
| 166 | + */ | ||
| 167 | + @VisibleForTesting | ||
| 168 | + void initUserRoleLocalCache() { | ||
| 169 | + // 获取用户与角色的关联列表,如果有更新 | ||
| 170 | + List<UserRoleDO> userRoleList = loadUserRoleIfUpdate(userRoleMaxUpdateTime); | ||
| 171 | + if (CollUtil.isEmpty(userRoleList)) { | ||
| 172 | + return; | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + // 初始化 userRoleCache 缓存 | ||
| 176 | + ImmutableMultimap.Builder<Long, Long> userRoleCacheBuilder = ImmutableMultimap.builder(); | ||
| 177 | + userRoleList.forEach(userRoleDO -> userRoleCacheBuilder.put(userRoleDO.getUserId(), userRoleDO.getRoleId())); | ||
| 178 | + userRoleCache = CollectionUtils.convertMultiMap2(userRoleList, UserRoleDO::getUserId, UserRoleDO::getRoleId); | ||
| 179 | + userRoleMaxUpdateTime = getMaxValue(userRoleList, UserRoleDO::getUpdateTime); | ||
| 180 | + log.info("[initUserRoleLocalCache][初始化用户与角色的关联数量为 {}]", userRoleList.size()); | ||
| 131 | } | 181 | } |
| 132 | 182 | ||
| 133 | @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) | 183 | @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) |
| @@ -156,6 +206,27 @@ public class PermissionServiceImpl implements PermissionService { | @@ -156,6 +206,27 @@ public class PermissionServiceImpl implements PermissionService { | ||
| 156 | return roleMenuMapper.selectList(); | 206 | return roleMenuMapper.selectList(); |
| 157 | } | 207 | } |
| 158 | 208 | ||
| 209 | + /** | ||
| 210 | + * 如果用户与角色的关联发生变化,从数据库中获取最新的全量用户与角色的关联。 | ||
| 211 | + * 如果未发生变化,则返回空 | ||
| 212 | + * | ||
| 213 | + * @param maxUpdateTime 当前角色与菜单的关联的最大更新时间 | ||
| 214 | + * @return 角色与菜单的关联列表 | ||
| 215 | + */ | ||
| 216 | + protected List<UserRoleDO> loadUserRoleIfUpdate(Date maxUpdateTime) { | ||
| 217 | + // 第一步,判断是否要更新。 | ||
| 218 | + if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 | ||
| 219 | + log.info("[loadUserRoleIfUpdate][首次加载全量用户与角色的关联]"); | ||
| 220 | + } else { // 判断数据库中是否有更新的用户与角色的关联 | ||
| 221 | + if (userRoleMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) { | ||
| 222 | + return null; | ||
| 223 | + } | ||
| 224 | + log.info("[loadUserRoleIfUpdate][增量加载全量用户与角色的关联]"); | ||
| 225 | + } | ||
| 226 | + // 第二步,如果有更新,则从数据库加载所有用户与角色的关联 | ||
| 227 | + return userRoleMapper.selectList(); | ||
| 228 | + } | ||
| 229 | + | ||
| 159 | @Override | 230 | @Override |
| 160 | public List<MenuDO> getRoleMenuListFromCache(Collection<Long> roleIds, Collection<Integer> menuTypes, | 231 | public List<MenuDO> getRoleMenuListFromCache(Collection<Long> roleIds, Collection<Integer> menuTypes, |
| 161 | Collection<Integer> menusStatuses) { | 232 | Collection<Integer> menusStatuses) { |
| @@ -176,35 +247,33 @@ public class PermissionServiceImpl implements PermissionService { | @@ -176,35 +247,33 @@ public class PermissionServiceImpl implements PermissionService { | ||
| 176 | } | 247 | } |
| 177 | 248 | ||
| 178 | @Override | 249 | @Override |
| 179 | - public Set<Long> getUserRoleIds(Long userId, Collection<Integer> roleStatuses) { | ||
| 180 | - List<UserRoleDO> userRoleList = userRoleMapper.selectListByUserId(userId); | 250 | + public Set<Long> getUserRoleIdsFromCache(Long userId, Collection<Integer> roleStatuses) { |
| 251 | + Set<Long> roleIds = new HashSet<>(userRoleCache.get(userId)); | ||
| 181 | // 过滤角色状态 | 252 | // 过滤角色状态 |
| 182 | if (CollectionUtil.isNotEmpty(roleStatuses)) { | 253 | if (CollectionUtil.isNotEmpty(roleStatuses)) { |
| 183 | - userRoleList.removeIf(userRoleDO -> { | ||
| 184 | - RoleDO role = roleService.getRoleFromCache(userRoleDO.getRoleId()); | 254 | + roleIds.removeIf(roleId -> { |
| 255 | + RoleDO role = roleService.getRoleFromCache(roleId); | ||
| 185 | return role == null || !roleStatuses.contains(role.getStatus()); | 256 | return role == null || !roleStatuses.contains(role.getStatus()); |
| 186 | }); | 257 | }); |
| 187 | } | 258 | } |
| 188 | - return CollectionUtils.convertSet(userRoleList, UserRoleDO::getRoleId); | 259 | + return roleIds; |
| 189 | } | 260 | } |
| 190 | 261 | ||
| 191 | @Override | 262 | @Override |
| 192 | public Set<Long> getRoleMenuIds(Long roleId) { | 263 | public Set<Long> getRoleMenuIds(Long roleId) { |
| 193 | // 如果是管理员的情况下,获取全部菜单编号 | 264 | // 如果是管理员的情况下,获取全部菜单编号 |
| 194 | - RoleDO role = roleService.getRole(roleId); | ||
| 195 | - if (roleService.hasAnySuperAdmin(Collections.singletonList(role))) { | ||
| 196 | - return CollectionUtils.convertSet(menuService.getMenus(), MenuDO::getId); | 265 | + if (roleService.hasAnySuperAdmin(Collections.singleton(roleId))) { |
| 266 | + return convertSet(menuService.getMenus(), MenuDO::getId); | ||
| 197 | } | 267 | } |
| 198 | // 如果是非管理员的情况下,获得拥有的菜单编号 | 268 | // 如果是非管理员的情况下,获得拥有的菜单编号 |
| 199 | - return CollectionUtils.convertSet(roleMenuMapper.selectListByRoleId(roleId), | ||
| 200 | - RoleMenuDO::getMenuId); | 269 | + return convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId); |
| 201 | } | 270 | } |
| 202 | 271 | ||
| 203 | @Override | 272 | @Override |
| 204 | @Transactional(rollbackFor = Exception.class) | 273 | @Transactional(rollbackFor = Exception.class) |
| 205 | public void assignRoleMenu(Long roleId, Set<Long> menuIds) { | 274 | public void assignRoleMenu(Long roleId, Set<Long> menuIds) { |
| 206 | // 获得角色拥有菜单编号 | 275 | // 获得角色拥有菜单编号 |
| 207 | - Set<Long> dbMenuIds = CollectionUtils.convertSet(roleMenuMapper.selectListByRoleId(roleId), | 276 | + Set<Long> dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), |
| 208 | RoleMenuDO::getMenuId); | 277 | RoleMenuDO::getMenuId); |
| 209 | // 计算新增和删除的菜单编号 | 278 | // 计算新增和删除的菜单编号 |
| 210 | Collection<Long> createMenuIds = CollUtil.subtract(menuIds, dbMenuIds); | 279 | Collection<Long> createMenuIds = CollUtil.subtract(menuIds, dbMenuIds); |
| @@ -234,20 +303,21 @@ public class PermissionServiceImpl implements PermissionService { | @@ -234,20 +303,21 @@ public class PermissionServiceImpl implements PermissionService { | ||
| 234 | 303 | ||
| 235 | @Override | 304 | @Override |
| 236 | public Set<Long> getUserRoleIdListByUserId(Long userId) { | 305 | public Set<Long> getUserRoleIdListByUserId(Long userId) { |
| 237 | - return CollectionUtils.convertSet(userRoleMapper.selectListByUserId(userId), | 306 | + return convertSet(userRoleMapper.selectListByUserId(userId), |
| 238 | UserRoleDO::getRoleId); | 307 | UserRoleDO::getRoleId); |
| 239 | } | 308 | } |
| 240 | 309 | ||
| 241 | @Override | 310 | @Override |
| 242 | - public Set<Long> getUserRoleIdListByRoleId(Long roleId) { | ||
| 243 | - return CollectionUtils.convertSet(userRoleMapper.selectListByRoleId(roleId), | ||
| 244 | - UserRoleDO::getRoleId); | 311 | + public Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds) { |
| 312 | + return convertSet(userRoleMapper.selectListByRoleIds(roleIds), | ||
| 313 | + UserRoleDO::getUserId); | ||
| 245 | } | 314 | } |
| 246 | 315 | ||
| 247 | @Override | 316 | @Override |
| 317 | + @Transactional(rollbackFor = Exception.class) | ||
| 248 | public void assignUserRole(Long userId, Set<Long> roleIds) { | 318 | public void assignUserRole(Long userId, Set<Long> roleIds) { |
| 249 | // 获得角色拥有角色编号 | 319 | // 获得角色拥有角色编号 |
| 250 | - Set<Long> dbRoleIds = CollectionUtils.convertSet(userRoleMapper.selectListByUserId(userId), | 320 | + Set<Long> dbRoleIds = convertSet(userRoleMapper.selectListByUserId(userId), |
| 251 | UserRoleDO::getRoleId); | 321 | UserRoleDO::getRoleId); |
| 252 | // 计算新增和删除的角色编号 | 322 | // 计算新增和删除的角色编号 |
| 253 | Collection<Long> createRoleIds = CollUtil.subtract(roleIds, dbRoleIds); | 323 | Collection<Long> createRoleIds = CollUtil.subtract(roleIds, dbRoleIds); |
| @@ -264,6 +334,15 @@ public class PermissionServiceImpl implements PermissionService { | @@ -264,6 +334,15 @@ public class PermissionServiceImpl implements PermissionService { | ||
| 264 | if (!CollectionUtil.isEmpty(deleteMenuIds)) { | 334 | if (!CollectionUtil.isEmpty(deleteMenuIds)) { |
| 265 | userRoleMapper.deleteListByUserIdAndRoleIdIds(userId, deleteMenuIds); | 335 | userRoleMapper.deleteListByUserIdAndRoleIdIds(userId, deleteMenuIds); |
| 266 | } | 336 | } |
| 337 | + // 发送刷新消息. 注意,需要事务提交后,在进行发送刷新消息。不然 db 还未提交,结果缓存先刷新了 | ||
| 338 | + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { | ||
| 339 | + | ||
| 340 | + @Override | ||
| 341 | + public void afterCommit() { | ||
| 342 | + permissionProducer.sendUserRoleRefreshMessage(); | ||
| 343 | + } | ||
| 344 | + | ||
| 345 | + }); | ||
| 267 | } | 346 | } |
| 268 | 347 | ||
| 269 | @Override | 348 | @Override |
| @@ -284,6 +363,7 @@ public class PermissionServiceImpl implements PermissionService { | @@ -284,6 +363,7 @@ public class PermissionServiceImpl implements PermissionService { | ||
| 284 | @Override | 363 | @Override |
| 285 | public void afterCommit() { | 364 | public void afterCommit() { |
| 286 | permissionProducer.sendRoleMenuRefreshMessage(); | 365 | permissionProducer.sendRoleMenuRefreshMessage(); |
| 366 | + permissionProducer.sendUserRoleRefreshMessage(); | ||
| 287 | } | 367 | } |
| 288 | 368 | ||
| 289 | }); | 369 | }); |
| @@ -305,8 +385,17 @@ public class PermissionServiceImpl implements PermissionService { | @@ -305,8 +385,17 @@ public class PermissionServiceImpl implements PermissionService { | ||
| 305 | } | 385 | } |
| 306 | 386 | ||
| 307 | @Override | 387 | @Override |
| 388 | + @Transactional(rollbackFor = Exception.class) | ||
| 308 | public void processUserDeleted(Long userId) { | 389 | public void processUserDeleted(Long userId) { |
| 309 | userRoleMapper.deleteListByUserId(userId); | 390 | userRoleMapper.deleteListByUserId(userId); |
| 391 | + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { | ||
| 392 | + | ||
| 393 | + @Override | ||
| 394 | + public void afterCommit() { | ||
| 395 | + permissionProducer.sendUserRoleRefreshMessage(); | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + }); | ||
| 310 | } | 399 | } |
| 311 | 400 | ||
| 312 | @Override | 401 | @Override |
| @@ -322,7 +411,7 @@ public class PermissionServiceImpl implements PermissionService { | @@ -322,7 +411,7 @@ public class PermissionServiceImpl implements PermissionService { | ||
| 322 | } | 411 | } |
| 323 | 412 | ||
| 324 | // 获得当前登录的角色。如果为空,说明没有权限 | 413 | // 获得当前登录的角色。如果为空,说明没有权限 |
| 325 | - Set<Long> roleIds = getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus())); | 414 | + Set<Long> roleIds = getUserRoleIdsFromCache(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus())); |
| 326 | if (CollUtil.isEmpty(roleIds)) { | 415 | if (CollUtil.isEmpty(roleIds)) { |
| 327 | return false; | 416 | return false; |
| 328 | } | 417 | } |
| @@ -357,7 +446,7 @@ public class PermissionServiceImpl implements PermissionService { | @@ -357,7 +446,7 @@ public class PermissionServiceImpl implements PermissionService { | ||
| 357 | } | 446 | } |
| 358 | 447 | ||
| 359 | // 获得当前登录的角色。如果为空,说明没有权限 | 448 | // 获得当前登录的角色。如果为空,说明没有权限 |
| 360 | - Set<Long> roleIds = getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus())); | 449 | + Set<Long> roleIds = getUserRoleIdsFromCache(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus())); |
| 361 | if (CollUtil.isEmpty(roleIds)) { | 450 | if (CollUtil.isEmpty(roleIds)) { |
| 362 | return false; | 451 | return false; |
| 363 | } | 452 | } |
| @@ -365,7 +454,7 @@ public class PermissionServiceImpl implements PermissionService { | @@ -365,7 +454,7 @@ public class PermissionServiceImpl implements PermissionService { | ||
| 365 | if (roleService.hasAnySuperAdmin(roleIds)) { | 454 | if (roleService.hasAnySuperAdmin(roleIds)) { |
| 366 | return true; | 455 | return true; |
| 367 | } | 456 | } |
| 368 | - Set<String> userRoles = CollectionUtils.convertSet(roleService.getRolesFromCache(roleIds), | 457 | + Set<String> userRoles = convertSet(roleService.getRolesFromCache(roleIds), |
| 369 | RoleDO::getCode); | 458 | RoleDO::getCode); |
| 370 | return CollUtil.containsAny(userRoles, Sets.newHashSet(roles)); | 459 | return CollUtil.containsAny(userRoles, Sets.newHashSet(roles)); |
| 371 | } | 460 | } |
| @@ -375,7 +464,7 @@ public class PermissionServiceImpl implements PermissionService { | @@ -375,7 +464,7 @@ public class PermissionServiceImpl implements PermissionService { | ||
| 375 | public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) { | 464 | public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) { |
| 376 | DeptDataPermissionRespDTO result = new DeptDataPermissionRespDTO(); | 465 | DeptDataPermissionRespDTO result = new DeptDataPermissionRespDTO(); |
| 377 | // 获得用户的角色 | 466 | // 获得用户的角色 |
| 378 | - Set<Long> roleIds = getUserRoleIds(userId, singleton(CommonStatusEnum.ENABLE.getStatus())); | 467 | + Set<Long> roleIds = getUserRoleIdsFromCache(userId, singleton(CommonStatusEnum.ENABLE.getStatus())); |
| 379 | if (CollUtil.isEmpty(roleIds)) { | 468 | if (CollUtil.isEmpty(roleIds)) { |
| 380 | return result; | 469 | return result; |
| 381 | } | 470 | } |
| @@ -425,10 +514,4 @@ public class PermissionServiceImpl implements PermissionService { | @@ -425,10 +514,4 @@ public class PermissionServiceImpl implements PermissionService { | ||
| 425 | return result; | 514 | return result; |
| 426 | } | 515 | } |
| 427 | 516 | ||
| 428 | - @Override | ||
| 429 | - public Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds) { | ||
| 430 | - return CollectionUtils.convertSet(userRoleMapper.selectListByRoleIds(roleIds), | ||
| 431 | - UserRoleDO::getUserId); | ||
| 432 | - } | ||
| 433 | - | ||
| 434 | } | 517 | } |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java
| 1 | package cn.iocoder.yudao.module.system.service.permission; | 1 | package cn.iocoder.yudao.module.system.service.permission; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.map.MapUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 5 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 6 | +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | ||
| 5 | import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; | 7 | import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; |
| 6 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; | 8 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 7 | import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; | 9 | import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; |
| 10 | +import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; | ||
| 8 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; | 11 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; |
| 9 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO; | 12 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO; |
| 10 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO; | 13 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO; |
| @@ -17,20 +20,24 @@ import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; | @@ -17,20 +20,24 @@ import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; | ||
| 17 | import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer; | 20 | import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer; |
| 18 | import cn.iocoder.yudao.module.system.service.dept.DeptService; | 21 | import cn.iocoder.yudao.module.system.service.dept.DeptService; |
| 19 | import cn.iocoder.yudao.module.system.service.user.AdminUserService; | 22 | import cn.iocoder.yudao.module.system.service.user.AdminUserService; |
| 23 | +import com.google.common.collect.ImmutableMultimap; | ||
| 24 | +import com.google.common.collect.Multimap; | ||
| 20 | import org.junit.jupiter.api.Test; | 25 | import org.junit.jupiter.api.Test; |
| 21 | import org.springframework.boot.test.mock.mockito.MockBean; | 26 | import org.springframework.boot.test.mock.mockito.MockBean; |
| 22 | import org.springframework.context.annotation.Import; | 27 | import org.springframework.context.annotation.Import; |
| 23 | 28 | ||
| 24 | import javax.annotation.Resource; | 29 | import javax.annotation.Resource; |
| 25 | -import java.util.List; | 30 | +import java.util.*; |
| 26 | 31 | ||
| 32 | +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; | ||
| 27 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; | 33 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; |
| 28 | -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; | ||
| 29 | -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | 34 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; |
| 35 | +import static java.util.Arrays.asList; | ||
| 30 | import static java.util.Collections.singleton; | 36 | import static java.util.Collections.singleton; |
| 31 | import static java.util.Collections.singletonList; | 37 | import static java.util.Collections.singletonList; |
| 32 | import static org.junit.jupiter.api.Assertions.*; | 38 | import static org.junit.jupiter.api.Assertions.*; |
| 33 | import static org.mockito.ArgumentMatchers.eq; | 39 | import static org.mockito.ArgumentMatchers.eq; |
| 40 | +import static org.mockito.ArgumentMatchers.same; | ||
| 34 | import static org.mockito.Mockito.verify; | 41 | import static org.mockito.Mockito.verify; |
| 35 | import static org.mockito.Mockito.when; | 42 | import static org.mockito.Mockito.when; |
| 36 | 43 | ||
| @@ -63,6 +70,226 @@ public class PermissionServiceTest extends BaseDbUnitTest { | @@ -63,6 +70,226 @@ public class PermissionServiceTest extends BaseDbUnitTest { | ||
| 63 | private PermissionProducer permissionProducer; | 70 | private PermissionProducer permissionProducer; |
| 64 | 71 | ||
| 65 | @Test | 72 | @Test |
| 73 | + public void testInitRoleMenuLocalCache() { | ||
| 74 | + // mock 数据 | ||
| 75 | + RoleMenuDO roleMenuDO01 = randomPojo(RoleMenuDO.class, o -> o.setRoleId(1L).setMenuId(10L)); | ||
| 76 | + roleMenuMapper.insert(roleMenuDO01); | ||
| 77 | + RoleMenuDO roleMenuDO02 = randomPojo(RoleMenuDO.class, o -> o.setRoleId(1L).setMenuId(20L)); | ||
| 78 | + roleMenuMapper.insert(roleMenuDO02); | ||
| 79 | + | ||
| 80 | + // 调用 | ||
| 81 | + permissionService.initRoleMenuLocalCache(); | ||
| 82 | + // 断言 roleMenuCache 缓存 | ||
| 83 | + assertEquals(1, permissionService.getRoleMenuCache().keySet().size()); | ||
| 84 | + assertEquals(asList(10L, 20L), permissionService.getRoleMenuCache().get(1L)); | ||
| 85 | + // 断言 menuRoleCache 缓存 | ||
| 86 | + assertEquals(2, permissionService.getMenuRoleCache().size()); | ||
| 87 | + assertEquals(singletonList(1L), permissionService.getMenuRoleCache().get(10L)); | ||
| 88 | + assertEquals(singletonList(1L), permissionService.getMenuRoleCache().get(20L)); | ||
| 89 | + // 断言 maxUpdateTime 缓存 | ||
| 90 | + Date maxUpdateTime = permissionService.getRoleMenuMaxUpdateTime(); | ||
| 91 | + assertEquals(ObjectUtils.max(roleMenuDO01.getUpdateTime(), roleMenuDO02.getUpdateTime()), maxUpdateTime); | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + @Test | ||
| 95 | + public void testInitUserRoleLocalCache() { | ||
| 96 | + // mock 数据 | ||
| 97 | + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); | ||
| 98 | + userRoleMapper.insert(userRoleDO01); | ||
| 99 | + UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(20L)); | ||
| 100 | + userRoleMapper.insert(roleMenuDO02); | ||
| 101 | + | ||
| 102 | + // 调用 | ||
| 103 | + permissionService.initUserRoleLocalCache(); | ||
| 104 | + // 断言 roleMenuCache 缓存 | ||
| 105 | + assertEquals(1, permissionService.getUserRoleCache().size()); | ||
| 106 | + assertEquals(asSet(10L, 20L), permissionService.getUserRoleCache().get(1L)); | ||
| 107 | + // 断言 maxUpdateTime 缓存 | ||
| 108 | + Date maxUpdateTime = permissionService.getUserRoleMaxUpdateTime(); | ||
| 109 | + assertEquals(ObjectUtils.max(userRoleDO01.getUpdateTime(), roleMenuDO02.getUpdateTime()), maxUpdateTime); | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + @Test | ||
| 113 | + public void testGetRoleMenuListFromCache_superAdmin() { | ||
| 114 | + // 准备参数 | ||
| 115 | + Collection<Long> roleIds = singletonList(100L); | ||
| 116 | + Collection<Integer> menuTypes = asList(2, 3); | ||
| 117 | + Collection<Integer> menusStatuses = asList(0, 1); | ||
| 118 | + // mock 方法 | ||
| 119 | + List<RoleDO> roleList = singletonList(randomPojo(RoleDO.class, o -> o.setId(100L))); | ||
| 120 | + when(roleService.getRolesFromCache(eq(roleIds))).thenReturn(roleList); | ||
| 121 | + when(roleService.hasAnySuperAdmin(same(roleList))).thenReturn(true); | ||
| 122 | + List<MenuDO> menuList = randomPojoList(MenuDO.class); | ||
| 123 | + when(menuService.getMenuListFromCache(eq(menuTypes), eq(menusStatuses))).thenReturn(menuList); | ||
| 124 | + | ||
| 125 | + // 调用 | ||
| 126 | + List<MenuDO> result = permissionService.getRoleMenuListFromCache(roleIds, menuTypes, menusStatuses); | ||
| 127 | + // 断言 | ||
| 128 | + assertSame(menuList, result); | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + @Test | ||
| 132 | + public void testGetRoleMenuListFromCache_normal() { | ||
| 133 | + // 准备参数 | ||
| 134 | + Collection<Long> roleIds = asSet(100L, 200L); | ||
| 135 | + Collection<Integer> menuTypes = asList(2, 3); | ||
| 136 | + Collection<Integer> menusStatuses = asList(0, 1); | ||
| 137 | + // mock 方法 | ||
| 138 | + Multimap<Long, Long> roleMenuCache = ImmutableMultimap.<Long, Long>builder().put(100L, 1000L) | ||
| 139 | + .put(200L, 2000L).put(200L, 2001L).build(); | ||
| 140 | + permissionService.setRoleMenuCache(roleMenuCache); | ||
| 141 | + List<MenuDO> menuList = randomPojoList(MenuDO.class); | ||
| 142 | + when(menuService.getMenuListFromCache(eq(asList(1000L, 2000L, 2001L)), eq(menuTypes), eq(menusStatuses))).thenReturn(menuList); | ||
| 143 | + | ||
| 144 | + // 调用 | ||
| 145 | + List<MenuDO> result = permissionService.getRoleMenuListFromCache(roleIds, menuTypes, menusStatuses); | ||
| 146 | + // 断言 | ||
| 147 | + assertSame(menuList, result); | ||
| 148 | + } | ||
| 149 | + | ||
| 150 | + @Test | ||
| 151 | + public void testGetUserRoleIdsFromCache() { | ||
| 152 | + // 准备参数 | ||
| 153 | + Long userId = 1L; | ||
| 154 | + Collection<Integer> roleStatuses = singleton(CommonStatusEnum.ENABLE.getStatus()); | ||
| 155 | + // mock 方法 | ||
| 156 | + Map<Long, Set<Long>> userRoleCache = MapUtil.<Long, Set<Long>>builder() | ||
| 157 | + .put(1L, asSet(10L, 20L)).build(); | ||
| 158 | + permissionService.setUserRoleCache(userRoleCache); | ||
| 159 | + RoleDO roleDO01 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); | ||
| 160 | + when(roleService.getRoleFromCache(eq(10L))).thenReturn(roleDO01); | ||
| 161 | + RoleDO roleDO02 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())); | ||
| 162 | + when(roleService.getRoleFromCache(eq(20L))).thenReturn(roleDO02); | ||
| 163 | + | ||
| 164 | + // 调用 | ||
| 165 | + Set<Long> roleIds = permissionService.getUserRoleIdsFromCache(userId, roleStatuses); | ||
| 166 | + // 断言 | ||
| 167 | + assertEquals(asSet(10L), roleIds); | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + @Test | ||
| 171 | + public void testGetRoleMenuIds_superAdmin() { | ||
| 172 | + // 准备参数 | ||
| 173 | + Long roleId = 100L; | ||
| 174 | + // mock 方法 | ||
| 175 | + when(roleService.hasAnySuperAdmin(eq(singleton(100L)))).thenReturn(true); | ||
| 176 | + List<MenuDO> menuList = singletonList(randomPojo(MenuDO.class).setId(1L)); | ||
| 177 | + when(menuService.getMenus()).thenReturn(menuList); | ||
| 178 | + | ||
| 179 | + // 调用 | ||
| 180 | + Set<Long> menuIds = permissionService.getRoleMenuIds(roleId); | ||
| 181 | + // 断言 | ||
| 182 | + assertEquals(singleton(1L), menuIds); | ||
| 183 | + } | ||
| 184 | + | ||
| 185 | + @Test | ||
| 186 | + public void testGetRoleMenuIds_normal() { | ||
| 187 | + // 准备参数 | ||
| 188 | + Long roleId = 100L; | ||
| 189 | + // mock 数据 | ||
| 190 | + RoleMenuDO roleMenu01 = randomPojo(RoleMenuDO.class).setRoleId(100L).setMenuId(1L); | ||
| 191 | + roleMenuMapper.insert(roleMenu01); | ||
| 192 | + RoleMenuDO roleMenu02 = randomPojo(RoleMenuDO.class).setRoleId(100L).setMenuId(2L); | ||
| 193 | + roleMenuMapper.insert(roleMenu02); | ||
| 194 | + | ||
| 195 | + // 调用 | ||
| 196 | + Set<Long> menuIds = permissionService.getRoleMenuIds(roleId); | ||
| 197 | + // 断言 | ||
| 198 | + assertEquals(asSet(1L, 2L), menuIds); | ||
| 199 | + } | ||
| 200 | + | ||
| 201 | + @Test | ||
| 202 | + public void testAssignRoleMenu() { | ||
| 203 | + // 准备参数 | ||
| 204 | + Long roleId = 1L; | ||
| 205 | + Set<Long> menuIds = asSet(200L, 300L); | ||
| 206 | + // mock 数据 | ||
| 207 | + RoleMenuDO roleMenu01 = randomPojo(RoleMenuDO.class).setRoleId(1L).setMenuId(100L); | ||
| 208 | + roleMenuMapper.insert(roleMenu01); | ||
| 209 | + RoleMenuDO roleMenu02 = randomPojo(RoleMenuDO.class).setRoleId(1L).setMenuId(200L); | ||
| 210 | + roleMenuMapper.insert(roleMenu02); | ||
| 211 | + | ||
| 212 | + // 调用 | ||
| 213 | + permissionService.assignRoleMenu(roleId, menuIds); | ||
| 214 | + // 断言 | ||
| 215 | + List<RoleMenuDO> roleMenuList = roleMenuMapper.selectList(); | ||
| 216 | + assertEquals(2, roleMenuList.size()); | ||
| 217 | + assertEquals(1L, roleMenuList.get(0).getRoleId()); | ||
| 218 | + assertEquals(200L, roleMenuList.get(0).getMenuId()); | ||
| 219 | + assertEquals(1L, roleMenuList.get(1).getRoleId()); | ||
| 220 | + assertEquals(300L, roleMenuList.get(1).getMenuId()); | ||
| 221 | + verify(permissionProducer).sendRoleMenuRefreshMessage(); | ||
| 222 | + } | ||
| 223 | + | ||
| 224 | + @Test | ||
| 225 | + public void testAssignUserRole() { | ||
| 226 | + // 准备参数 | ||
| 227 | + Long userId = 1L; | ||
| 228 | + Set<Long> roleIds = asSet(200L, 300L); | ||
| 229 | + // mock 数据 | ||
| 230 | + UserRoleDO userRole01 = randomPojo(UserRoleDO.class).setUserId(1L).setRoleId(100L); | ||
| 231 | + userRoleMapper.insert(userRole01); | ||
| 232 | + UserRoleDO userRole02 = randomPojo(UserRoleDO.class).setUserId(1L).setRoleId(200L); | ||
| 233 | + userRoleMapper.insert(userRole02); | ||
| 234 | + | ||
| 235 | + // 调用 | ||
| 236 | + permissionService.assignUserRole(userId, roleIds); | ||
| 237 | + // 断言 | ||
| 238 | + List<UserRoleDO> userRoleDOList = userRoleMapper.selectList(); | ||
| 239 | + assertEquals(2, userRoleDOList.size()); | ||
| 240 | + assertEquals(1L, userRoleDOList.get(0).getUserId()); | ||
| 241 | + assertEquals(200L, userRoleDOList.get(0).getRoleId()); | ||
| 242 | + assertEquals(1L, userRoleDOList.get(1).getUserId()); | ||
| 243 | + assertEquals(300L, userRoleDOList.get(1).getRoleId()); | ||
| 244 | + verify(permissionProducer).sendUserRoleRefreshMessage(); | ||
| 245 | + } | ||
| 246 | + | ||
| 247 | + @Test | ||
| 248 | + public void testGetUserRoleIdListByUserId() { | ||
| 249 | + // 准备参数 | ||
| 250 | + Long userId = 1L; | ||
| 251 | + // mock 数据 | ||
| 252 | + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); | ||
| 253 | + userRoleMapper.insert(userRoleDO01); | ||
| 254 | + UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(20L)); | ||
| 255 | + userRoleMapper.insert(roleMenuDO02); | ||
| 256 | + | ||
| 257 | + // 调用 | ||
| 258 | + Set<Long> result = permissionService.getUserRoleIdListByUserId(userId); | ||
| 259 | + // 断言 | ||
| 260 | + assertEquals(asSet(10L, 20L), result); | ||
| 261 | + } | ||
| 262 | + | ||
| 263 | + @Test | ||
| 264 | + public void testGetUserRoleIdListByRoleIds() { | ||
| 265 | + // 准备参数 | ||
| 266 | + Collection<Long> roleIds = asSet(10L, 20L); | ||
| 267 | + // mock 数据 | ||
| 268 | + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); | ||
| 269 | + userRoleMapper.insert(userRoleDO01); | ||
| 270 | + UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(2L).setRoleId(20L)); | ||
| 271 | + userRoleMapper.insert(roleMenuDO02); | ||
| 272 | + | ||
| 273 | + // 调用 | ||
| 274 | + Set<Long> result = permissionService.getUserRoleIdListByRoleIds(roleIds); | ||
| 275 | + // 断言 | ||
| 276 | + assertEquals(asSet(1L, 2L), result); | ||
| 277 | + } | ||
| 278 | + | ||
| 279 | + @Test | ||
| 280 | + public void testAssignRoleDataScope() { | ||
| 281 | + // 准备参数 | ||
| 282 | + Long roleId = 1L; | ||
| 283 | + Integer dataScope = 2; | ||
| 284 | + Set<Long> dataScopeDeptIds = asSet(10L, 20L); | ||
| 285 | + | ||
| 286 | + // 调用 | ||
| 287 | + permissionService.assignRoleDataScope(roleId, dataScope, dataScopeDeptIds); | ||
| 288 | + // 断言 | ||
| 289 | + verify(roleService).updateRoleDataScope(eq(roleId), eq(dataScope), eq(dataScopeDeptIds)); | ||
| 290 | + } | ||
| 291 | + | ||
| 292 | + @Test | ||
| 66 | public void testProcessRoleDeleted() { | 293 | public void testProcessRoleDeleted() { |
| 67 | // 准备参数 | 294 | // 准备参数 |
| 68 | Long roleId = randomLongId(); | 295 | Long roleId = randomLongId(); |
| @@ -89,6 +316,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { | @@ -89,6 +316,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { | ||
| 89 | assertPojoEquals(dbUserRoles.get(0), userRoleDO02); | 316 | assertPojoEquals(dbUserRoles.get(0), userRoleDO02); |
| 90 | // 断言调用 | 317 | // 断言调用 |
| 91 | verify(permissionProducer).sendRoleMenuRefreshMessage(); | 318 | verify(permissionProducer).sendRoleMenuRefreshMessage(); |
| 319 | + verify(permissionProducer).sendUserRoleRefreshMessage(); | ||
| 92 | } | 320 | } |
| 93 | 321 | ||
| 94 | @Test | 322 | @Test |
| @@ -127,14 +355,33 @@ public class PermissionServiceTest extends BaseDbUnitTest { | @@ -127,14 +355,33 @@ public class PermissionServiceTest extends BaseDbUnitTest { | ||
| 127 | List<UserRoleDO> dbUserRoles = userRoleMapper.selectList(); | 355 | List<UserRoleDO> dbUserRoles = userRoleMapper.selectList(); |
| 128 | assertEquals(1, dbUserRoles.size()); | 356 | assertEquals(1, dbUserRoles.size()); |
| 129 | assertPojoEquals(dbUserRoles.get(0), userRoleDO02); | 357 | assertPojoEquals(dbUserRoles.get(0), userRoleDO02); |
| 358 | + // 断言调用 | ||
| 359 | + verify(permissionProducer).sendUserRoleRefreshMessage(); | ||
| 130 | } | 360 | } |
| 131 | 361 | ||
| 362 | +// @Test | ||
| 363 | +// public void testHasAnyRoles_superAdmin() { | ||
| 364 | +// // 准备参数 | ||
| 365 | +// String[] roles = new String[]{"yunai", "tudou"}; | ||
| 366 | +// // mock 方法 | ||
| 367 | +// List<RoleDO> roleList = singletonList(randomPojo(RoleDO.class, o -> o.setId(100L))); | ||
| 368 | +// when(roleService.getRolesFromCache(eq(roleIds))).thenReturn(roleList); | ||
| 369 | +// when(roleService.hasAnySuperAdmin(same(roleList))).thenReturn(true); | ||
| 370 | +// List<MenuDO> menuList = randomPojoList(MenuDO.class); | ||
| 371 | +// when(menuService.getMenuListFromCache(eq(menuTypes), eq(menusStatuses))).thenReturn(menuList); | ||
| 372 | +// | ||
| 373 | +// // 调用 | ||
| 374 | +// List<MenuDO> result = permissionService.getRoleMenuListFromCache(roleIds, menuTypes, menusStatuses); | ||
| 375 | +// // 断言 | ||
| 376 | +// assertSame(menuList, result); | ||
| 377 | +// } | ||
| 378 | + | ||
| 132 | @Test | 379 | @Test |
| 133 | public void testGetDeptDataPermission_All() { | 380 | public void testGetDeptDataPermission_All() { |
| 134 | // 准备参数 | 381 | // 准备参数 |
| 135 | Long userId = 1L; | 382 | Long userId = 1L; |
| 136 | // mock 用户的角色编号 | 383 | // mock 用户的角色编号 |
| 137 | - userRoleMapper.insert(new UserRoleDO().setUserId(userId).setRoleId(2L)); | 384 | + permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(2L)).build()); |
| 138 | // mock 获得用户的角色 | 385 | // mock 获得用户的角色 |
| 139 | RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.ALL.getScope()) | 386 | RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.ALL.getScope()) |
| 140 | .setStatus(CommonStatusEnum.ENABLE.getStatus())); | 387 | .setStatus(CommonStatusEnum.ENABLE.getStatus())); |
| @@ -154,7 +401,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { | @@ -154,7 +401,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { | ||
| 154 | // 准备参数 | 401 | // 准备参数 |
| 155 | Long userId = 1L; | 402 | Long userId = 1L; |
| 156 | // mock 用户的角色编号 | 403 | // mock 用户的角色编号 |
| 157 | - userRoleMapper.insert(new UserRoleDO().setUserId(userId).setRoleId(2L)); | 404 | + permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(2L)).build()); |
| 158 | // mock 获得用户的角色 | 405 | // mock 获得用户的角色 |
| 159 | RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_CUSTOM.getScope()) | 406 | RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_CUSTOM.getScope()) |
| 160 | .setStatus(CommonStatusEnum.ENABLE.getStatus())); | 407 | .setStatus(CommonStatusEnum.ENABLE.getStatus())); |
| @@ -164,7 +411,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { | @@ -164,7 +411,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { | ||
| 164 | when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用 | 411 | when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用 |
| 165 | 412 | ||
| 166 | // 调用 | 413 | // 调用 |
| 167 | - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(1L); | 414 | + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); |
| 168 | // 断言 | 415 | // 断言 |
| 169 | assertFalse(result.getAll()); | 416 | assertFalse(result.getAll()); |
| 170 | assertFalse(result.getSelf()); | 417 | assertFalse(result.getSelf()); |
| @@ -178,7 +425,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { | @@ -178,7 +425,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { | ||
| 178 | // 准备参数 | 425 | // 准备参数 |
| 179 | Long userId = 1L; | 426 | Long userId = 1L; |
| 180 | // mock 用户的角色编号 | 427 | // mock 用户的角色编号 |
| 181 | - userRoleMapper.insert(new UserRoleDO().setUserId(userId).setRoleId(2L)); | 428 | + permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(2L)).build()); |
| 182 | // mock 获得用户的角色 | 429 | // mock 获得用户的角色 |
| 183 | RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_ONLY.getScope()) | 430 | RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_ONLY.getScope()) |
| 184 | .setStatus(CommonStatusEnum.ENABLE.getStatus())); | 431 | .setStatus(CommonStatusEnum.ENABLE.getStatus())); |
| @@ -188,7 +435,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { | @@ -188,7 +435,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { | ||
| 188 | when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用 | 435 | when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用 |
| 189 | 436 | ||
| 190 | // 调用 | 437 | // 调用 |
| 191 | - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(1L); | 438 | + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); |
| 192 | // 断言 | 439 | // 断言 |
| 193 | assertFalse(result.getAll()); | 440 | assertFalse(result.getAll()); |
| 194 | assertFalse(result.getSelf()); | 441 | assertFalse(result.getSelf()); |
| @@ -201,7 +448,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { | @@ -201,7 +448,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { | ||
| 201 | // 准备参数 | 448 | // 准备参数 |
| 202 | Long userId = 1L; | 449 | Long userId = 1L; |
| 203 | // mock 用户的角色编号 | 450 | // mock 用户的角色编号 |
| 204 | - userRoleMapper.insert(new UserRoleDO().setUserId(userId).setRoleId(2L)); | 451 | + permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(2L)).build()); |
| 205 | // mock 获得用户的角色 | 452 | // mock 获得用户的角色 |
| 206 | RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_AND_CHILD.getScope()) | 453 | RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_AND_CHILD.getScope()) |
| 207 | .setStatus(CommonStatusEnum.ENABLE.getStatus())); | 454 | .setStatus(CommonStatusEnum.ENABLE.getStatus())); |
| @@ -229,7 +476,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { | @@ -229,7 +476,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { | ||
| 229 | // 准备参数 | 476 | // 准备参数 |
| 230 | Long userId = 1L; | 477 | Long userId = 1L; |
| 231 | // mock 用户的角色编号 | 478 | // mock 用户的角色编号 |
| 232 | - userRoleMapper.insert(new UserRoleDO().setUserId(userId).setRoleId(2L)); | 479 | + permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(2L)).build()); |
| 233 | // mock 获得用户的角色 | 480 | // mock 获得用户的角色 |
| 234 | RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.SELF.getScope()) | 481 | RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.SELF.getScope()) |
| 235 | .setStatus(CommonStatusEnum.ENABLE.getStatus())); | 482 | .setStatus(CommonStatusEnum.ENABLE.getStatus())); |