Prechádzať zdrojové kódy

docs: Spring Boot 3升级 + Dify替代实施计划

asus 3 mesiacov pred
rodič
commit
56b91957c5

+ 401 - 0
docs/architecture/SpringBoot3升级+Dify替代实施计划.md

@@ -0,0 +1,401 @@
+# Spring Boot 3.x 升级 + Dify 替代 实施计划
+
+> 版本: v1.0
+> 日期: 2026-07-20
+> 范围: cfc-backend (Spring Boot 2.7.18 + Java 8 → Spring Boot 3.4.x + Java 21)
+
+---
+
+## 一、目标状态
+
+| 维度 | 当前 | 目标 |
+|------|------|------|
+| Java | 1.8 (JDK 8) | **21 LTS** |
+| Spring Boot | 2.7.18 | **3.4.x** (最新稳定) |
+| AI 框架 | 直调 Dify API | **Spring AI 1.x** |
+| 知识库 | Dify Datasets | **本地 sqlite-vec** |
+| 数学引擎 | Nashorn (JDK 15 已移除) | **exp4j / SpEL** |
+| API 文档 | springdoc-openapi 1.8.0 | **springdoc-openapi 2.7+** |
+| ORM | MyBatis-Plus 3.5.3.1 | **MyBatis-Plus 3.5.7+** |
+| JWT | jjwt 0.11.5 | **jjwt 0.12.6** |
+
+---
+
+## 二、总体路线
+
+```
+5 阶段 / 20 人天 / 可回退 / 每阶段独立验证
+
+Phase 0 ─── Phase 1 ─── Phase 2 ─── Phase 3 ─── Phase 4
+前置准备    javax→      行为适配     Spring AI    回归验证
+(3天)       jakarta      +            +            +
+            迁移         Nashorn       Dify         上线
+            (5天)        替换         替换          (3天)
+                        (4天)        (5天)
+```
+
+**回退机制**:每阶段结束时有一个 `git tag`,任一阶段失败可退回到上个稳定点。
+
+---
+
+## 三、各阶段详细任务
+
+### Phase 0 — 前置准备(3 天)
+
+**目标**:环境就绪,依赖对齐,识别所有需要改动的文件。
+
+| 任务 | 产出 | 验证 |
+|------|------|------|
+| 0.1 JDK 21 安装 + Maven 3.9+ 升级 | `java -version` → 21 | 开发/CI 环境确认 |
+| 0.2 pom.xml: parent → spring-boot 3.4.x | BOM 对齐 | `mvn dependency:tree` 无冲突 |
+| 0.3 依赖版本批量更新 | 见下方依赖表 | 编译无报错 |
+| 0.4 maven-compiler-plugin source/target → 21 | `java.version=21` | 编译通过 |
+| 0.5 `mvn compile` 采集完整 javax 报错清单 | javax 影响范围清单 | 确认 482 个文件全部覆盖 |
+| 0.6 Nashorn 调用栈录制 | WisdomMathService 表达式求值场景 | 确认替换范围 |
+| 0.7 创建 git tag: `v2.7.18-baseline` | 可回退点 | `git log` 确认 |
+
+**依赖版本变更表:**
+
+```xml
+<!-- pom.xml 关键变更 -->
+<parent>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-parent</artifactId>
+    <version>3.4.x</version>           <!-- 2.7.18 → 3.4.x -->
+</parent>
+<properties>
+    <java.version>21</java.version>    <!-- 1.8 → 21 -->
+    <mybatis-plus.version>3.5.9</mybatis-plus.version>  <!-- 3.5.3.1 → 3.5.9 -->
+</properties>
+
+<!-- 替换或新增 -->
+<dependency>
+    <!-- springdoc v1 → v2 (包名变更) -->
+    <groupId>org.springdoc</groupId>
+    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+    <version>2.7.0</version>
+</dependency>
+
+<dependency>
+    <!-- jjwt 0.11.5 → 0.12.6 -->
+    <groupId>io.jsonwebtoken</groupId>
+    <artifactId>jjwt-api</artifactId>
+    <version>0.12.6</version>
+</dependency>
+
+<!-- 移除:nashorn-core (如果显式引入) -->
+<!-- 新增:表达式求值替代库 -->
+<dependency>
+    <groupId>net.objecthunter</groupId>
+    <artifactId>exp4j</artifactId>
+    <version>0.4.8</version>
+</dependency>
+```
+
+---
+
+### Phase 1 — javax → jakarta 迁移(5 天)
+
+**目标**:482 个文件的 `javax.*` 引用全部替换为 `jakarta.*`,编译通过。
+
+**替换规则:**
+
+| 原包名 | 目标包名 | 影响模块 |
+|--------|---------|---------|
+| `javax.persistence.*` | `jakarta.persistence.*` | 所有 @Entity, @Table, @Column |
+| `javax.annotation.*` | `jakarta.annotation.*` | @Resource, @PostConstruct, @PreDestroy |
+| `javax.validation.*` | `jakarta.validation.*` | @Valid, @NotBlank, @Size, DTO |
+| `javax.servlet.*` | `jakarta.servlet.*` | HttpServletRequest/Response, Filter |
+| `javax.sql.*` | `jakarta.sql.*` | DataSource (如果直接引用) |
+
+**操作方式:**
+
+```
+方式 A:IDE 全局替换(推荐)
+  IntelliJ: 重构 → 迁移包 → javax→jakarta
+  或 sed 逐目录确认
+
+方式 B:分批替换
+  day1: entity 包(~80 个文件)—— 最规则,可批量
+  day2: dto 包(所有 @NotBlank/@Valid)—— 替换量大但简单
+  day3: config + task + filter 包 —— @Resource/@PostConstruct
+  day4: service + controller 包 —— 逐一检查
+  day5: 全量编译 + 修复残留问题
+```
+
+**风险提示**:
+- `javax.annotation.Resource` 和 `javax.annotation.PostConstruct` 在 Spring Boot 3 中内置了 jakarta 适配,但显式引用仍需改包名
+- Spring 自己的 `@Autowired` 不受影响
+- MyBatis-Plus 的注解 (`@TableName` 等) 不受影响(不走 javax)
+
+**产出**:`mvn clean compile` 零错误。
+
+---
+
+### Phase 2 — 行为适配 + Nashorn 替换(4 天)
+
+**目标**:Spring Boot 3 行为变更对齐,废弃 API 替换,全量编译通过。
+
+#### 2.1 Spring Boot 3 行为变更
+
+| 变更项 | 影响 | 处理方式 |
+|--------|------|---------|
+| PathPatternParser (默认) | 某些 Ant 风格路径可能不匹配 | 配置 `spring.mvc.pathmatch.matching-strategy=ant-path-matcher` 可回退 |
+| `spring.config.location` 弃用 | 如果使用了 | 改为 `spring.config.import` |
+| Spring Security 默认变更 | 如果有 Security 配置 | 检查 CSRF/鉴权默认值 |
+| `WebMvcConfigurerAdapter` 已删除 | 如果继承了 | 改为实现 `WebMvcConfigurer` |
+| Health indicator 变更 | actuator 配置 | 确认无需更改 |
+
+#### 2.2 Nashorn → exp4j 替换
+
+当前代码(WisdomMathService):
+```java
+ScriptEngineManager mgr = new ScriptEngineManager();
+ScriptEngine engine = mgr.getEngineByName("nashorn");
+engine.eval("12+38*2");  // → 88
+```
+
+替换方式:
+```java
+// exp4j (轻量,仅数学表达式,推荐)
+import net.objecthunter.exp4j.ExpressionBuilder;
+
+Expression exp = new ExpressionBuilder(expression).build();
+double result = exp.evaluate();
+```
+
+**验证**:
+- 提取 WisdomMathService 的所有表达式测试用例
+- 确保 exp4j 覆盖全部运算符(+ - * / ^ % 括号 函数)
+- 表达式求值精度一致
+
+#### 2.3 springdoc-openapi v1 → v2
+
+| v1 (当前) | v2 (目标) |
+|-----------|----------|
+| `springdoc-openapi-ui` | `springdoc-openapi-starter-webmvc-ui` |
+| 包名: `org.springdoc` | 包名: `org.springdoc` (同但内部结构变) |
+| 配置路径: `springdoc.swagger-ui.path` | 同(但需确认) |
+
+改动:pom.xml artifactId 变更,配置确认。
+
+#### 2.4 jjwt 0.11 → 0.12
+
+主要 API 变化:
+- `Jwts.builder()` → 签名方法参数类型变化
+- `Keys.secretKeyFor()` → 返回类型变更为 `SecretKey`
+- `Jwts.parserBuilder()` → `Jwts.parser()` (不再需要 .builder())
+
+需检查 `JwtUtil.java` / 任何使用 jjwt 的地方,逐一适配。
+
+#### 2.5 编译验证
+
+`mvn clean compile` 零错误。
+
+---
+
+### Phase 3 — Spring AI 集成 + Dify 替换(5 天)
+
+**目标**:用 Spring AI 替换 Dify 的全部调用,本地知识库就位。
+
+#### 3.1 Spring AI 依赖
+
+```xml
+<!-- Spring AI - BOM -->
+<dependencyManagement>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.ai</groupId>
+            <artifactId>spring-ai-bom</artifactId>
+            <version>1.x.x</version>
+            <type>pom</type>
+            <scope>import</scope>
+        </dependency>
+    </dependencies>
+</dependencyManagement>
+
+<dependencies>
+    <!-- OpenAI 兼容协议 (覆盖 DeepSeek, Ollama) -->
+    <dependency>
+        <groupId>org.springframework.ai</groupId>
+        <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
+    </dependency>
+    <!-- 如果用 Qwen, 加 dashscope starter -->
+</dependencies>
+```
+
+#### 3.2 ChatClient 封装(替代 AIService)
+
+```java
+// 核心抽象 — 替代原来的 AIService + OkHttp 直调
+@Service
+public class LLMService {
+
+    @Resource
+    private ChatClient.Builder chatClientBuilder;
+
+    // 聊天(带 System Prompt + 会话记忆)
+    public String chat(String query, String systemPrompt, String conversationId) {
+        return chatClientBuilder.build()
+            .prompt()
+            .system(systemPrompt)
+            .user(query)
+            .advisors(new MessageChatMemoryAdvisor(chatMemory, conversationId, 10))
+            .call()
+            .content();
+    }
+
+    // 流式
+    public Flux<String> stream(String query, String systemPrompt, String conversationId) {
+        return chatClientBuilder.build()
+            .prompt()
+            .system(systemPrompt)
+            .user(query)
+            .advisors(new MessageChatMemoryAdvisor(chatMemory, conversationId, 10))
+            .stream()
+            .content();
+    }
+}
+```
+
+#### 3.3 8 个 Service 逐一替换
+
+参考 `docs/architecture/Dify替代迁移可行性分析.md` 第 4.2 节的 `LLMService` 接口映射:
+
+| Service | Dify API | Spring AI 替代 | 工作量 |
+|---------|----------|---------------|--------|
+| AIService | chat-messages POST | ChatClient | ⭐ 小 |
+| DifySyncService | datasets | VectorStore + 本地管理 | ⭐⭐⭐ 中 |
+| AiConversationSummaryService | conversations | MemoryAdvisor | ⭐ 小 |
+| AiUserFactService | /workflows | ChatClient + @Tool | ⭐⭐ 中 |
+| ChatMirrorService | 日志镜像 | 转正为缓存层 | ⭐ 小 |
+| 其余 3 个 Service | 各异 | 具体分析 | ⭐⭐ 中 |
+
+#### 3.4 知识库本地化
+
+Dify Datasets 替代方案:
+
+```yaml
+# 方案投票:pgvector vs sqlite-vec
+# PostgreSQL 扩展 — 如果主库是 MySQL 则需要额外 PG 实例,引入成本高
+# sqlite-vec — 嵌入式,零运维,适合知识库 < 10万条
+
+# 选型:sqlite-vec(嵌入式,匹配项目规模)
+spring:
+  ai:
+    vectorstore:
+      sqlite:
+        path: ${data.dir}/knowledge.db
+```
+
+#### 3.5 System Prompt 外部化
+
+```
+不再依赖 Dify 的 Prompt 编辑器 →
+改为 YAML 文件或数据库表管理:
+
+resources/prompts/
+├── family-advisor.yaml
+├── growth-plan.yaml
+├── diet-recommend.yaml
+└── math-tutor.yaml
+```
+
+#### 3.6 Dify 数据归档
+
+Dify 替代表(原 6 张表):
+- `dify_*` 表 → 上游 Dify 不再写入后,保留 30 天观察期 → 归档/删除
+
+#### 3.7 验证标准
+
+- 原 Dify API 调用的 8 个 Service 全部改用 Spring AI
+- 流式聊天正常
+- 知识库检索准确率 >= Dify 时期
+- 对话记忆正常
+
+---
+
+### Phase 4 — 回归验证 + 上线(3 天)
+
+**目标**:全量回归通过,灰度上线。
+
+#### 4.1 回归范围
+
+| 测试范围 | 方法 | 负责人 |
+|---------|------|--------|
+| 所有 48 个 Controller API | 手动 + Postman 用例集 | 后端 |
+| 小程序端主流程 | 真机/开发者工具 | 前端联调 |
+| Web 管理端主流程 | 浏览器 | 前端联调 |
+| AI 聊天流程 | 对比测试(原 Dify vs Spring AI) | 后端 |
+| 数学表达式求值 | 用例集 + 精度对比 | 后端 |
+| 文件上传/PDF 解析 | 功能测试 | 后端 |
+
+#### 4.2 性能对比
+
+| 指标 | Dify 链路 | Spring AI 链路 | 目标 |
+|------|-----------|---------------|------|
+| 非流式首 Token 延迟 | ~2-3s | ~1-2s | 不劣化 |
+| 流式响应 TTFB | ~1.5s | ~0.8s | -30% |
+| 并发 50 用户 CPU | 待测 | 待测 | 不劣化 |
+| 内存使用 | 待测 | 待测 | 不劣化 |
+
+#### 4.3 上线方案
+
+```
+Step 1: 灰度 10% 流量(1 天) → 监控错误率
+Step 2: 灰度 50% 流量(1 天) → 监控延迟/错误率
+Step 3: 全量上线           → 观察 48h
+Step 4: Dify 实例下线       → 保留数据 30 天后清理
+```
+
+#### 4.4 回滚条件
+
+任一触发立即回滚:
+- API 错误率 > 1%
+- AI 响应可用率 < 99%
+- 核心接口延迟翻倍
+
+---
+
+## 四、风险评估
+
+| 风险 | 概率 | 影响 | 缓解措施 |
+|------|------|------|---------|
+| 三方库不兼容 Spring Boot 3 | 低 | 高 | Phase 0 先行验证,确认全部依赖兼容 |
+| javax→jakarta 遗漏某些深层引用 | 中 | 中 | Phase 1 分步替换,逐包编译验证 |
+| Spring AI 对 DeepSeek 的支持缺陷 | 低 | 中 | 降级方案:直调 OKHttp(方案 D) |
+| 知识库检索质量下降 | 中 | 中 | Phase 3 做对比测试,保留 Dify 数据 30 天 |
+| Nashorn 替换导致数学结果偏差 | 低 | 高 | Phase 2 提取全部测试用例,逐条验证 |
+
+---
+
+## 五、回退点
+
+| 阶段 | 回退点 | 回退方式 |
+|------|--------|---------|
+| Phase 0 完成 | `git tag v2.7.18-baseline` | `git checkout` |
+| Phase 1 完成 | `git tag v3.0-javax-migrated` | `git reset --hard` |
+| Phase 2 完成 | `git tag v3.0-build-ready` | `git reset --hard` |
+| Phase 3 完成 | `git tag v3.0-spring-ai` | `git reset --hard` + 切回 Dify 数据源 |
+
+每阶段可独立回退,不会影响其他阶段的工作。
+
+---
+
+## 六、资源估算
+
+```
+Phase 0  前置准备     3 天 × 1 人
+Phase 1  javax→jkt    5 天 × 1 人
+Phase 2  行为适配     4 天 × 1 人
+Phase 3  Spring AI    5 天 × 1 人
+Phase 4  回归+上线    3 天 × 1 人
+──────────────────────────────
+总计                   20 人天
+
+建议 2 人并行(后端 1 + 后端 2):
+Phase 0-2 可 2 人并行(一人改包名,一人适配行为)
+Phase 3    集中 1 人(Spring AI 集成需连续上下文)
+Phase 4    2 人并行回归
+→ 日历时间约 2 周
+```