# 08 Java 菜单树与 Flyway 权限迁移 ## 模块职责 将 Java 权限模型作为后台菜单唯一来源,继续使用 `columns` 和 `user_column_permission`,把现有扁平有效菜单转换为后端维护的树形菜单,并通过 Flyway 把旧 route_path 迁移到新版 History 路由。 本模块不引入按钮级权限,不新增 action 表。 ## 依赖关系 上游:现有数据库 `columns`、`user_column_permission`、`users`;`PermissionMenuService`。 下游:`AdminConsoleController.currentUserMenus`、Vue `fetchAdminMenuTree`、`MenusPage`。 相关文件和符号: - `backend-java/.../permission/service/PermissionMenuService.java:getUserColumnPermissions` - `backend-java/.../permission/controller/PermissionMenuController.java:listMenus/createMenu/updateMenu/deleteMenu/reorderColumns` - `backend-java/.../permission/model/entity/PermissionMenuEntity.java` - `backend-java/.../permission/model/entity/UserColumnPermissionEntity.java` - `backend-java/.../admin/controller/AdminConsoleController.java:currentUserMenus` - `backend-java/src/main/resources/db/V100__admin_menu_frontend_routes.sql`(目标迁移文件) ## 核心接口:原实现 → 目标实现 | 内容 | 原实现 | 目标实现 | |---|---|---| | 当前用户菜单 | `List` 扁平列表 | 树形 `items`,页面节点含 `key/name/route` | | 有效权限展开 | `PermissionMenuService.getUserColumnPermissions` | 保留,作为树输入;不在 Controller 重新实现授权规则 | | 菜单存储 | `columns.column_key` + `route_path` | `column_key` 保持稳定;`route_path` 改为 Vue path | | 用户授权 | `user_column_permission` | 保持不变 | | 菜单迁移 | 运行时 initializer 的默认菜单补齐 | Flyway 正式更新既有 admin route_path | | 权限菜单 CRUD | 旧 API 字段 | API 路径保持;页面使用树/表格适配器 | ## 内部结构\n\n`PermissionMenuService` 负责有效权限集合,`AdminConsoleController` 负责 DTO 树组装,Flyway 负责 route_path 数据迁移,`PermissionMenuController` 负责菜单管理 CRUD。\n\n## 目标树组装规则 1. 先由 `PermissionMenuService` 得到当前用户有效菜单集合。 2. 以 `id` 建立节点索引。 3. 用 `parent_id` 将子节点挂到父节点。 4. 按 `sort_order`、再按稳定 key 排序。 5. 分组节点可以无 route;页面节点带 route。 6. 只返回当前用户有效节点,禁止返回全量菜单后由前端过滤。 ## 类型映射 | 数据库/旧 DTO | 目标菜单 DTO | |---|---| | `column_key` | `key` | | `name` | `name` | | `route_path` | `route` | | `parent_id` | `children` 关系 | | `sort_order` | 后端排序值 | | `menu_type=admin` | 后台菜单域 | ## Flyway 迁移内容 目标迁移按 `column_key` 更新 `route_path`,示例: - `admin_users` → `account/users` - `admin_columns` → `account/menus` - `admin_group_manage` → `account/groups` - `admin_dedupe_total_data` → `asin-center/registry` - `admin_shop_manage` → `shop-center/shops` - `admin_history` → `records/history` - `admin_version` → `records/software-version` 迁移必须: - 可重复执行或由 Flyway 保证版本只执行一次。 - 不删除 `user_column_permission`。 - 不修改既有 `column_key`,避免 Java 业务鉴权常量失效。 - 迁移前后对比每个用户的有效菜单 key 集合。 - 检查 `(menu_type, route_path)` 唯一约束。 ## 迁移/实现注意事项 1. `PermissionMenuSchemaInitializer` 仍可负责缺失基础表/默认数据兜底,但不能取代一次性数据迁移。 2. Controller 不得根据当前请求头、User-Agent 或查询参数返回不同菜单结构。 3. 树构造不能把同一个节点挂到多个父节点;发现脏数据应记录错误并阻止上线。 4. 菜单分组虚拟 route 不能被当作页面路由。 5. 新版前端不再兼容旧 route/hash,但权限 key 保持稳定,这两件事必须区分。 6. 菜单 CRUD 新增页面时必须同时提供稳定 `column_key` 和 Vue `route_path`。