# java-mock 接口文档 & 数据设计 > Base URL: `http://localhost:8080` > > 认证方式: JWT Bearer Token(除登录/注册外,所有接口均需在请求头附加 `Authorization: Bearer `) --- ## 目录 - [接口总览](#接口总览) - [一、认证接口](#一认证接口) - [1.1 登录](#11-登录) - [1.2 注册](#12-注册) - [1.3 获取当前用户信息](#13-获取当前用户信息) - [二、AI 代理接口(转发 Python)](#二ai-代理接口转发-python) - [2.1 获取场景列表](#21-获取场景列表) - [2.2 开始语音对话](#22-开始语音对话) - [2.3 停止语音对话](#23-停止语音对话) - [2.4 写入历史上下文](#24-写入历史上下文) - [三、对话记录接口](#三对话记录接口) - [3.1 保存对话](#31-保存对话) - [3.2 对话列表(分页)](#32-对话列表分页) - [3.3 对话详情](#33-对话详情) - [3.4 追加消息](#34-追加消息) - [3.5 删除对话](#35-删除对话) - [四、其他](#四其他) - [4.1 健康检查](#41-健康检查) - [数据结构设计](#数据结构设计) - [User(用户表)](#user用户表) - [Conversation(对话表)](#conversation对话表) - [Message(消息子文档)](#message消息子文档) - [内部转发签名协议](#内部转发签名协议) - [通用错误响应](#通用错误响应) - [环境变量](#环境变量) --- ## 接口总览 | 方法 | 路径 | 是否需要 Token | 说明 | |---|---|---|---| | GET | `/health` | 否 | 健康检查 | | POST | `/api/auth/login` | 否 | 登录 | | POST | `/api/auth/register` | 否 | 注册 | | GET | `/api/auth/me` | ✅ | 获取当前用户信息 | | POST | `/api/ai/getScenes` | ✅ | 获取场景列表(转发 Python) | | POST | `/api/ai/proxy?Action=StartVoiceChat` | ✅ | 开始语音对话(转发 Python) | | POST | `/api/ai/proxy?Action=StopVoiceChat` | ✅ | 停止语音对话(转发 Python) | | POST | `/api/ai/session/history` | ✅ | 写入历史上下文(转发 Python) | | POST | `/api/ai/conversations` | ✅ | 保存对话记录 | | GET | `/api/ai/conversations` | ✅ | 对话列表(分页) | | GET | `/api/ai/conversations/:id` | ✅ | 对话详情 | | POST | `/api/ai/conversations/:id/append` | ✅ | 追加消息到对话 | | DELETE | `/api/ai/conversations/:id` | ✅ | 删除对话 | --- ## 一、认证接口 ### 1.1 登录 ``` POST /api/auth/login ``` **请求体(JSON):** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | username | string | ✅ | 用户名 | | password | string | ✅ | 密码(明文) | **请求示例:** ```json { "username": "admin", "password": "admin123" } ``` **成功响应 200:** ```json { "code": 200, "data": { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "name": "管理员", "sex": "male", "isDriver": false, "deptId": 1, "deptName": "办公室", "roleList": ["admin", "user"] } } ``` **失败响应:** | HTTP 状态码 | code | message | |---|---|---| | 400 | 400 | 用户名和密码不能为空 | | 401 | 401 | 用户名或密码错误 | --- ### 1.2 注册 ``` POST /api/auth/register ``` **请求体(JSON):** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | username | string | ✅ | 用户名(唯一) | | password | string | ✅ | 密码(明文) | | nickname | string | ❌ | 昵称,不传时默认等于 username | **请求示例:** ```json { "username": "newuser", "password": "pass123", "nickname": "新用户" } ``` **成功响应 200:** ```json { "code": 200, "data": { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "name": "新用户", "sex": "unknown", "isDriver": false, "deptId": 0, "deptName": "", "roleList": ["user"] } } ``` **失败响应:** | HTTP 状态码 | code | message | |---|---|---| | 400 | 400 | 用户名和密码不能为空 | | 409 | 409 | 用户名已存在 | > 注册成功后新用户默认属性:`sex=unknown`、`isDriver=false`、`deptId=0`、`roleList=["user"]` --- ### 1.3 获取当前用户信息 ``` GET /api/auth/me ``` **成功响应 200:** ```json { "code": 200, "data": { "name": "管理员", "sex": "male", "isDriver": false, "deptId": 1, "deptName": "办公室", "roleList": ["admin", "user"] } } ``` **失败响应:** | HTTP 状态码 | code | message | |---|---|---| | 401 | 401 | 未提供 Authorization Token | | 401 | 401 | Token 无效或已过期 | | 404 | 404 | 用户不存在 | --- ## 二、AI 代理接口(转发 Python) > 所有 AI 代理接口均带 HMAC-SHA256 内部签名后转发至 Python 后端(`PYTHON_BACKEND_URL`),响应内容原样透传。 > > 详细签名规则见 [内部转发签名协议](#内部转发签名协议)。 --- ### 2.1 获取场景列表 ``` POST /api/ai/getScenes ``` **请求体:** `{}` 或空 **成功响应(Python 原样返回):** ```json { "ResponseMetadata": { "Action": "getScenes" }, "Result": { "scenes": [ { "scene": { "id": "Custom", "botName": "BotUser001", "isInterruptMode": true, "isVision": false, "isScreenMode": false, "isAvatarScene": false, "avatarBgUrl": null }, "rtc": { "AppId": "6xxxxxxx", "RoomId": "room-abc123", "UserId": "user-xyz", "Token": "AQBhMGI3Zm...", "TaskId": "task-001" } } ] } } ``` --- ### 2.2 开始语音对话 ``` POST /api/ai/proxy?Action=StartVoiceChat ``` **请求体(JSON):** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | SceneID | string | ✅ | 场景 ID(从 getScenes 获取) | **请求示例:** ```json { "SceneID": "Custom" } ``` **成功响应(Python 原样返回):** ```json { "ResponseMetadata": { "RequestId": "2024xxxxxxxxxx", "Action": "StartVoiceChat", "Version": "2024-12-01", "Service": "rtc" }, "Result": { "Message": "success" } } ``` --- ### 2.3 停止语音对话 ``` POST /api/ai/proxy?Action=StopVoiceChat ``` **请求体(JSON):** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | SceneID | string | ✅ | 场景 ID | **请求示例:** ```json { "SceneID": "Custom" } ``` **成功响应(Python 原样返回):** ```json { "ResponseMetadata": { "RequestId": "2024xxxxxxxxxx", "Action": "StopVoiceChat", "Version": "2024-12-01", "Service": "rtc" }, "Result": { "Message": "success" } } ``` --- ### 2.4 写入历史上下文 > 在 StartVoiceChat 之前调用,将历史对话上下文注入 Python Session,以便 AI 延续上下文。 ``` POST /api/ai/session/history ``` **请求体(JSON):** 转发到 Python `/api/session/history`,具体字段由 Python 接口定义,典型示例: ```json { "roomId": "room-abc123", "history": [ { "role": "user", "content": "你好" }, { "role": "assistant", "content": "你好!有什么可以帮你?" } ] } ``` **成功响应:** Python 原样返回 --- ## 三、对话记录接口 ### 3.1 保存对话 ``` POST /api/ai/conversations ``` **请求体(JSON):** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | sceneId | string | ✅ | 场景 ID | | roomId | string | ❌ | RTC 房间 ID | | messages | array | ✅ | 消息数组(见下表) | **messages 数组每条消息字段:** | 字段 | 类型 | 说明 | |---|---|---| | role | string | `"user"` 或 `"assistant"`(优先使用) | | content | string | 消息文本 | | time | string | ISO 时间戳,不传取服务器当前时间 | | userId | string | 兼容旧格式。与当前登录用户 ID 相同则视为 `user`,否则视为 `assistant` | | text | string | 兼容旧格式,与 `content` 二选一 | **请求示例:** ```json { "sceneId": "Custom", "roomId": "room-abc123", "messages": [ { "role": "assistant", "content": "你好,我是小块", "time": "2026-04-02T10:00:00Z" }, { "role": "user", "content": "今天出勤情况咋样", "time": "2026-04-02T10:00:05Z" }, { "role": "assistant", "content": "今天出勤率 90%", "time": "2026-04-02T10:00:08Z" } ] } ``` **成功响应 200:** ```json { "code": 200, "data": { "sessionId": "9864c5ef-cdee-4c35-8f6a-81a9a4f6d323" } } ``` **失败响应:** | HTTP 状态码 | code | message | |---|---|---| | 400 | 400 | sceneId 和 messages 不能为空 | --- ### 3.2 对话列表(分页) ``` GET /api/ai/conversations?page=1&size=20 ``` **Query 参数:** | 字段 | 类型 | 默认值 | 说明 | |---|---|---|---| | page | number | 1 | 页码(从 1 开始) | | size | number | 20 | 每页条数(上限 100) | **成功响应 200:** ```json { "code": 200, "data": { "total": 5, "page": 1, "size": 20, "list": [ { "id": "9864c5ef-cdee-4c35-8f6a-81a9a4f6d323", "sceneId": "Custom", "roomId": "room-abc123", "startedAt": "2026-04-02T10:00:00Z", "endedAt": "2026-04-02T10:00:08Z", "messageCount": 3, "firstMessage": "今天出勤情况咋样" } ] } } ``` > - 列表按 `createdAt` **倒序**排列 > - `firstMessage` 取第一条 `role === "user"` 的消息内容,无用户消息时为空串 > - 仅返回**当前登录用户**的对话记录 --- ### 3.3 对话详情 ``` GET /api/ai/conversations/:id ``` **Path 参数:** | 字段 | 说明 | |---|---| | id | 对话 UUID | **成功响应 200:** ```json { "code": 200, "data": { "id": "9864c5ef-cdee-4c35-8f6a-81a9a4f6d323", "userId": "user-admin-001", "sceneId": "Custom", "roomId": "room-abc123", "startedAt": "2026-04-02T10:00:00Z", "endedAt": "2026-04-02T10:00:08Z", "createdAt": "2026-04-02T10:00:10Z", "messages": [ { "role": "assistant", "content": "你好,我是小块", "createdAt": "2026-04-02T10:00:00Z" }, { "role": "user", "content": "今天出勤情况咋样", "createdAt": "2026-04-02T10:00:05Z" }, { "role": "assistant", "content": "今天出勤率 90%", "createdAt": "2026-04-02T10:00:08Z" } ] } } ``` **失败响应:** | HTTP 状态码 | code | message | |---|---|---| | 404 | 404 | 对话记录不存在 | | 403 | 403 | 无权访问该对话 | --- ### 3.4 追加消息 > 对话保存后如需继续追加消息(例如语音会话延续),调用此接口。 ``` POST /api/ai/conversations/:id/append ``` **Path 参数:** | 字段 | 说明 | |---|---| | id | 对话 UUID | **请求体(JSON):** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | messages | array | ✅ | 追加的消息数组,格式同 3.1 | **请求示例:** ```json { "messages": [ { "role": "user", "content": "那明天呢", "time": "2026-04-02T10:01:00Z" }, { "role": "assistant", "content": "明天是周末,无需考勤", "time": "2026-04-02T10:01:03Z" } ] } ``` **成功响应 200:** ```json { "code": 200, "data": { "sessionId": "9864c5ef-cdee-4c35-8f6a-81a9a4f6d323" } } ``` **失败响应:** | HTTP 状态码 | code | message | |---|---|---| | 400 | 400 | messages 不能为空 | | 404 | 404 | 对话记录不存在 | | 403 | 403 | 无权操作该对话 | --- ### 3.5 删除对话 ``` DELETE /api/ai/conversations/:id ``` **Path 参数:** | 字段 | 说明 | |---|---| | id | 对话 UUID | **成功响应 200:** ```json { "code": 200, "data": null } ``` **失败响应:** | HTTP 状态码 | code | message | |---|---|---| | 404 | 404 | 对话记录不存在 | | 403 | 403 | 无权删除该对话 | --- ## 四、其他 ### 4.1 健康检查 ``` GET /health ``` **响应(无需 Token):** ```json { "status": "ok", "service": "java-mock", "timestamp": "2026-04-02T10:00:00.000Z" } ``` --- ## 数据结构设计 ### User(用户表) > 文件存储路径:`data/users.json`(数组) | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | ✅ | 唯一 ID,格式 `user-` 或 `user-admin-001`(内置账号) | | username | string | ✅ | 登录用户名,全局唯一 | | password | string | ✅ | 明文密码(Mock 环境,生产请改用 bcrypt 哈希) | | name | string | ✅ | 显示名 / 昵称 | | sex | string | ✅ | 性别:`"male"` / `"female"` / `"unknown"` | | isDriver | boolean | ✅ | 是否为司机角色 | | deptId | number | ✅ | 部门 ID,`0` 表示无部门 | | deptName | string | ✅ | 部门名称 | | roleList | string[] | ✅ | 角色列表,如 `["admin","user"]` / `["user"]` | | createdAt | string | ✅ | 创建时间 ISO8601 | **示例数据:** ```json [ { "id": "user-admin-001", "username": "admin", "password": "admin123", "name": "管理员", "sex": "male", "isDriver": false, "deptId": 1, "deptName": "办公室", "roleList": ["admin", "user"], "createdAt": "2026-01-01T00:00:00.000Z" }, { "id": "user-001", "username": "user1", "password": "user123", "name": "测试用户", "sex": "female", "isDriver": false, "deptId": 2, "deptName": "工程部", "roleList": ["user"], "createdAt": "2026-01-01T00:00:00.000Z" } ] ``` --- ### Conversation(对话表) > 文件存储路径:`data/conversations.json`(数组) | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | ✅ | UUID v4,全局唯一 | | userId | string | ✅ | 所属用户 ID(关联 User.id) | | sceneId | string | ✅ | 场景 ID,如 `"Custom"` | | roomId | string | ✅ | RTC 房间 ID,无则为空串 | | startedAt | string | ✅ | 对话开始时间(取第一条消息 `createdAt`) | | endedAt | string | ✅ | 对话结束时间(取最后一条消息 `createdAt`) | | createdAt | string | ✅ | 记录入库时间 | | messages | Message[] | ✅ | 消息数组(见 Message 结构) | **示例数据:** ```json { "id": "85ce1273-7279-44fb-b018-3e49295c89f7", "userId": "user-admin-001", "sceneId": "Custom", "roomId": "4fea87af-5b23-445d-9754-d4d878a1c705", "startedAt": "2026-04-02T05:06:57.828Z", "endedAt": "2026-04-02T05:07:18.750Z", "createdAt": "2026-04-02T05:07:28.729Z", "messages": [...] } ``` --- ### Message(消息子文档) > 嵌套在 Conversation.messages 数组中 | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | role | string | ✅ | `"user"`(用户说)或 `"assistant"`(AI 说) | | content | string | ✅ | 消息文本内容 | | createdAt | string | ✅ | 消息时间 ISO8601 | **示例:** ```json [ { "role": "assistant", "content": "你好,我是小块,有什么需要帮忙的吗?", "createdAt": "2026-04-02T05:06:57.828Z" }, { "role": "user", "content": "今天办公室出勤情况咋样", "createdAt": "2026-04-02T05:07:12.023Z" }, { "role": "assistant", "content": "今天办公室一共九个人,出勤率 90%。", "createdAt": "2026-04-02T05:07:18.750Z" } ] ``` --- ## 内部转发签名协议 > 转发到 Python 时,java-mock 会附加以下请求头,Python 侧需验证签名合法性。 | Header | 说明 | |---|---| | `X-Internal-Service` | 固定值 `java-gateway` | | `X-Internal-User-Id` | 当前登录用户 ID | | `X-Internal-Timestamp` | 毫秒级 Unix 时间戳(字符串) | | `X-Internal-Signature` | HMAC-SHA256 签名,见下方算法 | | `X-User-Name` | URL 编码的用户显示名 | | `X-User-Sex` | 性别字符串 | | `X-User-Is-Driver` | `"true"` 或 `"false"` | | `X-User-Dept-Id` | 部门 ID 字符串 | | `X-User-Dept-Name` | URL 编码的部门名称 | | `X-User-Role-List` | URL 编码的 JSON 数组字符串,如 `%5B%22admin%22%5D` | **签名算法:** ``` message = "java-gateway:{userId}:{timestamp}" signature = HMAC-SHA256(INTERNAL_SERVICE_SECRET, message) // hex 输出 ``` --- ## 通用错误响应 所有接口在出错时均返回如下结构: ```json { "code": , "message": "错误描述" } ``` | code | 含义 | |---|---| | 400 | 请求参数缺失或格式错误 | | 401 | 未登录或 Token 无效 / 过期 | | 403 | 无权限访问该资源 | | 404 | 资源不存在 | | 409 | 资源冲突(如用户名重复) | | 502 | 无法连接 Python 后端 | | 500 | 服务器内部错误 | --- ## 环境变量 | 变量名 | 默认值 | 说明 | |---|---|---| | `PORT` | `8080` | 服务监听端口 | | `JWT_SECRET` | — | JWT 签名密钥(**必填**) | | `JWT_EXPIRES_IN` | `7d` | JWT 过期时间 | | `PYTHON_BACKEND_URL` | `http://localhost:3001` | Python 后端地址 | | `INTERNAL_SERVICE_SECRET` | — | 内部签名密钥(**必填**) |