SpringBoot后端转写方案.md 10 KB

SpringBoot 后端转写 技术实施方案

1. 目标与约束

需求原文:后端目前没有必须使用 Python 才能方便实现的功能,改为 SpringBoot 转写以方便跨平台部署。不删除当前后端代码,在新目录下写入。ORM 框架使用 MyBatis。

约束 说明
原 Python 后端保留 backend/ 目录原样保留,不做任何修改;两套后端可在不同端口并行运行验证
新目录 全部 Java 代码写入 backend-java/,Maven 标准布局
前端零改动 API 契约完全对齐 backend/openapi/openapi.yaml,前端仅在切换时改 base URL(或经 Nginx 反代不改)
数据同库 复用同一 MySQL 库(Alembic 已建表,schema 以 Alembic 0016 head 为准),不另建库
文件存储共用 复用同一 DMS_STORAGE_ROOT,两套后端可直接读取对方写入的文件
端口错开 Java 版默认 9346(Python 版 9345),避免并行验证冲突

2. Python 依赖盘点结论(转写可行性依据)

Python 依赖 实际用途(代码位置) Java 对应方案 结论
flask / flask-cors Web 框架与 CORS Spring Boot Web + CorsConfig 直译
Flask-SQLAlchemy / SQLAlchemy / PyMySQL ORM 与 MySQL 驱动 MyBatis + mysql-connector-j 直译(SQL 为准)
alembic(迁移 0001~0016) 表结构演进 Flyway(baseline 对齐 0016,此后 Java 版独占演进) 见 §4.3
PyJWT(HS256) 登录态令牌 jjwt(同 DMS_JWT_SECRET、同算法) 令牌互通
argon2-cffi(Argon2id,PHC 串) 密码哈希 spring-security-crypto Argon2PasswordEncoder(可校验存量 PHC 串) 存量密码直接可用
pymupdf(fitz) PDF 正文提取与预览(document_content_service / preview_service) Apache PDFBox(PDFTextStripper / Loader) 需回归验证提取差异
python-docx DOCX 正文提取 Apache POI XWPFParagraph 需回归验证
olefile 上传件 OLE 结构校验(storage/uploads) Apache POI POIFSFileSystem 直译
LibreOffice subprocess DOC→PDF 转换(document_converter) ProcessBuilder(命令行不变,语言无关) 直译
langchain / langchain-openai / pypinyin 代码中零引用(requirements.txt 残留依赖) 无需对应 直接丢弃
requests 门户 HTTP 验签(portal_provider) Spring RestClient 直译
PyYAML openapi 装配期校验 SnakeYAML(仅测试用) 直译
python-docx / tzdata 等 — JDK 内置 / 依赖自带 —

结论:无必须使用 Python 的功能,全部能力均有成熟 Java 对应,转写为纯工程翻译工作。

3. 技术选型

项 选择 版本
运行时 Java 17(LTS)
框架 Spring Boot 3.3.x
ORM MyBatis(mybatis-spring-boot-starter) 3.0.x
数据库驱动 mysql-connector-j 8.4.x
迁移 Flyway(flyway-core + flyway-mysql) 随 Boot
JWT jjwt-api/impl/jackson 0.12.x
密码哈希 spring-security-crypto(仅用 Argon2PasswordEncoder,不引入完整 Security 过滤链) 随 Boot
DOCX/OLE Apache POI 5.3.x
PDF Apache PDFBox 3.0.x
工具 Lombok、HikariCP(Boot 默认) —
构建 Maven + spring-boot-maven-plugin(单 jar,替代 PyInstaller) —

认证与授权沿用 Python 版自研方案(JWT 过滤器 + 注解式角色/权限校验),不启用 Spring Security 默认过滤链,保证行为与 Python 版逐条对齐。

4. 兼容性设计

4.1 响应包络与错误码

  • 响应包络与 backend/dms/common/response.py 一致:{code, message, data},成功 code="OK";
  • 全部错误码(约 40 个,含 HTTP 状态映射)从 backend/dms/common/errors.py 逐条移植为 DmsException(code, httpStatus, defaultMessage) + 子类;
  • 校验失败、参数缺失等框架层异常统一在 @RestControllerAdvice 转译为 INVALID_ARGUMENT,保证前端 errorCode 分支完全不变。

4.2 认证兼容

  • JWT:同 DMS_JWT_SECRET、HS256、同 claims(sub/uid/role/authVersion/iat/exp),两套后端签发的令牌互相可验;
  • auth_version 失效机制同款:改密/登出后令牌立即失效;
  • 密码:Argon2id PHC 串原样存储,Argon2PasswordEncoder 校验存量哈希;新设密码同样产出 PHC 串,Python 版亦能校验(双写期安全)。

4.3 数据库迁移策略

  • Alembic 已在库中留下 alembic_version 表(值 0016);
  • Java 版首次启动:Flyway baseline-on-migrate=true, baseline-version=0,V1__baseline_alembic_0016.sql 为空 DDL(仅占位,schema 已由 Alembic 建好),此后演进全部走 Flyway V2+;
  • 两套后端并行期内禁止任何一方再新增 Alembic 迁移,schema 演进以 Flyway 为唯一出口。

