Files
AIclinicalresearch/docs/09-架构实施/旧版系统集成/01-新旧系统集成方案.md
HaHafeng c3f7d54fdf feat(platform): Implement legacy system integration with Wrapper Bridge architecture
Complete integration of the old clinical research platform (www.xunzhengyixue.com)
into the new AI platform via Token injection + iframe embedding:

Backend:
- Add legacy-bridge module (MySQL pool, auth service, routes)
- POST /api/v1/legacy/auth: JWT -> phone lookup -> Token injection into old MySQL
- Auto-create user in old system if not found (matched by phone number)

Frontend:
- LegacySystemPage: iframe container with Bridge URL construction
- ResearchManagement + StatisticalTools entry components
- Module registry updated from external links to iframe embed mode

ECS (token-bridge.html deployed to www.xunzhengyixue.com):
- Wrapper Bridge: sets cookies within same-origin context
- Storage Access API for cross-site dev environments
- CSS injection: hide old system nav/footer, remove padding gaps
- Inner iframe loads target page with full DOM access (same-origin)

Key technical decisions:
- Token injection (direct MySQL write) instead of calling login API
- Wrapper Bridge instead of parent-page cookie setting (cross-origin fix)
- Storage Access API + SameSite=None;Secure for third-party cookie handling
- User isolation guaranteed by phone number matching

Documentation:
- Integration plan v4.0 with full implementation record
- Implementation summary with 6 pitfalls documented
- System status guide updated (ST module now integrated)

Tested: Local E2E verified - auto login, research management, 126 statistical
tools, report generation, download, UI layout all working correctly

Made-with: Cursor
2026-02-27 21:54:38 +08:00

19 KiB
Raw Blame History

新旧系统集成方案

版本: v4.0
创建日期: 2026-02-27
最后更新: 2026-02-27Wrapper Bridge 架构 + Storage Access API + 本地 E2E 验证通过)
维护者: 开发团队
状态: Phase 0-2 全部完成,本地开发环境 E2E 验证通过,待部署生产环境


1. 背景

1.1 两套系统概览

维度 新系统AI临床研究平台 老系统(循证医学平台)
域名 iit.xunzhengyixue.com www.xunzhengyixue.com
API 域名 iit.xunzhengyixue.com/api (SAE) api.xunzhengyixue.com (ECS Nginx 反代)
部署 阿里云 SAEServerless 阿里云 ECS8.154.22.149
技术栈 Node.js + React 19 + PostgreSQL Spring Boot 1.4.1 + Java 8 + MySQL
前端部署 SAE 静态资源 Nginx 直接 serve 静态文件
认证方式 JWTAccess 2h + Refresh 7d 自定义 MD5 TokenMySQL 存储3.5 天有效期)
数据库 PostgreSQL 1514 个 Schema MariaDB/MySQLxzyx_online

1.2 老系统模块

模块 入口地址 集成状态
研究管理 https://www.xunzhengyixue.com/index.html Phase 0 外链已完成 → Phase 2 将改为 iframe 内嵌
统计分析工具 https://www.xunzhengyixue.com/tool.html Phase 0 外链已完成 → Phase 2 将改为 iframe 内嵌
AI 问答 老系统内 已在新系统完全重写AIA 模块),无需集成

1.3 约束条件

  • Java 团队已离职,未正式交接源码
  • 后找到一份源码,经 ECS 侦察确认 与生产环境完全一致
  • 线上系统可通过 ECS SSH 访问MySQL 数据库可完全读写
  • 两系统同属 xunzhengyixue.com 根域Cookie 可共享)

1.4 用户关系

  • 两套系统的用户是 同一批人,由运营人员统一开账号
  • 老系统按用户隔离数据(每个用户有自己的研究项目)
  • 自动登录必须以用户本人身份进行,不能使用公共账号

2. ECS 侦察结果Phase 1 - 已完成)

2026-02-27 通过 SSH 登录 8.154.22.149 实地验证

2.1 部署架构

                    ┌─────────────────────────────────────────┐
                    │          ECS 8.154.22.149                │
                    │                                          │
  www.xunzhengyixue.com ──► Nginx:443                         │
                    │        │                                 │
                    │        ├─ / → 静态文件                    │
                    │        │   /home/work/www/xunzhengyixue/ │
                    │        │                                 │
                    │        └─ /api-proxy/ → rag.xunzhengyixue│
                    │                                          │
  api.xunzhengyixue.com ──► Nginx:443                         │
                    │        └─ / → proxy_pass 127.0.0.1:8899 │
                    │                    │                     │
                    │            Java JAR (Spring Boot)        │
                    │            XZYXServer-0.0.1-SNAPSHOT.jar │
                    │            -Xms800m -Xmx4000m            │
                    │            运行自 2025 年至今              │
                    │                    │                     │
                    │            MariaDB/MySQL :3306            │
                    │            xzyx_online                   │
                    └─────────────────────────────────────────┘

2.2 关键确认事项

项目 侦察结果
源码一致性 生产 common.js 与本地源码 100% 一致
前端静态文件路径 /home/work/www/xunzhengyixue/
要修改的文件 /home/work/www/xunzhengyixue/static/js/common.js
Java 部署方式 直接 JAR 运行(非 DockerPID 66548
API 地址 https://api.xunzhengyixue.comconfig.js 确认)
Cookie 域名 xunzhengyixue.comconfig.js 退出登录逻辑确认)
Cookie 名称 token, nickname, id3 个)
登录检查逻辑 仅检查 $.cookie("nickname") 是否存在
API 认证逻辑 $.cookie("token")Authorization 请求头
X-Frame-Options 未设置 → iframe 嵌入可行
Nginx 改 common.js 无需重启 Java,静态文件改完即生效

2.3 认证机制详解

Token 生成公式MD5("KyKz1.0:" + userId + ":" + timestamp)
Token 存储位置MySQL u_user_token 表
Token 有效期:可配置(生产 5000 分钟 ≈ 3.5 天)
Token 传递方式Cookie → JS 读取 → Authorization 请求头

老系统 AuthInterceptor 验证流程:
  1. 从 Authorization header 取 Token
  2. 查 u_user_token 表是否存在该 Token
  3. 检查是否过期gen_time + timeout
  4. 不涉及密码验证 ← 这是直接写 Token 方案可行的根本原因

2.4 对集成友好的 6 个关键发现

发现 对集成的意义
无 CSRF 保护 可以从新系统直接 POST 调用 API
CORS 全开Access-Control-Allow-Origin: * 新系统前端可直接 fetch 调用老系统 API
无 X-Frame-Options iframe 嵌入完全可行
Token 仅查表验证,不校验密码 直接写 Token 到 DB 即可,绕过密码
同根域名 .xunzhengyixue.com 新系统 iit.* 可设置 Cookie 供 www.* 读取
前端纯静态 + 后端分离 common.js 无需碰 Java 代码或重启服务

3. 最终方案Token 注入 + iframe 嵌入

经过 Phase 0外链验证和 Phase 1ECS 侦察),最终确认采用 方案 B+E 组合

  • 方案 EToken 注入):新系统后端直接写 Token 到老系统 MySQL实现自动登录
  • 方案 Biframe 嵌入):在新系统内用 iframe 加载老系统页面,隐藏老系统导航

3.1 为什么选 Token 注入而非调用登录 API

