Files
springboot-template/README_USAGE.md
shenjianZ 40c85c3c1f feat: 实现完整的 RBAC 权限管理系统与基础设施增强
在初始认证基础上,新增完整的 RBAC 权限模型(角色、权限、菜单三级管理),
  集成审计日志、接口限流、登录失败锁定、Refresh Token 机制、Redis 分布式缓存与锁、
  RocketMQ 消息队列,并引入 Flyway 数据库版本管理,同时补充项目文档与使用示例
2026-04-10 10:58:22 +08:00

12 KiB
Raw Blame History

Spring Boot 模板项目使用文档

项目概述

这是一个功能完整的 Spring Boot 3.x 项目模板,集成了以下核心功能:

  • 用户认证与授权:基于 JWT + Spring Security
  • RBAC 权限模型:角色-权限-菜单三级权限控制
  • 数据库迁移Flyway 版本化管理
  • Redis 缓存:多种场景化缓存支持
  • RocketMQ 消息队列:异步消息处理
  • 分布式锁:基于 Redis 实现
  • 接口限流:基于 Redis + AOP
  • 审计日志AOP 自动记录操作日志
  • 账户安全:登录失败锁定、密码强度校验

1. 快速开始

1.1 环境要求

  • JDK 17+
  • MySQL 8.0+
  • Redis 6.0+
  • RocketMQ 5.x可选

1.2 数据库初始化

项目使用 Flyway 自动管理数据库迁移,启动时会自动执行以下操作:

  1. 创建用户表
  2. 创建 RBAC 相关表(角色、权限、菜单)
  3. 创建审计日志表
  4. 创建 Refresh Token 表

1.3 配置文件

修改 application-dev.yaml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=Asia/Shanghai
    username: your_username
    password: your_password
  
  data:
    redis:
      host: localhost
      port: 6379
      password: your_redis_password

jwt:
  secret: your-secret-key-at-least-64-characters-long

2. 核心功能使用

2.1 用户认证与授权

注册用户

@Autowired
private UserService userService;

UserDto userDto = new UserDto();
userDto.setUsername("testuser");
userDto.setPassword("Test123!"); // 必须包含大小写字母、数字、特殊字符
userDto.setEmail("test@example.com");

RestBean<LoginResponseVo> result = userService.register(userDto);

用户登录

UserDto loginDto = new UserDto();
loginDto.setUsername("testuser");
loginDto.setPassword("Test123!");

RestBean<LoginResponseVo> result = userService.login(loginDto);
// 返回 accessToken 和 refreshToken

使用 Token 访问接口

curl -H "Authorization: Bearer {accessToken}" \
     http://localhost:8080/api/v1/user/info

Token 刷新

curl -X POST \
     -H "Content-Type: application/json" \
     -d '{"refreshToken": "{refreshToken}"}' \
     http://localhost:8080/api/v1/user/refresh

登出

curl -X POST \
     -H "Authorization: Bearer {accessToken}" \
     http://localhost:8080/api/v1/user/logout

2.2 RBAC 权限控制

创建角色

@Autowired
private SysRoleService roleService;

RoleDto roleDto = new RoleDto();
roleDto.setRoleCode("ROLE_EDITOR");
roleDto.setRoleName("编辑");
roleDto.setDescription("内容编辑角色");
roleDto.setSortOrder(3);
roleDto.setStatus(1);

RoleVo role = roleService.create(roleDto);

为角色分配权限

List<Long> permissionIds = Arrays.asList(1L, 2L, 3L); // 文章创建、编辑、删除
roleService.assignPermissions(roleId, permissionIds);

为用户分配角色

@Autowired
private UserService userService;

UserRoleUpdateDto dto = new UserRoleUpdateDto();
dto.setRoleIds(Set.of(1L, 2L)); // 角色ID列表

userService.updateUserRole(userId, dto);

在 Controller 中使用权限注解

@RestController
@RequestMapping("/api/v1/articles")
public class ArticleController {

    // 只有具有 'article:create' 权限的用户可以访问
    @PreAuthorize("hasAuthority('article:create')")
    @PostMapping
    public RestBean<Void> create(@RequestBody ArticleDto dto) {
        // ...
    }