4.4 存储与配置兼容

  • DMS_STORAGE_ROOT 等全部 DMS_* 环境变量名与语义逐一同名移植(见 backend/dms/config.py),.env 可直接复用;
  • 存储目录布局(docs/{id}/...、预览缓存、正文缓存)按 backend/dms/storage/paths.py 原样复刻,保证两套后端互读。

5. 工程结构

backend-java/
├── pom.xml
├── .env.example                  # 与 backend/.env.example 同键
└── src/main/
    ├── java/com/dms/
    │   ├── DmsApplication.java
    │   ├── config/               # CorsConfig、MyBatis 配置、环境变量装载(DmsProperties)
    │   ├── common/               # 响应包络 ApiResponse、分页、业务异常体系、时间范围解析
    │   ├── security/             # JwtFilter、JwtTokens、Argon2 密码、AuthContext、注解鉴权
    │   ├── model/                # POJO 实体(对应 sys_user / sys_role / sys_organization /
    │   │                         #   sys_category / doc_document / doc_relation / doc_permission /
    │   │                         #   sys_audit_log / sys_ip_entry / sys_org_ip_assignment)
    │   ├── mapper/               # MyBatis Mapper 接口 + resources/mapper/*.xml
    │   ├── service/              # 业务服务,与 Python dms/services/* 一一对应
    │   ├── storage/              # 上传落盘、路径、完整性校验、正文提取(POI/PDFBox)
    │   └── api/v1/               # Controller:auth、portalAuth、users、roles、organizations、
    │                             #   categories、documents、files、recycleBin、audit、
    │                             #   ipEntries、uiDictionaries、runtimeConfig、health
    ├── resources/
    │   ├── application.yml
    │   ├── mapper/*.xml
    │   ├── db/migration/         # Flyway
    │   └── resources/            # ui-dictionaries / document-relation-presets(从 Python 版同步)
    └── test/java/com/dms/        # 关键路径测试(auth、权限矩阵、文档生命周期)

6. 分阶段实施计划

每阶段完成后以「Python 版对应 pytest 用例 + 前端手工冒烟」双口径验证;前端指向 9346 冒烟通过后该阶段才算完成。

阶段 内容 主要产出 验证标准 预估
1 工程骨架 pom、application.yml、ApiResponse、全局异常→错误码映射、CORS、健康检查、Flyway baseline、环境变量装载 启动无报错;GET /api/v1/health 200;非法请求返回包络错误码 1 天
2 认证与用户基础 users 表 Mapper、login/logout/me、JWT、Argon2、IP 登录限制 前端可登录/登出/会话保持;存量账号密码可直接登录 2 天
3 门户跳转登录 portal verify / setup-password、provider(http/mock/custom)、自动建号 test_portal_auth.py 全部分支在 Java 版行为一致(mock 流程手工复测) 1.5 天
4 组织 / 用户 / 角色管理 organizations、users CRUD、roles 与权限矩阵、审计写入 后台管理页全功能可用;操作审计落库 3 天
5 分类与文档 categories(含扁平模式)、documents CRUD、上下传、dms-storage 落盘、完整性校验、方案密码锁 文档全生命周期可用;与 Python 版互读对方存储文件 4 天
6 检索与正文 正文提取(PDFBox/POI)、search_text 回填、关键词/时间范围/全局检索、命中片段 检索结果与 Python 版抽样一致;提取差异肉眼可接受 3 天
7 权限引擎与关系面板 permission_service、authorization_service、部门数据范围、挂载/解绑、回收站 权限矩阵逐格抽验;回收站恢复全约束生效 3 天
8 预览转换与审计统计 预览缓存、DOC→PDF(LibreOffice)、审计查询与统计 三类文件预览正常;审计统计口径一致 2 天
9 工具与部署 seed 数据脚本、upgrade-db、打包(单 jar)、run.bat/run.sh、docs/ 运维手册 打包产物在干净机器可一键启动 2 天

合计约 18~21 个工作日。阶段 2 起每阶段收尾生成对比清单(Python 用例 → Java 行为结论)存入 docs/plans/SpringBoot转写验证记录.md。

7. 风险与对策

风险 等级 对策
dms-storage 目录/文件名规则移植不一致导致互读失败 高 阶段 5 先写"Python 版建→Java 版读 / Java 版建→Python 版读"互读测试再接入业务
PDFBox 与 PyMuPDF 正文提取细节差异(分页、空格、乱码) 中 阶段 6 抽样对比提取文本;差异仅影响片段高亮,不影响正确性时记录已知差异
Argon2 存量 PHC 校验兼容 中 阶段 2 首个测试即为"Python 版建号 → Java 版登录";spring-security-crypto 默认参数与 argon2-cffi 默认参数不同,但校验按 PHC 串内嵌参数执行,需实测确认
Flyway 与 alembic_version 并存的管理混乱 中 立即冻结 Alembic 演进(§4.3);Java 版 schema 操作仅经 Flyway
LibreOffice 转换在 Java 进程管理的退出码/超时语义差异 低 ProcessBuilder 显式 destroy + 同款超时秒数,阶段 8 实测
openapi.yaml 装配期校验缺失导致契约漂移 低 阶段 1 搭 SnakeYAML 冒烟校验(仅测试期),后续按需补

8. 当前状态

  • 依赖盘点(§2)
  • 方案确认(MyBatis 为 ORM)
  • 阶段 1 ~ 9 实施(进行中,见 docs/plans/SpringBoot转写验证记录.md)