最适合机器人的视频基座模型:被中国团队开源了
2026-07-10
2026-07-11 0
从零开始——一个刚初始化完的空白仓库,要让 AI 从零搭出一套完整的 RBAC 权限系统。

前端用 Vue,后端 Java 17 + Spring Boot 3,数据库 MySQL,认证用 SaToken。需求包括:用户登录、用户管理、角色管理、权限分配、操作审计日志。
以前这种活儿我得手动写几天:设计表结构、写实体类、Service 层、Controller 层、单元测试,然后 code review、改 bug。这次我想试试让 Claude 从需求分析到代码生成完整走一遍,顺便验证一下之前文章里讲的规则管理方法,在实际项目里到底好不好用。
接手这种需求,我不会一上来就让 AI 写代码。超过 3 个文件需要改动的任务,先用 /plan 让它规划方案——这是我之前文章里总结的经验,改到一半发现方向不对,整个上下文废了只能重新开始,这种情况我遇到过两次。
我让 Claude 读了项目现有代码结构,然后给它这个需求:
/plan 这是一个AI开发一个rbac系统示例,现在处于刚刚初始化仓库,还没进行任何开发的状态。前端可以使用vue,后端使用java,版本使用17,数据库使用mysql。增加用户登录、用户管理与权限管理功能。RBAC 权限系统,要求:- 支持用户多角色分配- 基于角色的细粒度权限控制- 权限校验用 AOP 拦截,不在每个方法里手写- 角色和权限变更必须记录审计日志- 数据库用 MySQL
它给出的方案对比了三种实现:
我选了第一种——RBAC 是标准方案,SaToken 原生支持角色和权限判断,团队里其他人也好接手。后两种更灵活,但学习成本也高。
确认后,Claude 把方案拆成了任务清单,按依赖关系排序:
1. 设计数据模型(User-Role-Permission 五张关系表)2. 写实体类和 Mapper(MyBatis-Plus)3. 写 Service 层(权限校验、角色分配)4. 写 AOP 拦截器(基于注解的权限校验)5. 写 Controller(用户/角色/权限 CRUD)6. 写审计日志7. 写全局异常处理
这个任务清单就是后面开发过程的"施工图"。
这次没有搞三层规则分层,只用了一个 CLAUDE.md。原因很简单——这个权限模块是一次性开发任务,不是要长期维护的独立子系统。专门为它建一个 L3 文件,后期维护成本大于收益。
CLAUDE.md 里的核心规则:
## 技术栈- Java 17, Spring Boot 3.x- MyBatis-Plus 3.5.x, SaToken 1.38.x- Hutool 5.8.x, Lombok 1.18.x## 代码规范- 使用 @RequirePermission 注解 + AOP 做权限校验- 禁止在 Controller 方法体内写权限判断逻辑- 使用 BusinessException 抛业务异常- 统一用 ApiResponse 包装返回结果## 查询规范- 使用 MyBatis-Plus LambdaQueryWrapper- 禁止手写 SQL 字符串拼接
核心就一条:你不说清楚,AI 就按它的训练数据来,而它的训练数据是全网代码的平均值,不是你团队的规范。
先跑 /init 让 Claude 确认项目结构,然后从任务 1 开始。
RBAC 的标准数据模型是 5 张表:
┌─────────┐┌──────────────┐ ┌─────────┐│t_user │ ────▶│ t_user_role│◀────│ t_role││(用户)││(用户-角色)│ │(角色)│└─────────┘└──────────────┘ └────┬────┘│┌─────────────────┐│t_role_permission││ (角色-权限)│└─────────────────┘│ ┌──────┴─────┐ │t_permission│ │ (权限)│ └────────────┘
Claude 生成的实体类用的是 MyBatis-Plus 注解,不是 JPA——这也是提前在 CLAUDE.md 里说清楚技术栈的好处:
public class UserRole {private Long id;private Long userId;private Long roleId;private LocalDateTime createTime;}
用 MyBatis-Plus 的好处是不需要操心 EAGER/LAZY 这些 JPA 的加载策略——每次查询都是主动调用,N+1 问题靠手动优化查询逻辑来避免,后面会说。
先说 AOP 部分,因为这个是权限系统的核心。
@RequirePermission 注解定义得很简单:
public RequirePermission {/** * 权限标识,格式为 "resource:action" */String value();}
切面实现:
public class PermissionAspect {private final PermissionService permissionService;public Object checkPermission(ProceedingJoinPoint joinPoint,RequirePermission requirePermission) throws Throwable {if (!StpUtil.isLogin()) {throw new PermissionDeniedException("未登录或登录已过期");}String permissionCode = requirePermission.value();long userId = StpUtil.getLoginIdAsLong();boolean hasPermission = permissionService.hasPermission(userId, permissionCode);if (!hasPermission) {log.warn("用户 {} 尝试访问权限 {} 被拒绝", userId, permissionCode);throw new PermissionDeniedException("没有权限执行此操作");}return joinPoint.proceed();}}
用法就是在 Controller 方法上贴注解:
public ApiResponse
这个部分 Claude 生成的质量很高——AOP + 自定义注解是 Spring 生态里的标准模式,训练数据里样本多。而且用了 SaToken 的 StpUtil.isLogin() 做登录检查,说明 AI 读了一下项目里的依赖。
这里是第一个值得说的地方。
AI 生成的 hasPermission 方法:
public boolean hasPermission(Long userId, String permissionCode) {// 获取用户所有角色List
然后是 getUserPermissionCodes 的具体实现:
public List
这段代码其实有 N+1 查询的问题。 对每个角色调用 getPermissionIdsByRoleId,再对每个角色调用 listByIds 批量查权限。用户有 3 个角色就是 6 次数据库查询(3 次查权限 ID + 3 次批量查权限详情)。
不过这个项目是个人演示项目,数据量小,暂时没到必须优化的程度。如果放到真实生产环境,我会让 AI 改成一次 JOIN 查询或者用 IN 子句批量查——这就是我之前文章里说的,AI 不会主动考虑数据量增长后的性能问题。
审计日志这块,AI 最初的方案是用 AOP 切面自动记录。后来改成了在 Controller 里手动调用 auditLogService.logAudit()。
原因是:AOP 切面虽然看起来省事,但很难记录变更前后的具体值。比如"把用户从'普通用户'改成了'管理员'"这种信息,AOP 只能拿到方法名和参数,拿不到变更前的数据。手动调用虽然多写几行,但记录的精度更高。
实际的 AuditLog 实体:
public class AuditLog {private Long id;private Long operatorId;private String operatorName;private String action;private String targetType;private Long targetId;private String detail;private String ipAddress;private LocalDateTime createTime;}
Controller 里调用的方式:
auditLogService.logAudit(StpUtil.getLoginIdAsLong(),StpUtil.getLoginIdAsString(),AuditAction.CREATE_ROLE.name(),"role",role.getId(),"创建角色: " + role.getName(),null);
这篇权限模块的代码,从写完到能跑,中间改了好几个回合。这其实挺正常的——用 AI 写代码,一次需求描述清楚、AI 一次写完、你一次 review 通过,这种情况很少见。
原因也简单:AI 不会主动想边界场景。你让它"做一套 RBAC 权限系统",它会给你一个标准的 RBAC 实现,但标准实现不等于适合你的场景。
这次主要的反复集中在几个问题上:
最开始 AI 生成的代码混用了 JPA 和 MyBatis-Plus 两种 ORM——有些实体用了 @Entity,有些用了 @TableName。原因是在最初的 CLAUDE.md 里我没写清楚技术栈,AI 按自己的训练数据默认选了 JPA(Spring Boot 教程里 JPA 出现频率高)。
后来在 CLAUDE.md 里加了一条"使用 MyBatis-Plus 3.5.x,禁止使用 JPA",之后生成的代码就统一了。
上面说过了,AI 一开始用 AOP 切面自动记录审计日志。看起来省事,但实际效果是记录的信息太粗糙——只能拿到方法名,拿不到变更前后的具体值。
后来改成了 Controller 里手动调用 auditLogService.logAudit(),虽然多写几行,但每条审计日志的 detail 字段都能写清楚具体做了什么操作。
AI 生成的 Controller 里,有的地方抛 RuntimeException,有的地方返回 null。后来在 CLAUDE.md 里加了"使用 BusinessException 抛业务异常",同时写了 GlobalExceptionHandler 统一处理:
public class GlobalExceptionHandler {public ApiResponse
这三个问题回头看,都不是技术难题,都是"初始需求描述不够细"导致的。
所以我现在养成了一个习惯:让 AI 写代码之前,先花 10 分钟把需求写到"不需要追问"的粒度。 不是写大段文档,而是在对话里把关键点说清楚:
/implement 按任务清单实现权限模块,注意以下几点:1. 使用 MyBatis-Plus,禁止使用 JPA2. 权限校验用 @RequirePermission 注解 + AOP 拦截3. 统一用 BusinessException 抛业务异常4. 审计日志在 Controller 里手动调用 logAudit 记录5. 所有返回结果用 ApiResponse 包装
这几条看起来都是废话("用 MyBatis-Plus"、"抛 BusinessException"谁不知道),但你不说 AI 就不会做。AI 不是不懂 MyBatis-Plus,是它不知道你的项目已经选定了技术栈,需要主动遵守。
需求写得越细,改的次数越少,上下文 token 浪费也越少。 这个道理跟带新人其实一样——你交代任务时不说清楚,新人做出来肯定不是你要的,然后反复沟通,双方都累。
这次全流程跑下来,AI 真正帮上忙的是这些环节:
做得好的:
必须人来做:
我的结论是:AI 把标准活干得又快又好,但非标准的坑你得自己趟。趟完把经验写回规则文件,下次 AI 就不会再踩。 这个闭环跑顺了,开发效率确实比以前高。
本文对应的代码仓库开源在 Gitee:gitee.com/tangyuewei/…,包含 RBAC 权限系统的完整实现、CLAUDE.md 规则文件,以及开发过程中的提示词记录。可以直接拉下来跑。
tangyuewei,从后端出发,用 AI 拓展到全栈的工程师。