Commit 7ad10679 by Lizh

docs: 添加 /api/v2 全量迁移设计文档

Co-Authored-By: Claude <noreply@anthropic.com>
parent 19bcc9c2
# /api/v2 全量迁移设计文档
> **编制日期**:2026-07-13
> **来源项目**:`custom-back`(Spring Boot 2.5.15 / Java 8 / RuoYi)
> **目标项目**:`custom-server`(Spring Boot 4.0.5 / Java 17 / DDD)
> **迁移范围**:全部 64 个 `/api/v2` 端点
---
## 一、总体方案
### 执行顺序
```
Step 0 → Step 1 → Step 2 → Step 3 → Step 4
目录 P0 P1 P2 P3
重构 登录鉴权 RBAC Compose 仓库+国家
```
### 关键决策
| 决策 | 结论 |
|------|------|
| API 前缀 | `/api/v2/*`(与 custom-back 一致,前端无需改动) |
| 目录结构 | 迁移前先重构:controller/appService/domainService 按业务域分包 |
| 不迁移的功能 | 验证码、注册、监控、字典、配置、定时任务(不在 64 端点范围) |
| 数据权限 `@DataScope` | 暂不实现,后续按需迁移 |
---
## 二、Step 0:目录重构
### 2.1 目标结构
**controller 层**`custom-server-webapp`):
```
webapp/controller/
├── product/
│ ├── CustomProductInfoController.java
│ ├── CustomProductItemController.java
│ ├── ProductTemplateInfoController.java
│ ├── SysBillRuleController.java
│ └── LogCustomProductController.java
├── system/ ← 迁移时新增
├── warehouse/ ← 迁移时新增
└── HealthController.java (保留顶层)
```
**app/service 层**`custom-server-app`):
```
app/service/
├── product/
│ ├── CustomProductInfoService.java
│ ├── CustomProductItemService.java
│ ├── ProductTemplateInfoService.java
│ ├── SysBillRuleService.java
│ ├── LogCustomProductService.java
│ ├── DiyUserService.java
│ └── impl/
├── system/ ← 迁移时新增
├── warehouse/ ← 迁移时新增
└── PermissionService.java (保留顶层)
```
**domain/service 层**`custom-server-domain`):
```
domain/service/
├── product/ (13 组:商品相关的 DomainService)
├── system/ (8 组:SysUser/SysRole/SysMenu/SysUserRole/SysRoleMenu/SysRoleDept/SysUserOld/SysBillRule)
├── diy/ (3 组:DbDiy/DbDiyXiaoguotu/DbDiyUser)
├── warehouse/ (2 组:CustomWarehouseInfo + CustomProductWarehouseRel)
└── misc/ (其余零散:CraftCenter/LogCustomProduct/LogProductTemplate/ProductFactoryRel)
```
**不调整的模块**
| 模块 | 原因 |
|------|------|
| `domain/dal/entity` | 33 个 Entity,与表一一对应,平铺更易查找 |
| `domain/dal/mapper` | 与 Entity 对应,平铺即可 |
| `domain/resources/mapper` | Mapper XML,平铺即可 |
| `custom-server-core` | 公共层,与业务域无关 |
| `custom-server-integrate` | 已有子包划分 |
| `custom-server-starter/config` | 全局 @Configuration,不按域拆分 |
### 2.2 改动量
| 动作 | 文件数 |
|------|--------|
| controller 移动 | 5 |
| app service 移动 | 6 组(12 文件) |
| domain service 移动 | 33 组(66 文件) |
| import 路径修正 | ~100 处 |
| **总计** | **~83 文件移动** |
---
## 三、Step 1:P0 登录鉴权(4 端点)
### 3.1 端点清单
| 方法 | URL | 说明 |
|------|-----|------|
| POST | `/api/v2/login` | 用户名密码登录,返回 JWT token |
| GET | `/api/v2/getInfo` | 获取当前用户信息 + 角色 + 权限 |
| GET | `/api/v2/getRouters` | 根据用户权限返回前端路由菜单 |
| POST | `/api/v2/logout` | 退出登录 |
### 3.2 新增/修改文件
| 文件 | 层 | 动作 |
|------|-----|------|
| `core/.../security/TokenHandle.java` | core | 修改:新增 `createToken(LoginUser)` |
| `starter/.../config/SecurityConfig.java` | starter | 新增:`PasswordEncoder` Bean |
| `app/service/system/SysLoginService.java` | app | 新增:登录/登出/用户信息逻辑 |
| `app/service/system/impl/SysLoginServiceImpl.java` | app | 新增 |
| `webapp/controller/system/SysLoginController.java` | webapp | 新增 |
### 3.3 登录流程
```
POST /api/v2/login { username, password }
→ SysLoginService.login()
→ SysUserDomainService.getOne(Wrappers.lambdaQuery(SysUserEntity.class).eq(SysUserEntity::getUserName, username))
→ PasswordEncoder.matches(password, user.password)
→ SysMenuDomainService.selectMenuPermsByUserId(userId) // 查权限
→ SysRoleDomainService 查用户角色 // 已有
→ TokenHandle.createToken(loginUser) // 新增:JWT 生成
→ Redis 存储 login_tokens:{uuid} // custom-back 兼容
→ 返回 { "token": "..." }
```
### 3.4 Token 生成策略
custom-server 使用 **JJWT 0.12.x 标准格式** 生成新 token:
```
JWT Claims:
- id: userId
- account: username
- deptId: deptId
- permissions: ["system:user:list", ...]
- exp: 过期时间
签名: HS512,密钥 = token.secret("custom")
```
**兼容性**`TokenCompatibilityParser` 已支持解析 custom-back 旧格式 token(从 Redis 或 JWT claims 读取),无需修改。
### 3.5 RouterVO 路由构建
`SysLoginService.getRouters()``sys_menu` 表查询菜单,递归构建 `RouterVO` 树:
```
RouterVO:
- name: String // 路由名称
- path: String // 路由路径
- component: String // 前端组件
- meta: MetaVO // { title, icon, isCache, isFrame }
- children: List<RouterVO>
构建规则:
- 过滤 menuType == 'F'(按钮),不显示在路由中
- isFrame == 1 → 外链,path 为完整 URL
- 按 parentId 递归构建父子树
- 按 orderNum 排序
```
### 3.6 不迁移的部分
- `captchaImage`(验证码)— 前端未使用
- `register`(注册)— 前端未使用
- Spring Security 过滤器链 — custom-server 已有 `SecurityInterceptor` 体系
- `@Anonymous` 注解 — 用 `server.needAuthentication` 配置控制
---
## 四、Step 2:P1 RBAC(46 端点)
### 4.1 已有基础
| 层 | 已有(直接复用) |
|----|------------------|
| Entity | `SysUserEntity`, `SysRoleEntity`, `SysMenuEntity`, `SysUserRoleEntity`, `SysRoleMenuEntity`, `SysRoleDeptEntity` |
| Mapper + XML | 对应 6 个 Mapper |
| DomainService | `SysUserDomainService`, `SysRoleDomainService`, `SysMenuDomainService`, `SysUserRoleDomainService`, `SysRoleMenuDomainService`, `SysRoleDeptDomainService` |
### 4.2 需要新建
#### 全栈新建(Entity → Mapper → DomainService → AppService → Controller)
| 模块 | Entity | 端点数 |
|------|--------|--------|
| 部门管理 | `SysDeptEntity` (`sys_dept`) | 6 |
| 岗位管理 | `SysPostEntity` (`sys_post`) | 5 |
| 用户-岗位关联 | `SysUserPostEntity` (`sys_user_post`) | — |
> `SysUserPostEntity` 用于用户-岗位多对多关联,custom-back 中有此表。
#### 补齐上层(AppService + Controller)
| 模块 | 端点数 |
|------|--------|
| 用户管理 | 14 |
| 角色管理 | 13 |
| 菜单管理 | 7 |
### 4.3 各 Controller 端点
#### SysUserController (`/api/v2/system/user`)
```
GET /list → 分页查询(deptId/userName/phonenumber/status 筛选)
GET /{userId} → 查询详情(含角色、岗位)
POST / → 新增(BCrypt 密码 + 角色/岗位关联)
PUT / → 修改(角色/岗位同步更新)
DELETE /{userIds} → 批量删除(逻辑删 delFlag = 1)
PUT /resetPwd → 重置密码
PUT /changeStatus → 状态切换
GET /profile → 个人信息
PUT /profile → 修改个人信息
PUT /profile/updatePwd → 修改密码(验证旧密码)
POST /profile/avatar → 头像上传
GET /authRole/{userId} → 已授权 + 未授权角色
PUT /authRole → 保存授权角色(先删后插)
GET /deptTree → 部门下拉树
```
#### SysRoleController (`/api/v2/system/role`)
```
GET /list → 分页查询
GET /{roleId} → 查询详情
POST / → 新增(含 role_menu 关联)
PUT / → 修改(含 role_menu 更新)
PUT /dataScope → 数据权限(更新 role_dept)
PUT /changeStatus → 状态切换
DELETE /{roleIds} → 批量删除
GET /authUser/allocatedList → 已授权用户分页
GET /authUser/unallocatedList → 未授权用户分页
PUT /authUser/cancel → 取消单个授权
PUT /authUser/cancelAll → 批量取消授权
PUT /authUser/selectAll → 批量授权
GET /deptTree/{roleId} → 角色部门树
```
#### SysMenuController (`/api/v2/system/menu`)
```
GET /list → 菜单树列表
GET /{menuId} → 详情
GET /treeselect → 菜单下拉树
GET /roleMenuTreeselect/{roleId} → 角色菜单树(含 checkedKeys)
POST / → 新增
PUT / → 修改
DELETE /{menuId} → 删除(检测子菜单)
```
#### SysDeptController (`/api/v2/system/dept`)
```
GET /list → 部门树
GET /list/exclude/{deptId} → 排除节点的部门树
GET /{deptId} → 详情
POST / → 新增
PUT / → 修改
DELETE /{deptId} → 删除(检测子部门 + 用户)
```
#### SysPostController (`/api/v2/system/post`)
```
GET /list → 分页查询
GET /{postId} → 详情
POST / → 新增
PUT / → 修改
DELETE /{postIds} → 批量删除
```
### 4.4 文件清单
```
新增 Entity: SysDeptEntity, SysPostEntity, SysUserPostEntity
新增 Mapper: SysDeptMapper, SysPostMapper, SysUserPostMapper + 3 XML
新增 DomainSvc: SysDeptDomainService, SysPostDomainService + 2 Impl
新增 AppSvc: SysUserService, SysRoleService, SysMenuService,
SysDeptService, SysPostService + 5 Impl
新增 VO/DTO: ~10 个
新增 Controller: 5 个
总计:~40 个新文件
```
---
## 五、Step 3:P2 ComposeServer + Log(8 端点)
### 5.1 端点清单
#### SysComposeServerController (`/api/v2/system/composeServer`)
```
POST /list → 分页查询(含 status0Count/status1Count 统计)
POST /add → 新增(校验 title/host 非空)
POST /updateById → 修改
GET /deleteById?id={id} → 删除
GET /updateStatusById?id={id}&status= → 状态切换
GET /getAllServerHost → 全部主机地址
```
#### SysComposeServerLogController (`/api/v2/system/composeServerLog`)
```
POST /list → 分页查询(composeServerId/status 筛选,JOIN host)
POST /deleteByIdList → 批量删除
```
### 5.2 新建内容
```
新增 Entity: SysComposeServerEntity, SysComposeServerLogEntity
新增 Mapper: SysComposeServerMapper, SysComposeServerLogMapper + 2 XML
新增 DomainSvc: 接口 + Impl × 2 = 4
新增 AppSvc: SysComposeServerService + Impl, SysComposeServerLogService + Impl
新增 VO: 按需
新增 Controller: SysComposeServerController, SysComposeServerLogController
总计:~16 个新文件
```
### 5.3 修正 custom-back 中的问题
| 问题 | 修正 |
|------|------|
| `SysComposeServerLogMapper.deleteByIdList` SQL 误删 `compose_server` 表 | 正确删除 `compose_server_log` 表 |
| `selectServerLogList``getServerLogById` 参数命名误导 | 正确命名为 `id` |
| 删除 Server 时未级联删除 Log | 删除 Server 时同步删除关联 Log |
---
## 六、Step 4:P3 CountryCode + Warehouse(6 端点)
### 6.1 CountryCode(2 端点)
```
GET /api/v2/countryCode/map → Map<String, String> (countryCode → nameCn)
GET /api/v2/countryCode/all → List<BaseCountryCodeVO>
```
**数据来源**:对接外部 manage 服务 API + Redis 缓存(与 custom-back 一致),复用 `custom-server-integrate` 模块的 WebClient 模式。
```
Controller → AppService → integrate/SaasAdminService (新增方法) → 外部 API
→ Redis 缓存 1h
```
**新建文件**(~8 个):
```
新增 integrate: SaasAdminService 新增 getCountryCodeAll() 方法
新增 VO: BaseCountryCodeVO
新增 AppSvc: BaseCountryCodeService + Impl
新增 Controller: BaseCountryCodeController
```
### 6.2 Warehouse(5 端点)
```
GET /api/v2/customWarehouse/statusList → 状态枚举
GET /api/v2/customWarehouse/list → 分页查询
POST /api/v2/customWarehouse → 新增
PUT /api/v2/customWarehouse → 修改
DELETE /api/v2/customWarehouse/{ids} → 批量删除
```
**已有基础**:Entity、Mapper、DomainService 均已存在。
**新建文件**(~4 个):
```
新增 AppSvc: CustomWarehouseInfoService + Impl
新增 Controller: CustomWarehouseInfoController
```
> custom-back 中还有 6 个 `/rest/customWarehouse/*` 对外 REST API,不在本次迁移范围。
---
## 七、关键技术对齐
| 差异点 | custom-back | custom-server |
|--------|-------------|---------------|
| 响应格式 | `AjaxResult` + `TableDataInfo` | `R<T>` + `IPage<T>` |
| 分页 | `PageHelper.startPage()` | MyBatis-Plus `Page<T>` |
| 鉴权 | `@PreAuthorize("@ss.hasPermi(...)")` | `@RequiresPermissions("...")` |
| JWT 生成 | JJWT 0.9.1 旧格式 | JJWT 0.12.x 标准格式 |
| JWT 解析 | 仅旧格式 | `TokenCompatibilityParser` 兼容新旧 |
| 密码 | Spring Security BCryptPasswordEncoder | 新增 `PasswordEncoder` Bean |
| 实体映射 | 手动 getter/setter | `BeanMapper` (Jackson SNAKE_CASE) |
| 数据权限 | `@DataScope` AOP + SQL 注入 | 暂不实现 |
| 外部 HTTP | `RestTemplate` | `WebClient`(integrate 模块已有) |
---
## 八、文件统计
| 步骤 | 内容 | 新建文件 | 修改文件 | 移动文件 |
|------|------|----------|----------|----------|
| Step 0 | 目录重构 | 0 | 0 | ~83 |
| Step 1 | P0 登录鉴权 | ~8 | 2 | 0 |
| Step 2 | P1 RBAC | ~40 | 0 | 0 |
| Step 3 | P2 ComposeServer | ~16 | 0 | 0 |
| Step 4 | P3 CountryCode + Warehouse | ~12 | 0 | 0 |
| **合计** | | **~76** | **2** | **~83** |
---
## 九、风险与对策
| 风险 | 对策 |
|------|------|
| 目录重构导致编译错误 | 重构完成后立即 `mvn compile` 验证 |
| JJWT 新格式 token 不被 custom-back 识别 | 两套系统独立运行,不影响;`TokenCompatibilityParser` 已兼容旧格式读取 |
| 密码编码器不兼容 | 新生成的密码用 BCrypt 编码,旧密码(custom-back 也是 BCrypt)直接兼容 |
| 前端 baseURL 指向 | 前端 `requestV2.ts` 的 baseURL 已指向 `/api/v2`,迁移后无变化 |
| 体量较大(64 端点) | 按 Step 0-4 分步执行,每步完成后验证 |
| CountryCode 外部服务不可用 | Redis 缓存 1 小时降级,返回缓存数据 |
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment