# 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. 当前状态 - [x] 依赖盘点(§2) - [x] 方案确认(MyBatis 为 ORM) - [ ] 阶段 1 ~ 9 实施(进行中,见 `docs/plans/SpringBoot转写验证记录.md`)