    // 需要管理员角色或文章管理权限
    @PreAuthorize("hasAnyRole('ROLE_ADMIN') or hasAuthority('article:delete')")
    @DeleteMapping("/{id}")
    public RestBean<Void> delete(@PathVariable Long id) {
        // ...
    }
}

2.3 Redis 缓存使用

基本缓存操作

@Autowired
private RedisCache redisCache;

// 设置缓存30分钟过期
redisCache.set("user:" + userId, userObject, 30, TimeUnit.MINUTES);

// 获取缓存
User user = redisCache.get("user:" + userId, User.class);

// 删除缓存
redisCache.delete("user:" + userId);

计数器(阅读数、点赞数)

// 原子自增
long viewCount = redisCache.increment("article:view:" + articleId, 1);

// 原子自减
long stock = redisCache.decrement("product:stock:" + productId, quantity);

哈希表(对象字段缓存)

// 设置单个字段
redisCache.hSet("user:profile:" + userId, "nickname", "张三");
redisCache.hSet("user:profile:" + userId, "age", 25);

// 获取单个字段
String nickname = (String) redisCache.hGet("user:profile:" + userId, "nickname");

// 获取所有字段
Map<Object, Object> profile = redisCache.hGetAll("user:profile:" + userId);

列表(消息队列)

// 从右侧推入(队列尾部)
redisCache.lRightPush("queue:email", emailObject);

// 从左侧弹出(队列头部)
Object email = redisCache.lLeftPop("queue:email");

集合(去重、标签)

// 添加标签(自动去重)
redisCache.sAdd("article:tags:" + articleId, "Java", "Spring", "Redis");

// 检查标签是否存在
boolean hasTag = redisCache.sIsMember("article:tags:" + articleId, "Java");

// 获取所有标签
Set<Object> tags = redisCache.sMembers("article:tags:" + articleId);

有序集合(排行榜)

// 添加到排行榜
redisCache.zAdd("leaderboard:user:score", userId, score);

// 获取用户排名
Long rank = redisCache.zReverseRank("leaderboard:user:score", userId);

// 获取用户分数
Double score = redisCache.zScore("leaderboard:user:score", userId);

// 增加分数
redisCache.zIncrementScore("leaderboard:user:score", userId, 10.0);

2.4 分布式锁使用

@Autowired
private RedisLock redisLock;

public void processOrder(Long orderId) {
    // 1. 获取锁30秒过期
    String lockValue = redisLock.tryLock("order:" + orderId, 30);
    
    if (lockValue == null) {
        throw new RuntimeException("订单正在处理中");
    }
    
    try {
        // 2. 执行业务逻辑
        // ...
        
    } finally {
        // 3. 释放锁(只有持有者才能释放)
        redisLock.unlock("order:" + orderId, lockValue);
    }
}

2.5 接口限流使用

@RestController
public class LoginController {

    // 限制每 IP 每分钟最多 5 次登录尝试
    @RateLimit(permits = 5, seconds = 60, limitType = RateLimit.LimitType.IP)
    @PostMapping("/login")
    public RestBean<LoginResponseVo> login(@RequestBody UserDto dto) {
        // ...
    }
}

2.6 审计日志使用

@RestController
public class UserController {

    // 自动记录审计日志
    @AuditLog(action = "update", resource = "user", description = "更新用户信息")
    @PutMapping("/{id}")
    @PreAuthorize("hasAuthority('user:update')")
    public RestBean<UserVo> updateUser(@PathVariable Long id, @RequestBody UserDto dto) {
        // 操作会被自动记录到 sys_audit_log 表
    }
}

2.7 事务使用

基本事务

@Service
public class UserService {

    // 所有异常都回滚
    @Transactional(rollbackFor = Exception.class)
    public void createUserWithRole(UserDto userDto, Set<Long> roleIds) {
        // 创建用户
        User user = new User();
        // ...
        userRepository.save(user);

        // 分配角色
        for (Long roleId : roleIds) {
            SysRole role = roleRepository.findById(roleId)
                .orElseThrow(() -> new BusinessException("角色不存在"));
            user.getRoles().add(role);
        }
        userRepository.save(user);
        // 任何异常都会回滚整个事务
    }
}

嵌套事务

// 外层事务
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
    // 业务逻辑
    innerMethod(); // 加入外层事务
}

// 内层事务
@Transactional(propagation = Propagation.REQUIRED)
public void innerMethod() {
    // 加入外层事务
}

独立事务

@Transactional(propagation = Propagation.REQUIRED)
public void mainMethod() {
    // 主事务逻辑
    
    // 独立事务(即使主事务回滚也不影响)
    recordLog();
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void recordLog() {
    // 独立事务
}

2.8 RocketMQ 消息队列使用

发送消息

@Autowired
private UserMessageProducer messageProducer;

// 发送注册消息
messageProducer.sendRegisterMessage(userId, username, email);

// 发送登录消息
messageProducer.sendLoginMessage(userId, username, ipAddress);

消费消息

消息会被 UserMessageConsumer 自动消费,根据消息类型执行不同操作:

@RocketMQMessageListener(
    consumerGroup = "user-consumer-group",
    topic = "user-topic"
)
public class UserMessageConsumer implements RocketMQListener<UserMessage> {
    
    @Override
    public void onMessage(UserMessage message) {
        switch (message.getMessageType()) {
            case "REGISTER":
                // 处理注册消息(发送欢迎邮件等)
                break;
            case "LOGIN":
                // 处理登录消息(记录登录日志)
                break;
            // ...
        }
    }
}

3. 配置说明

3.1 JWT 配置

jwt:
  # JWT 密钥至少64字符
  secret: your-secret-key-at-least-64-characters-long
  # Access Token 过期时间(秒)
  access-token-expiration: 3600  # 1小时
  # Refresh Token 过期时间(秒)
  refresh-token-expiration: 604800  # 7天

3.2 登录安全配置

app:
  login:
    # 最大失败次数
    max-attempts: 5
    # 锁定时长(分钟)
    lock-duration-minutes: 30

3.3 Redis 配置

spring:
  data:
    redis:
      host: localhost
      port: 6379
      password: your-password
      database: 0
      timeout: 5000ms
      lettuce:
        pool:
          max-active: 8
          max-idle: 8
          min-idle: 2

3.4 RocketMQ 配置

rocketmq:
  name-server: localhost:9876
  producer:
    group: user-producer-group
    user-topic: user-topic

4. 常见问题

4.1 如何添加新的权限?

  1. 在数据库中插入权限记录(通过 Flyway 迁移脚本)
  2. 在 Controller 上使用 @PreAuthorize 注解
@PreAuthorize("hasAuthority('new:permission')")
public void someMethod() { }

4.2 如何自定义限流规则?

使用 @RateLimit 注解:

@RateLimit(
    permits = 10,           // 10次
    seconds = 60,           // 每分钟
    limitType = RateLimit.LimitType.USER,  // 按用户限流
    keyPrefix = "custom:"    // 自定义键前缀
)
public void customMethod() { }

4.3 如何实现缓存预热?

在应用启动时加载热点数据:

@Component
public class CacheWarmupRunner implements ApplicationRunner {

    @Autowired
    private RedisCache redisCache;

    @Override
    public void run(ApplicationArguments args) {
        // 预热热点数据
        List<User> hotUsers = userRepository.findHotUsers();
        for (User user : hotUsers) {
            redisCache.set("user:" + user.getId(), user, 1, TimeUnit.HOURS);
        }
    }
}

5. 最佳实践

5.1 密码安全

  • 生产环境必须修改 JWT 密钥
  • 使用强密码策略(已集成 @StrongPassword
  • 定期更换密码

5.2 数据库事务

  • 查询操作使用 @Transactional(readOnly = true)
  • 明确指定 rollbackFor = Exception.class
  • 避免大事务

5.3 Redis 使用

  • 合理设置过期时间,避免内存溢出
  • 使用 Redis 分布式锁防止并发问题
  • 热点数据使用缓存,减少数据库压力

5.4 安全建议

  • 修改 CORS 配置,限制允许的域名
  • 使用 HTTPS
  • 定期审查用户权限
  • 启用审计日志