# 万象口袋 — Java（Spring Boot）后端文档

**技术栈**：Java 17 · Spring Boot 3.5 · Spring Web · Spring Data JPA · Hibernate · MySQL · Spring Data Redis（Lettuce）

**模块路径**：Maven 工程 `infogenie-backend-java`（坐标 `com.smyhub.infogenie:infogenie-backend-java`）

**入口**：`com.smyhub.infogenie.infogeniebackendjava.InfogenieBackendJavaApplication` — 载入 `application.yaml`、连接 MySQL、按需使用 Redis、启动内嵌 Tomcat。

**与 Go 后端关系**：路由与 JSON 契约与 `infogenie-backend-go` 对齐，便于前端同一份 `REACT_APP_API_URL` 切换端口联调；生产环境当前以 Go 部署为主时，可将前端仍指向 Go 服务。

---

## 运行与配置

- 配置主文件：[`src/main/resources/application.yaml`](src/main/resources/application.yaml)（占位符 `${VAR:default}` 可被系统环境变量或 IDE Run Configuration 覆盖）。
- Spring Boot **不会自动读取** 仓库内 `.env.development`；该文件仅作文向 `application.yaml` 变量说明（也可自行在 IDE 中一条条导入为环境变量）。
- `**APP_PORT**`：默认 **5002**（与 Go 开发端口一致时需注意二选一占用；亦可改为 5003 等与 Go 错峰）。
- 数据库：通过 `DB_HOST`、`DB_PORT`、`DB_NAME`、`DB_USER`、`DB_PASSWORD` 注入 JDBC URL（yaml 内已给开发用默认值，与 Go `.env.development` 常见配置一致）。
- 认证中心：`AUTH_CENTER_API_URL` → `app.auth-center-url`。
- 站点管理：`INFOGENIE_SITE_ADMIN_TOKEN` → `app.site-admin-token`（请求头 `X-Site-Admin-Token`）。

### Redis（可选）

业务是否走缓存由 **`app.redis-enabled`**（环境变量 `REDIS_ENABLED`）决定；关闭时服务逻辑直连 MySQL，不在启动阶段强制 Ping Redis。

| 变量 | 说明 |
| --- | --- |
| `REDIS_ENABLED` | `true` / `false`；映射 `app.redis-enabled` |
| `REDIS_HOST` / `REDIS_PORT` | `spring.data.redis.host` / `port` |
| `REDIS_PASSWORD` | 可选 |
| `REDIS_DB` | 逻辑库编号，默认与 yaml 中示例一致 |
| `REDIS_KEY_PREFIX` | `app.redis-key-prefix`，建议与 Go 前缀区分（如 `infogenie:java:`） |
| `REDIS_SITE_TTL` | 站点类缓存 TTL（秒）→ `app.redis-site-ttl` |

站点只读接口对 `60s-disabled`、`60s-source`、`ai-model-disabled`、`feature-clicks:{section}` 等做 cache-aside；管理端写入后删除对应 Key（见 `SiteConfigService`、`FeatureClickService`）。

### 邮件（诊断展示）

管理页 diagnostics 中的 `mail` 块来自环境变量 `MAIL_HOST`、`MAIL_PORT`、`MAIL_USERNAME`、`MAIL_PASSWORD`（仅展示是否配置密码，不落明文）。

---

## 健康与诊断

### `GET /api/health`（公开）

响应形状与 Go 一致，供 `AdminPage.js` 中 `normalizeHealthPayload` 解析：

- **`status`**：`running` 或 `degraded`（MySQL 未连通或 60s 上游探测失败；**不**因 Redis 将整体标为 degraded，与 Go 一致）。
- **`database`**：`connected` / `disconnected`。
- **`mysql`**：`{ ok, status }`。
- **`redis`**：未启用 `{ enabled: false }`；启用 `{ enabled: true, ok, error? }`。
- **`backend_api`**：`{ ok: true }`。
- **`sixty_api`**：`ok`、`source_id`、`base_url`、`label`、`probe_url`、`http_status`、`latency_ms`、`error`。

**HTTP 状态**：始终 **200**（退化只体现在 JSON `status`），避免前端将健康拉取判为失败。

### `GET /api/admin/site/diagnostics`（需管理员）

请求头 `X-Site-Admin-Token` 与 `INFOGENIE_SITE_ADMIN_TOKEN` 一致。返回字段与 Go 对齐：`app`（`env`、`listen_addr`、`listen_port`）、`mysql`、`redis`、`sixty_upstream`、`auth_center.api_url`、`mail` 等（不含密钥明文）。