对比项 调用登录 API方案 C 直接写 Token方案 E
需要知道用户密码
用户改了老系统密码 失败 不受影响
依赖老系统 API 可用 (只依赖 MySQL
可同时创建账号
安全性 密码在网络传输 Token 仅写入 DB

3.2 整体流程

用户在新系统点击"研究管理"或"统计分析工具"
  │
  ▼
新系统前端 → POST /api/legacy/auth携带 JWT
  │
  ▼
新系统后端:
  1. 从 JWT 解出当前用户手机号
  2. 连接老系统 MySQLxzyx_online
  3. SELECT id FROM u_user_info WHERE phone = 手机号
     ├─ 不存在 → INSERT 创建账号(默认密码 MD5
     └─ 存在 → 获取 userId
  4. 生成 Token = MD5("KyKz1.0:" + userId + ":" + Date.now())
  5. INSERT INTO u_user_token (user_id, token, gen_time, user_role)
  6. 返回 { token, nickname, id, userRole }
  │
  ▼
新系统前端:
  7. 构建 Bridge URLtoken/nickname/id/userRole/redirect 作为参数)
  8. iframe src = https://www.xunzhengyixue.com/token-bridge.html?...
  │
  ▼
Bridge 页面www.xunzhengyixue.com 域内执行):
  9. Storage Access API 检查(同站自动授权,跨站需一次性用户点击)
  10. document.cookie = "token=xxx; domain=.xunzhengyixue.com"(同域设置)
  11. 创建内部 iframe 加载目标页面(/index.html 或 /tool.html
  12. 每次内部页面加载后,注入自定义 CSS隐藏导航栏、页脚等
  │
  ▼
老系统页面Bridge 内部 iframe同源
  13. 读取 Cookie nickname → 存在 → 正常渲染
  14. AJAX 请求带 Cookie 中的 token → AuthInterceptor 验证通过
  │
  ▼
用户看到自己的研究项目iframe 内),新系统导航栏保持在顶部

3.3 账号同步策略

场景 处理方式
用户在老系统已有账号 直接注入 Token使用原有账号
用户在老系统无账号 自动创建INSERT u_user_info默认密码 123456 的 MD5
用户改了老系统密码 不影响Token 注入不依赖密码
用户在老系统被删除 自动重新创建

匹配规则:以 手机号phone 作为两套系统的用户关联键。


4. 实施计划

Phase 0 — 外链跳转(已完成)

顶部导航加外链按钮,点击后 window.open() 打开老系统新标签页。

已改动文件:

文件 改动
frontend-v2/src/framework/modules/types.ts 新增 externalUrl?: string 字段
frontend-v2/src/framework/modules/moduleRegistry.ts 新增「研究管理」模块 + 「统计分析工具」加 externalUrl
frontend-v2/src/framework/layout/TopNavigation.tsx 外部模块 window.open + 外链图标 + 跳过权限检查
frontend-v2/src/App.tsx 外部模块跳过内部路由注册

Phase 1 — ECS 侦察(已完成)

SSH 登录 ECS验证部署架构、Nginx 配置、Cookie 机制、源码一致性。

结论: 全部确认,方案可行。详见第 2 节。

Phase 2 — 新系统代码改动清单

后端新增文件:

文件 说明
backend/src/modules/legacy-bridge/legacy-auth.service.ts 连接老系统 MySQL查询用户、写入 token
backend/src/modules/legacy-bridge/routes.ts POST /api/v1/legacy/auth 接口

后端改动文件:

文件 改动
backend/.env 新增 LEGACY_MYSQL_* 连接配置
backend/src/index.ts 注册 /api/v1/legacy 路由

前端新增文件:

