diff --git a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/constant/RedisKeyConstants.java b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/constant/RedisKeyConstants.java index 73bd439..62f034f 100644 --- a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/constant/RedisKeyConstants.java +++ b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/constant/RedisKeyConstants.java @@ -26,9 +26,14 @@ public class RedisKeyConstants { private static final String USER_ROLES_KEY_PREFIX = "user:roles:"; /** - * 小哈书全局 ID 生成器 KEY + * 小壹书全局 ID 生成器 KEY */ - public static final String XIAOYI_ID_GENERATOR_KEY = "xiaoyishu_id_generator"; + public static final String XIAOYI_ID_GENERATOR_KEY = "xiaoyishu.id.generator"; + + /** + * 角色权限数据 KEY 前缀 + */ + public static final String ROLE_PERMISSIONS_KEY_PREFIX = "role:permissions:"; /** * 构建验证码 KEY @@ -50,4 +55,14 @@ public class RedisKeyConstants { return USER_ROLES_KEY_PREFIX + phone; } + /** + * 构建角色权限数据 KEY + * + * @param roleId 角色 ID + * @return 角色权限数据 KEY + */ + public static String buildRolePermissionsKey(Long roleId) { + return ROLE_PERMISSIONS_KEY_PREFIX + roleId; + } + } diff --git a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappers/PermissionMapper.java b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappers/PermissionMapper.java index 0e1f095..ff05057 100644 --- a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappers/PermissionMapper.java +++ b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappers/PermissionMapper.java @@ -1,7 +1,9 @@ package top.crushtj.xiaoyishu.auth.domain.mappers; -import top.crushtj.xiaoyishu.auth.domain.entity.PermissionEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import top.crushtj.xiaoyishu.auth.domain.entity.PermissionEntity; + +import java.util.List; /** * @author ayi @@ -12,5 +14,12 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; */ public interface PermissionMapper extends BaseMapper { + /** + * 查询所有已启用的权限列表 + * + * @return 已启用的权限列表 + */ + List selectAppEnabledList(); + } diff --git a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappers/RoleMapper.java b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappers/RoleMapper.java index 1464617..d4da61d 100644 --- a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappers/RoleMapper.java +++ b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappers/RoleMapper.java @@ -1,7 +1,9 @@ package top.crushtj.xiaoyishu.auth.domain.mappers; -import top.crushtj.xiaoyishu.auth.domain.entity.RoleEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import top.crushtj.xiaoyishu.auth.domain.entity.RoleEntity; + +import java.util.List; /** * @author ayi @@ -12,5 +14,12 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; */ public interface RoleMapper extends BaseMapper { + /** + * 查询所有启用的角色列表 + * + * @return 角色列表 + */ + List selectEnabledRoleList(); + } diff --git a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappers/RolePermissionRelMapper.java b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappers/RolePermissionRelMapper.java index 1854be4..52fadd0 100644 --- a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappers/RolePermissionRelMapper.java +++ b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappers/RolePermissionRelMapper.java @@ -1,8 +1,11 @@ package top.crushtj.xiaoyishu.auth.domain.mappers; +import org.apache.ibatis.annotations.Param; import top.crushtj.xiaoyishu.auth.domain.entity.RolePermissionRelEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import java.util.List; + /** * @author ayi * @version V1.0 @@ -12,5 +15,13 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; */ public interface RolePermissionRelMapper extends BaseMapper { + /** + * 根据角色ID查询权限 + * + * @param roleIds 角色ID列表 + * @return 权限列表 + */ + List selectByRoleIds(@Param("roleIds") List roleIds); + } diff --git a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappings/PermissionMapping.xml b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappings/PermissionMapping.xml index e956b80..455e659 100644 --- a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappings/PermissionMapping.xml +++ b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappings/PermissionMapping.xml @@ -16,5 +16,12 @@ + diff --git a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappings/RoleMapping.xml b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappings/RoleMapping.xml index 1ad584f..b74e891 100644 --- a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappings/RoleMapping.xml +++ b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappings/RoleMapping.xml @@ -14,4 +14,10 @@ + diff --git a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappings/RolePermissionRelMapping.xml b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappings/RolePermissionRelMapping.xml index 8ad8a98..b043053 100644 --- a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappings/RolePermissionRelMapping.xml +++ b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/domain/mappings/RolePermissionRelMapping.xml @@ -10,5 +10,16 @@ + diff --git a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/runner/PushRolePermissions2RedisRunner.java b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/runner/PushRolePermissions2RedisRunner.java new file mode 100644 index 0000000..eaab601 --- /dev/null +++ b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/runner/PushRolePermissions2RedisRunner.java @@ -0,0 +1,123 @@ +package top.crushtj.xiaoyishu.auth.runner; + +import cn.hutool.core.collection.CollUtil; +import com.google.common.collect.Lists; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; +import top.crushtj.framework.common.utils.JsonUtils; +import top.crushtj.xiaoyishu.auth.constant.RedisKeyConstants; +import top.crushtj.xiaoyishu.auth.domain.entity.PermissionEntity; +import top.crushtj.xiaoyishu.auth.domain.entity.RoleEntity; +import top.crushtj.xiaoyishu.auth.domain.entity.RolePermissionRelEntity; +import top.crushtj.xiaoyishu.auth.domain.mappers.PermissionMapper; +import top.crushtj.xiaoyishu.auth.domain.mappers.RoleMapper; +import top.crushtj.xiaoyishu.auth.domain.mappers.RolePermissionRelMapper; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * + * @author ayi + * @version V1.0 + * @title PushRolePermissions2RedisRunner + * @date 2026/01/23 16:51 + * @description 推送角色权限到Redis + */ + +@Slf4j +@Component +public class PushRolePermissions2RedisRunner implements ApplicationRunner { + + @Resource + private RedisTemplate redisTemplate; + + @Resource + private RoleMapper roleMapper; + + @Resource + private RolePermissionRelMapper rolePermissionRelMapper; + + @Resource + private PermissionMapper permissionMapper; + + public static final String PUSH_PERMISSION_FLAG = "push.permission.flag"; + + @Override + public void run(ApplicationArguments args) throws Exception { + log.info("==> 开始同步角色权限数据到 Redis 中..."); + + try { + // 是否能够同步数据: 原子操作,只有在键 PUSH_PERMISSION_FLAG 不存在时,才会设置该键的值为 "1",并设置过期时间为 1 天 + boolean canPushed = Boolean.TRUE.equals(redisTemplate.opsForValue() + .setIfAbsent(PUSH_PERMISSION_FLAG, "1", 1, TimeUnit.DAYS)); + // 如果无法同步权限数据 + if (!canPushed) { + log.warn("==> 角色权限数据已经同步至 Redis 中,不再同步..."); + return; + } + // 查询所有已启用角色 + List roleList = roleMapper.selectEnabledRoleList(); + if (CollUtil.isNotEmpty(roleList)) { + // 获取角色ID集合 + List roleIds = roleList.stream() + .map(RoleEntity::getId) + .toList(); + + //查询角色对应的权限 + List rolePermissionList = rolePermissionRelMapper.selectByRoleIds(roleIds); + + // 按角色 ID 分组, 每个角色 ID 对应多个权限 ID + Map> roleIdPermissionIdsMap = rolePermissionList.stream() + .collect(Collectors.groupingBy(RolePermissionRelEntity::getRoleId, + Collectors.mapping(RolePermissionRelEntity::getPermissionId, Collectors.toList()))); + + // 查询所有启用的权限 + List permissionList = permissionMapper.selectAppEnabledList(); + + // 构建权限 ID 和权限 DO 对象的映射关系 + Map permissionIdEntityMap = permissionList.stream() + .collect(Collectors.toMap(PermissionEntity::getId, permissionEntity -> permissionEntity)); + + // 构建角色 ID 和权限 DO 列表的映射关系 + Map> roleIdPermissionMap = new HashMap<>(); + roleList.forEach(role -> { + Long roleId = role.getId(); + //获取角色对应的权限id列表 + List permissionIds = roleIdPermissionIdsMap.get(roleId); + if (CollUtil.isNotEmpty(permissionIds)) { + List perDOS = Lists.newArrayList(); + permissionIds.forEach(permissionId -> { + // 根据权限 ID 获取具体的权限 DO 对象 + PermissionEntity permissionDO = permissionIdEntityMap.get(permissionId); + if (Objects.nonNull(permissionDO)) { + perDOS.add(permissionDO); + } + }); + roleIdPermissionMap.put(roleId, perDOS); + } + }); + + // 将角色 ID 和权限 DO 列表的映射关系写入 Redis + roleIdPermissionMap.forEach((roleId, permission) -> { + String key = RedisKeyConstants.buildRolePermissionsKey(roleId); + redisTemplate.opsForValue() + .set(key, JsonUtils.toJsonString(permission)); + }); + } + log.info("==> 角色权限数据同步到 Redis 完成..."); + } catch (Exception e) { + log.error("==> 角色权限数据同步到 Redis 失败...", e); + } + + } + +} diff --git a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/cache/CacheLoader.java b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/runner/cache/CacheLoader.java similarity index 73% rename from xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/cache/CacheLoader.java rename to xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/runner/cache/CacheLoader.java index 360f72d..2b2658b 100644 --- a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/cache/CacheLoader.java +++ b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/runner/cache/CacheLoader.java @@ -1,4 +1,4 @@ -package top.crushtj.xiaoyishu.auth.cache; +package top.crushtj.xiaoyishu.auth.runner.cache; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import jakarta.annotation.PostConstruct; @@ -34,16 +34,18 @@ public class CacheLoader { */ @PostConstruct public void loadUserCache() { - log.info("加载用户自增ID缓存开始..."); + log.info("==> 加载用户自增ID缓存开始..."); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.orderByDesc(UserEntity::getXiaoyishuId); queryWrapper.last("limit 1"); UserEntity user = userMapper.selectOne(queryWrapper); - if (user != null){ - redisTemplate.opsForValue().set(XIAOYI_ID_GENERATOR_KEY, Long.valueOf(user.getXiaoyishuId())); - }else { - redisTemplate.opsForValue().set(XIAOYI_ID_GENERATOR_KEY, XIAOYI_ID_INITIAL_VALUE); + if (user != null) { + redisTemplate.opsForValue() + .set(XIAOYI_ID_GENERATOR_KEY, Long.valueOf(user.getXiaoyishuId())); + } else { + redisTemplate.opsForValue() + .set(XIAOYI_ID_GENERATOR_KEY, XIAOYI_ID_INITIAL_VALUE); } - log.info("加载用户自增ID缓存结束..."); + log.info("==> 加载用户自增ID缓存结束..."); } }