---

**根路径**：`GET /` — 服务说明与主要 endpoint 列表（`version` 为 **3.3.0-java**）。

---

## 数据库（JPA）

`spring.jpa.hibernate.ddl-auto: update` 启动时按实体同步表结构，与 Go `AutoMigrate` 使用同一组业务表：

| 实体 | 用途 |
| --- | --- |
| `AIConfig` | 多厂商 AI Key / Base / 模型 |
| `Site60sDisabled` | 60s 前台隐藏 `feature_id` |
| `SiteAIRuntime` | DeepSeek 兼容网关（Base + Key + 默认模型），优先级高于部分 `AIConfig` |
| `Site60sUpstream` | 60s 上游（单例 `id=1`） |
| `SiteAIModelDisabled` | AI 应用前台隐藏 `app_id` |
| `SiteFeatureCardClick` | 功能卡片点击（`section` + `item_id` 联合主键）；增量 SQL 为 MySQL `INSERT … ON DUPLICATE KEY UPDATE`，对应 Repository 使用 `nativeQuery = true` |

---

## 路由与包结构概览

包根：`com.smyhub.infogenie.infogeniebackendjava`

| 包 | 说明 |
| --- | --- |
| `config` | `WebConfig`（CORS）、`RedisConfig`、`RestTemplateConfig`、`AppProperties` |
| `controller` | `Health`、`Auth`、`User`、`SiteConfig`、`Admin`、`AIModel` |
| `service` | 站点配置、点击统计、AI 调用、AI 工具提示词、运行时配置、健康探测 |
| `repository` | Spring Data JPA |
| `entity` | JPA 实体 |
| `dto.request` / `dto.response` | 入参与出参；**管理端、`item_id` 等入参使用 snake_case**（`@JsonProperty`），与前端、Go 一致 |
| `filter` | `JwtAuthFilter`：将 `Authorization: Bearer` 转发认证中心 `POST …/api/auth/verify`，结果放入 request attribute |
| `util` | 管理员令牌校验、AI 辅助方法 |

### CORS

`WebConfig` 放宽常用 Method/Header（含 `Authorization`、`X-Site-Admin-Token`）。

### 认证与用户

| 方法 | 路径 | 说明 |
| --- | --- | --- |
| GET | `/api/auth/check` | 可选 Bearer：已登录则返回简要 user |
| GET | `/api/user/profile` | **需**有效 Bearer |

### 站点公开配置

| 方法 | 路径 | 说明 |
| --- | --- | --- |
| GET | `/api/site/60s-disabled` | 隐藏 60s id 列表 |
| GET | `/api/site/60s-source` | 当前 60s 节点 |
| GET | `/api/site/ai-model-disabled` | 隐藏 AI 应用 id |
| GET | `/api/site/feature-card-clicks?section=` | 点击统计 |
| POST | `/api/site/feature-card-clicks/increment` | body：`section`、`item_id` |

### 站点管理（`X-Site-Admin-Token`）

| 方法 | 路径 | 说明 |
| --- | --- | --- |
| PUT | `/api/admin/site/60s-disabled` | body：`disabled` |
| PUT | `/api/admin/site/60s-source` | body：`source_id` |
| PUT | `/api/admin/site/ai-model-disabled` | body：`disabled` |
| GET/PUT | `/api/admin/site/ai-runtime` | GET 脱敏；PUT body：`api_base`、`api_key`、`default_model`、`default_provider` |
| GET | `/api/admin/site/diagnostics` | 配置快照 |

### AI（`/api/aimodelapp`，需 Bearer）

| 方法 | 路径 | 说明 |
| --- | --- | --- |
| POST | `/chat`、`/chat/stream` | 非流式 / SSE 透传 |
| POST | `/name-analysis` 等 | 垂直场景 |
| GET | `/models` | 白名单模型列表 |

上游解析与 Go 一致：`SiteAIRuntime` 在 base+key 齐全时优先；否则读 `AIConfig`（deepseek/kimi）。

---

## 常用命令

```bash
cd infogenie-backend-java
./mvnw test
./mvnw spring-boot:run
```

---

## 与其他工程的关系

- 前端 SPA 通过 `REACT_APP_API_URL` 指向本服务或 Go 服务（路径相同，端口按实际进程调整）。
- 更完整的前端对接说明见 **`infogenie-frontend/前端文档.md`**；Go 行为对照见 **`infogenie-backend-go/后端文档.md`**。
