20260730173012

This commit is contained in:
oneao committed 2026-07-30 17:30:13 +08:00
1 parent 84673b3d3d
commit 4929b78434
25 files changed
+1796 -68

No files matched your search

@@ -0,0 +1,117 @@
---
name: field-name-sync-from-old-db
overview: 创建可复用的字段名同步服务,从旧库 s_columnLib.col_Caption 同步到新库 s_module_field.b_name,按视图名和字段名匹配,首批执行 v_b_othercompany。
todos:
- id: fix-old-db-ssl
content: 修复 g3hd-old.properties:移除 sslProtocol=TLSv1 参数,JDK 21 驱动自动协商 TLSv1.2 即可连通
status: completed
- id: create-sync-service
content: 新建 FieldNameSyncService.java:实现跨库 UPDATE SQL,按 viewName 匹配 s_columnLib,将 col_Caption 写入 s_module_field.b_name,不匹配字段不改动,返回更新行数
status: completed
dependencies:
- fix-old-db-ssl
- id: create-admin-controller
content: 新建 AdminController.java,添加 POST /api/admin/sync-field-names 端点,JWT 认证,viewName 参数白名单校验,调用 FieldNameSyncService 并返回 ApiResponse
status: completed
dependencies:
- create-sync-service
- id: add-sql-migration-ref
content: 新建 023_sync_field_names.sql 参考脚本,记录跨库同步 SQL 作为纯 SQL 手动执行备选方案
status: completed
---
## 用户需求
构建一个可复用的工具,将旧库 `G3HY2025.dbo.s_columnLib` 中存储的字段中文名称(`col_Caption`)同步到新库 `fms.dbo.s_module_field.b_name`。
### 匹配规则
- `s_module.b_viewtable` = `s_columnLib.col_TableName`(模块视图名对应旧库表名)
- `s_module_field.b_field` = `s_columnLib.col_FieldName`(字段名精确匹配)
- 匹配不上的字段,`b_name` 保持不变
### 首批同步目标
视图 `v_b_othercompany`
### 可复用要求
以后还有更多视图需要同步,工具须参数化视图名,方便批量复用。
## 技术方案
### 方案选择:跨库 SQL + 管理端点
**核心决策**:新旧库在同一 SQL Server 实例(`118.89.70.199:1433`),使用**跨数据库 SQL** 直接从新库连接执行 `UPDATE ... FROM G3HY2025.dbo.s_columnLib`,无需单独连接旧库。
```sql
UPDATE sf
SET sf.b_name = LTRIM(RTRIM(sc.col_Caption))
FROM dbo.s_module_field sf
JOIN dbo.s_module m ON m.b_id = sf.b_module_id
JOIN G3HY2025.dbo.s_columnLib sc
ON sc.col_TableName = m.b_viewtable
AND sc.col_FieldName = sf.b_field
WHERE m.b_viewtable = ?
AND sc.col_Caption IS NOT NULL
AND LTRIM(RTRIM(sc.col_Caption)) != '';
```
**为何需要新端点而非复用通用端点**:
- 通用 `saveObjectApi` 只能操作当前 org 数据库的单表 insert/update/delete,无法表达跨库 JOIN 逻辑
- 通用 `loadDataApi` 只能查询当前 org 的表,无法读取旧库 `s_columnLib`
- 此操作为管理类批量数据同步,不在业务 CRUD 范畴内
### 实现架构
```mermaid
flowchart LR
A[前端/管理员] -->|POST /api/admin/sync-field-names| B[AdminController]
B -->|校验 viewName 参数| C[FieldNameSyncService]
C -->|获取新库 Connection| D[OrgRoutingDataSource]
D -->|fms 连接| E[(SQL Server)]
E -->|跨库 JOIN| F[G3HY2025.dbo.s_columnLib]
E -->|UPDATE| G[fms.dbo.s_module_field]
C -->|返回同步数量| B
B -->|ApiResponse| A
```
### 模块划分
| 模块 | 文件 | 职责 |
| --- | --- | --- |
| 配置修复 | `config/dbconfigs/g3hd-old.properties` | 移除 `sslProtocol=TLSv1` |
| 同步服务 | `service/FieldNameSyncService.java` | 执行跨库 UPDATE,校验参数,返回影响行数 |
| 管理控制器 | `controller/AdminController.java` | `POST /api/admin/sync-field-names` 端点,JWT 保护 |
| 参考脚本 | `config/migrations/023_sync_field_names.sql` | 纯 SQL 版本供手动执行 |
### 数据流
1. 前端/管理员发送 `POST /api/admin/sync-field-names`,请求体 `{ "viewName": "v_b_othercompany" }`
2. `AdminController` 校验 `viewName` 为合法标识符(字母/下划线/数字,最长128)
3. `FieldNameSyncService` 通过 `@Resource DataSource` 获取新库连接
4. 执行跨库 PreparedStatement UPDATE
5. 返回 `{ "updatedCount": 42, "message": "v_b_othercompany 同步完成,共更新 42 个字段名称" }`
### 安全措施
- `viewName` 参数:白名单正则 `^[A-Za-z_][A-Za-z0-9_]{0,127},校验后作为 PreparedStatement 参数绑定(非字符串拼接)
- JWT 认证:`AdminController` 路径 `/api/admin/**` 经 `JwtAuthFilter` 保护,仅登录用户可调用
- 失败不影响现有数据:UPDATE 在一条 SQL 内执行,单条匹配失败不阻断其他行
### 执行说明
- **热路径**:单条 UPDATE SQL 跨库 JOIN,性能取决于 `s_module_field` 行数和索引;对单个视图(~50 字段)毫秒级完成
- **日志**:服务层记录同步开始/完成/失败日志,使用 `@Slf4j`,级别 INFO/ERROR
- **事务**:使用 Spring 声明式事务 `@Transactional`,确保整批同步原子提交或回滚
- **向后兼容**:不修改现有 `DataController` 和通用端点,不影响业务数据流
## Agent Extensions
### SubAgent
- **code-explorer**
- 目的:探索旧库连接方式、现有 Service/Controller 模式、参数校验惯例
- 预期结果:确认 `OrgDataSourceManager` 的 API 使用方式和现有异常处理/日志模式