文件 说明
frontend-v2/src/modules/legacy/LegacySystemPage.tsx iframe 容器页面(调后端注入 token → 加载 iframe
frontend-v2/src/modules/legacy/ResearchManagement.tsx 研究管理入口(指向 index.html
frontend-v2/src/modules/legacy/StatisticalTools.tsx 统计分析工具入口(指向 tool.html

前端改动文件:

文件 改动
frontend-v2/src/framework/modules/types.ts 新增 legacyUrl 字段
frontend-v2/src/framework/modules/moduleRegistry.ts 研究管理/统计分析模块改为 iframe 内嵌模式
frontend-v2/src/App.tsx legacy 模块路由注册

ECS 改动文件:

文件 改动
/home/work/www/xunzhengyixue/token-bridge.html 新增Wrapper Bridge 页面(设 Cookie + 内嵌 iframe + 注入 CSS
/home/work/www/xunzhengyixue/static/js/common.js iframe 检测:隐藏 header + footerbridge 的 CSS 注入已覆盖,可选回退)
/home/work/www/xunzhengyixue/tool/js/appajax.js iframe 检测:隐藏 menu + footerbridge 的 CSS 注入已覆盖,可选回退)

Phase 2 — Token 注入 + iframe 嵌入(已完成)

步骤 内容 位置 状态
2.1 新系统后端添加 MySQL 连接(老系统数据库) backend/ 已完成
2.2 新增 POST /api/v1/legacy/auth 接口 backend/ 已完成
2.3 前端创建 iframe 容器页面组件 frontend-v2/ 已完成
2.4 修改模块注册:从外链改为内嵌 iframe 页面 frontend-v2/ 已完成
2.5 ECS 部署 Token Bridge 页面 ECS 服务器 已部署
2.6 Token 注入测试 + iframe 显示测试 浏览器 已验证

Phase 2.5 — Wrapper Bridge 架构升级

动机: 原方案由父页面(新系统)设置 Cookie但在 localhost 开发环境无法跨域设置 .xunzhengyixue.com 的 Cookie。改为 Wrapper Bridge 方案后Cookie 在老系统域名内 由 bridge 页面自己设置,同时利用同源 DOM 访问注入自定义 CSS。

架构:

新系统 iframe
  └─ token-bridge.htmlwww.xunzhengyixue.com设 Cookie + 注入 CSS
       └─ inner iframewww.xunzhengyixue.com/index.html 或 /tool.html
            ↑ 同源bridge 可直接操作其 DOM

优势:

  • 本地开发环境localhost可正常测试
  • 所有样式定制集中在 bridge 页面一处
  • 不再需要修改老系统的 common.js / appajax.js(之前的改动可选回退)
  • 未来可随时调整老系统的外观,无需登录 ECS 改文件

token-bridge.html 工作流程:

  1. 检查 Storage Access APIdocument.hasStorageAccess()
    • 同站(生产环境):自动授权 → 直接进入步骤 2
    • 跨站(本地开发)首次:显示"点击授权并继续"按钮 → 用户点击 → requestStorageAccess() → 浏览器授权(缓存 30 天)
    • 跨站(本地开发)后续:已缓存授权 → 直接进入步骤 2
  2. 读取 URL 参数,在 .xunzhengyixue.com 域下设置 CookieSameSite=None; Secure
  3. 创建内部 iframe 加载目标页面
  4. 每次内部 iframe 导航后,注入自定义 CSS
    • 隐藏 #header-navbar#footer-bar(主页面)
    • 隐藏 #menu#footer(工具详情页)
    • 清除 body#page-wrapper 的顶部间距

源码位置: backend/src/modules/legacy-bridge/token-bridge.html

浏览器兼容性:

环境 结果 说明
生产环境(同站) 自动工作 iit.*www.* 是 same-site
本地开发普通模式 自动工作 Storage Access API 自动授权
本地开发无痕模式 不可用 Chrome 无痕模式禁止所有第三方 Cookie

Phase 2 — ECS 历史操作记录

以下 common.jsappajax.js 的改动在 Bridge 升级后已冗余bridge 的 CSS 注入覆盖了相同功能)。 保留这些改动作为双重保障;如需回退,用 .bak 文件恢复即可。

文件 1/home/work/www/xunzhengyixue/static/js/common.js

navigation:function () { 开头加入的 iframe 检测代码。

文件 2/home/work/www/xunzhengyixue/tool/js/appajax.js

在文件开头加入的 iframe 检测代码。

Phase 2 — 踩坑记录

问题 原因 修复
Token 注入后 tool.html 正常,但 index.html 跳转登录页 gen_time 字段用了 MySQL NOW()datetime 格式),老系统期望 Java System.currentTimeMillis()(毫秒时间戳) 改为 Date.now(),同时先 DELETE 旧 token 再 INSERT
研究管理没有左侧导航 iframe 检测代码隐藏了 #nav-colreturn 导致侧边栏内容未生成 只隐藏 header + footer不 return
工具详情页仍显示顶部导航 工具详情页是独立前端,不加载 common.js,使用 tool/js/appajax.js appajax.js 开头也加 iframe 检测
localhost 无法测试 iframe 嵌入 父页面(localhost)无法为 .xunzhengyixue.com 设 Cookie 升级为 Wrapper Bridge由 bridge 页面在同域内设 Cookie
Bridge 设了 Cookie 但老系统仍跳登录页 浏览器第三方 Cookie 隔离cross-site iframe 的 document.cookie 被静默拒绝 添加 SameSite=None; Secure + Storage Access API 双重保障
隐藏导航栏后页面顶部多出空白条 #header-navbar 隐藏后 body 的 padding-top 仍在 Bridge CSS 注入额外清除 body#page-wrapper 的 padding-top/margin-top

5. 验证结果2026-02-27 本地 E2E 测试)

测试项 结果
Token 注入 + 自动登录 通过
研究管理index.html— 左侧导航正常 通过
统计分析工具tool.html— 126 个工具 通过
工具详情页tool/isttest1.html 等) 通过
统计分析 + 出报告 + 下载报告 通过
导航栏/页脚隐藏 + 顶部间距消除 通过
用户隔离(不同用户看不到彼此项目) 设计保证(按手机号绑定)
普通模式 Storage Access API 自动授权
无痕模式 预期不可用(浏览器限制)

6. 后续步骤

事项 说明
部署新系统后端到 SAE 确保 .envLEGACY_MYSQL_* 配置指向 ECS MySQL
部署新系统前端到 SAE 包含 LegacySystemPage 等新组件
生产端到端验证 同站环境(iit.*www.*),应自动工作无需 Storage Access API
可选:回退 ECS JS 改动 common.jsappajax.js 的 iframe 检测代码已被 bridge CSS 覆盖,可用 .bak 恢复
监控 关注 /api/v1/legacy/auth 接口调用量和失败率

7. 曾考虑但未选用的方案

方案 A直接外链跳转

作为 Phase 0 已实施。用户需手动登录老系统,两个标签页切换,体验不佳。

方案 C前端直调登录 API

需要知道用户在老系统的密码。如果用户改了密码就会失败。已被方案 EToken 注入)取代。

方案 DNginx 反向代理统一入口

在新系统 Nginx 配置 /legacy/* 反代到老系统。路径改写复杂流量多一次中转SAE 环境配置不便。


附录 ANginx 配置摘要(生产环境)

# api.xunzhengyixue.com → Java 后端
server {
    listen 443 ssl;
    server_name api.xunzhengyixue.com;
    location / {
        proxy_pass http://127.0.0.1:8899;
        proxy_cookie_path / /;
    }
}

# www.xunzhengyixue.com → 静态文件
server {
    listen 443 ssl;
    server_name xunzhengyixue.com www.xunzhengyixue.com;
    root /home/work/www/xunzhengyixue;
    index index.html;

    location /api-proxy/ {
        proxy_pass https://rag.xunzhengyixue.com/api/v1/;
    }
}

附录 B老系统源码关键文件索引

文件 位置(相对于 Java_old_system/XZYXServer 说明
登录 Controller src/main/java/com/xzyx/controller/UserController.java 3 个登录端点
Token 生成 src/main/java/com/xzyx/biz/service/impl/MysqlTokenValidator.java MD5 Token 公式
认证拦截器 src/main/java/com/xzyx/framework/AuthInterceptor.java 仅查表验证 Token
CORS 配置 src/main/java/com/xzyx/framework/CorsFilter.java 全开(*
MVC 配置 src/main/java/com/xzyx/framework/MvcConfig.java 拦截路径注册
前端导航+登录检查 ECS /home/work/www/xunzhengyixue/static/js/common.js 已修改iframe 检测
工具详情页 JS ECS /home/work/www/xunzhengyixue/tool/js/appajax.js 已修改iframe 检测
前端 API 配置 ECS /home/work/www/xunzhengyixue/static/js/config.js Cookie 域名逻辑
前端 HTTP 工具 ECS /home/work/www/xunzhengyixue/static/js/request.js Token → Authorization
前端入口页 ECS /home/work/www/xunzhengyixue/index.html, tool.html iframe 加载目标

附录 C老系统数据库表结构

详见 02-服务器与数据库配置说明.md