生成模块手工落地实战
这篇教程接在生成第一个模块之后,专门解决新手最容易卡住的一步:生成器已经成功,generated-output/ 里也有后端、前端、权限 SQL,但后台菜单还看不到,新页面也还不能访问。
核心原则很简单:Community 版生成器是先审查、再合并。Apply 只写入 staging 模块包。你需要选择 Maven 模块,把权限 seed 改成 Flyway 迁移,复制 Vue 文件,增加静态 route,再核对 RBAC 与菜单树。
你要接入什么
Section titled “你要接入什么”以教程表 biz_todo_item 为例,预览 / 应用之前,建议把生成配置定成:
- Strip prefix:
biz_,让biz_todo_item变成 Java 类TodoItem。 - Module name:
todo,用于前端 feature 目录和 RBAC 前缀。 - Feature name:
todoItem,用于todo:todoItem:list这类权限码。 - Package name:
com.stackrivet.demo.todo,第一次练习可以落进现有stackrivet-demoMaven 模块。
Apply 后,默认 staging 目录类似这样:
generated-output/ src/main/java/com/stackrivet/demo/todo/... src/test/java/com/stackrivet/demo/todo/... frontend/src/api/todo-item.api.ts frontend/src/features/todo/TodoItemList.vue frontend/src/features/todo/TodoItemFormDrawer.vue db/migration/todo__permissions.sql module.manifest.json docs/ai/modules/todo.mdtodo-item.api.ts 调用的 REST 集合路径是 /todo-items。权限 SQL 里的页面路径默认是 /todo-item。这个单复数差异是刻意的:API collection 用复数,后台页面 route 用页面 slug。
1. 先选 Maven 模块
Section titled “1. 先选 Maven 模块”不要因为 stackrivet-app、stackrivet-common、stackrivet-security 看起来很核心,就把业务代码复制进去。stackrivet-app 是 Boot 入口,common 是共享基础设施,security 是认证与 RBAC 基础设施,都不是普通业务模块的落点。
按下面这张表选:
| 选择 | 适用场景 | 需要改哪些 POM |
|---|---|---|
| 现有业务模块 | 新资源属于已有业务边界。 | 通常不用改;确认该模块已是 stackrivet-app 依赖。 |
stackrivet-demo | 学习、演示、示例模块。 | 本教程路径不用额外改 POM;root reactor 和 stackrivet-app 已包含它。 |
新建 stackrivet-<domain> 模块 | 真实业务域需要独立依赖边界。 | root reactor、BOM、stackrivet-app 依赖都要加。 |
第一次练习建议用 stackrivet-demo。它已经有生成 CRUD 需要的依赖:stackrivet-common、MyBatis-Plus、Spring Web、Spring Security core 和 OpenAPI annotations。
如果要做真实业务模块,比如 stackrivet-todo,可以从 stackrivet-demo/pom.xml 复制一份,再改三个地方:
<modules> ... <module>stackrivet-todo</module> <module>stackrivet-app</module></modules><dependency> <groupId>com.stackrivet</groupId> <artifactId>stackrivet-todo</artifactId> <version>${stackrivet.version}</version></dependency><dependency> <groupId>com.stackrivet</groupId> <artifactId>stackrivet-todo</artifactId></dependency>root reactor 负责把模块纳入构建;BOM 负责给模块依赖托管版本;stackrivet-app 依赖负责把模块的 classes 和 resources 放到运行时 classpath,让 Spring、MyBatis 和 Flyway 看得到它。
2. 复制后端文件
Section titled “2. 复制后端文件”如果用 stackrivet-demo 跑第一次练习,在后端仓库根目录执行:
cd stackrivet-server
rsync -av generated-output/src/main/java/ stackrivet-demo/src/main/java/rsync -av generated-output/src/test/java/ stackrivet-demo/src/test/java/然后检查包路径:
find stackrivet-demo/src/main/java/com/stackrivet/demo/todo -type f | sortfind stackrivet-demo/src/test/java/com/stackrivet/demo/todo -type f | sort你应该能看到 TodoItemEntity、TodoItemMapper、TodoItemService、TodoItemServiceImpl、TodoItemController、DTO、VO 和一个 service test。生成的 Controller 已带 @PreAuthorize,权限码是 todo:todoItem:{list,create,update,delete}。
先跑窄范围后端检查:
mvn -pl stackrivet-demo -am test如果你新建了模块,把 stackrivet-demo 换成自己的 artifact:
mvn -pl stackrivet-todo -am test3. 把权限 seed 改成 Flyway 版本
Section titled “3. 把权限 seed 改成 Flyway 版本”生成出来的是 seed,不是 Flyway 版本:
generated-output/db/migration/todo__permissions.sql先看所有已使用版本:
find stackrivet-app/src/main/resources/db/migration -name 'V*__*.sql' | sort本仓库的应用迁移树在 vendor 目录里已有 V1__baseline.sql 和 V2__dashboard_count_indexes.sql。本教程继续用下一个整数版本:
cp generated-output/db/migration/todo__permissions.sql \ stackrivet-app/src/main/resources/db/migration/common/V3__seed_todo_permissions.sqlSQL 不依赖特定数据库方言时,放 common/。生成器产出的权限 seed 可同时用于 MySQL 和 PostgreSQL。你自己写的 SQL 如果用到了某个数据库专属语法,就分别放到 mysql/ 与 postgresql/,并保持两边业务含义一致。
启动前重点检查这些字段:
| 字段 | 检查点 |
|---|---|
id | MGEN_TODO 不能和已有 sr_sys_menu.id 冲突。 |
path | 默认是 /todo-item,必须和 Vue route 对齐。 |
component | 默认是 features/todo/TodoItemList,应和复制后的 Vue 文件一致。 |
permission | todo:todoItem:list 必须和 route meta、Controller @PreAuthorize 一致。 |
visible / status | 页面菜单行应为 TRUE 和 active;按钮权限行隐藏但用于授权。 |
不要修改已经在共享数据库执行过的 Flyway 文件。后续要改菜单 ID、路径或权限时,新增一个迁移版本。
4. 复制前端文件
Section titled “4. 复制前端文件”在管理端仓库根目录执行:
cd stackrivet-admin-ui
rsync -av ../stackrivet-server/generated-output/frontend/src/api/ src/api/rsync -av ../stackrivet-server/generated-output/frontend/src/features/ src/features/你应该得到:
src/api/todo-item.api.tssrc/features/todo/TodoItemList.vuesrc/features/todo/TodoItemFormDrawer.vue打开 TodoItemList.vue,如果数据库字段注释是英文,把组件里的本地 zh-CN 文案改成中文。生成组件把模块标题和字段标签放在组件本地 i18n 里,所以不改全局 locale 也能先跑起来。
5. 增加 Vue route
Section titled “5. 增加 Vue route”打开 src/router/index.ts,在 "/" 主布局的 children 里加:
{ path: "todo-item", name: "TodoItem", component: () => import("@/features/todo/TodoItemList.vue"), meta: { title: "Todo items", permission: "todo:todoItem:list", icon: "list" },},这三处必须一致:
| 位置 | 值 |
|---|---|
sr_sys_menu.path | /todo-item |
Vue 子路由 path | todo-item |
Route meta.permission | todo:todoItem:list |
后台侧栏来自 /api/v1/me 返回的菜单树,但前端还会过滤掉无法解析到真实 route 的菜单项。因此 SQL 有菜单并不等于侧栏马上可见:route 不存在时,它会被侧栏过滤掉。
跑前端检查:
pnpm typecheckpnpm lint6. 启动验证
Section titled “6. 启动验证”启动后端,让 Flyway 执行 V3__seed_todo_permissions.sql:
cd stackrivet-servermvn -pl stackrivet-app -am -DskipTests packagemvn -pl stackrivet-app spring-boot:run启动管理端:
cd stackrivet-admin-uipnpm dev用拥有 seeded super_admin 角色的用户登录,然后访问:
http://127.0.0.1:5173/todo-item再检查 API 与授权:
curl -H "Authorization: Bearer $TOKEN" \ http://127.0.0.1:8080/api/v1/todo-items
curl -H "Authorization: Bearer $TOKEN" \ http://127.0.0.1:8080/api/v1/me | jq '.permissions'你应该能看到 todo:todoItem:list、todo:todoItem:create、todo:todoItem:update、todo:todoItem:delete。
7. 菜单不可见怎么排查
Section titled “7. 菜单不可见怎么排查”按顺序查,别靠猜:
| 现象 | 检查 | 修复 |
|---|---|---|
直接打开 /todo-item 是 404 | route 缺失或 path 写错。 | 增加子路由,重载 Vite。 |
直接打开 /todo-item 是 403 | route 存在,但权限缺失。 | 给角色授予 todo:todoItem:list。 |
| API 返回 403 | Controller 权限没有授予。 | 授予对应按钮/API 权限行。 |
| API 能通,但侧栏没有 | /me 菜单树缺行,或被 route 过滤。 | 查角色授权、visible、status 和 route path。 |
| SQL 已存在但没人看到 | Flyway 没跑到当前数据库。 | 查当前 datasource 和 Flyway history 表。 |
| 只在开发环境出现 | 菜单挂到了示例分组。 | 移到正式业务分组,或保持顶层菜单。 |
数据库检查:
SELECT id, parent_id, type, title, path, component, permission, visible, statusFROM sr_sys_menuWHERE id LIKE 'MGEN_TODO%' OR permission LIKE 'todo:%' OR path = '/todo-item';
SELECT role_id, menu_idFROM sr_sys_role_menuWHERE menu_id LIKE 'MGEN_TODO%';前端检查:
rg -n "TodoItem|todo-item|todo:todoItem" src/router src/features src/api认证检查:
curl -H "Authorization: Bearer $TOKEN" \ http://127.0.0.1:8080/api/v1/me \ | jq '{permissions, menus}'改完用户角色授权后,退出并重新登录。管理端只把 token 放进 localStorage;用户信息、权限集合、菜单树都会从 /me 重新拉取。
8. 新手常见错误
Section titled “8. 新手常见错误”| 错误 | 为什么会坏 |
|---|---|
把后端文件复制进 stackrivet-app | app 是运行时装配模块,不是业务边界。 |
只加 root <module>,没加 app dependency | Maven 会构建它,但 Spring Boot 运行时不会加载它。 |
| 加了 app dependency,没加 BOM | 依赖可能缺版本,构建失败。 |
权限 SQL 还叫 todo__permissions.sql | Flyway 不会把它当作 V...__...sql 迁移执行。 |
改了 sr_sys_menu.path,没改 Vue route | 侧栏会因为 route 不存在而隐藏菜单。 |
改了 route meta.permission,没改 SQL/Controller 权限 | 页面导航和 API 授权不再一致。 |
第二个模块继续复用 MGEN_TODO | sr_sys_menu.id 冲突,或角色授权指向错误菜单。 |
最终检查清单
Section titled “最终检查清单”- 后端文件已经进入选定 Maven 模块。
- 如新建 Maven 模块,root reactor、BOM、
stackrivet-app依赖都已更新。 - 权限 SQL 已改成下一个 Flyway 版本,并放入
common/、mysql/或postgresql/。 - 前端 API 与 feature 文件已经复制进
stackrivet-admin-ui/src。 src/router/index.ts中 route 的 path 与 permission 对齐sr_sys_menu。mvn -pl <module> -am test、pnpm typecheck、pnpm lint通过。/api/v1/me返回预期权限和菜单行。