# API 文档 - 检索操作 ## 元数据 - 需求编号:003-06 - 创建时间:2026-02-06 - 创建人:AI Assistant - 状态:已完成 - 版本:v1.0.0 ## API 概述 本文档描述了 Salesforce Metadata API 检索操作相关的 REST API 接口,包括元数据检索请求提交、状态轮询、状态检查和历史查询功能。 ### 核心功能 1. **提交检索请求**:向 Salesforce 提交元数据检索请求,返回异步操作 ID 2. **轮询检索状态**:循环检查检索状态直到完成或超时 3. **单次状态检查**:单次检查检索状态,返回当前状态 4. **检索历史查询**:查询检索操作的历史记录 5. **检索记录查询**:根据 asyncId 查询具体的检索记录 ### 技术栈 - Spring Boot 2.7.x - Spring Security(权限控制) - MyBatis Plus(数据持久化) - Salesforce Metadata API ### 基础路径 ``` /salesforce/metadata/retrieve ``` ## 接口列表 ### 接口 1:提交检索请求 #### 功能描述 向 Salesforce 提交元数据检索请求。检索操作是异步的,提交后会立即返回一个异步操作 ID(asyncId),客户端需要使用这个 ID 轮询检索状态或查询结果。 #### 请求方式 `POST` #### 请求路径 ``` /salesforce/metadata/retrieve ``` #### 权限要求 - 权限标识:`salesforce:metadata:retrieve` - 使用 `@PreAuthorize("@ss.hasPermi('salesforce:metadata:retrieve')")` 控制 #### 请求参数 ##### 请求体参数(JSON) | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | apiVersion | Double | 是 | API 版本 | `59.0` | | singlePackage | Boolean | 否 | 是否为单个包,默认 false | `false` | | unpackaged | Object | 条件 | 未打包的元数据类型列表(与 packageNames 二选一) | 见下方示例 | | packageNames | String[] | 条件 | 包名称列表(与 unpackaged 二选一) | `["MyPackage"]` | | specificFiles | String[] | 否 | 特定文件列表 | `["package.xml"]` | ##### Unpackaged 对象结构 | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | types | Array | 是 | 元数据类型列表 | 见下方示例 | ##### PackageTypeMember 对象结构 | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | name | String | 是 | 元数据类型名称 | `"CustomObject"` | | members | String[] | 是 | 成员列表,`*` 表示所有 | `["*"]` | #### 请求示例 ##### 示例 1:检索所有 CustomObject ```json POST /salesforce/metadata/retrieve Content-Type: application/json { "apiVersion": 59.0, "singlePackage": false, "unpackaged": { "types": [ { "name": "CustomObject", "members": ["*"] } ] } } ``` ##### 示例 2:检索特定包 ```json POST /salesforce/metadata/retrieve Content-Type: application/json { "apiVersion": 59.0, "singlePackage": true, "packageNames": ["MyManagedPackage"] } ``` ##### 示例 3:检索多种元数据类型 ```json POST /salesforce/metadata/retrieve Content-Type: application/json { "apiVersion": 59.0, "unpackaged": { "types": [ { "name": "CustomObject", "members": ["Account", "Contact"] }, { "name": "ApexClass", "members": ["MyClass", "MyTestClass"] }, { "name": "ApexTrigger", "members": ["*"] } ] } } ``` #### 响应参数 ##### 成功响应(HTTP 200) | 参数名 | 类型 | 说明 | 示例 | |--------|------|------|------| | code | Integer | 状态码,200 表示成功 | `200` | | msg | String | 提示信息 | `"操作成功"` | | data | Object | 异步结果对象 | 见下方说明 | ##### AsyncResult 对象 | 参数名 | 类型 | 说明 | 示例 | |--------|------|------|------| | id | String | 异步操作 ID | `"09Sxx0000000001EAA"` | | done | Boolean | 是否完成 | `false` | | state | String | 状态(Queued、InProgress、Completed、Error) | `"Queued"` | #### 成功响应示例 ```json { "code": 200, "msg": "操作成功", "data": { "id": "09Sxx0000000001EAA", "done": false, "state": "Queued" } } ``` #### 错误响应示例 ```json { "code": 500, "msg": "检索元数据失败: 连接超时", "data": null } ``` --- ### 接口 2:轮询检索状态 #### 功能描述 轮询检索状态直到完成或超时。此接口会循环检查检索状态,直到检索完成(成功或失败)或达到超时时间。适用于需要等待检索完成的场景。 #### 请求方式 `GET` #### 请求路径 ``` /salesforce/metadata/retrieve/status/{asyncId} ``` #### 权限要求 - 权限标识:`salesforce:metadata:retrieve` #### 请求参数 ##### 路径参数 | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | asyncId | String | 是 | 异步操作 ID | `"09Sxx0000000001EAA"` | ##### 查询参数 | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | interval | Long | 否 | 轮询间隔(毫秒),默认 5000 | `5000` | | timeout | Long | 否 | 超时时间(毫秒),默认 300000(5分钟) | `300000` | #### 请求示例 ``` GET /salesforce/metadata/retrieve/status/09Sxx0000000001EAA?interval=5000&timeout=300000 ``` #### 响应参数 ##### 成功响应(HTTP 200) | 参数名 | 类型 | 说明 | 示例 | |--------|------|------|------| | code | Integer | 状态码,200 表示成功 | `200` | | msg | String | 提示信息 | `"操作成功"` | | data | Object | 检索结果对象 | 见下方说明 | ##### RetrieveResultVo 对象 | 参数名 | 类型 | 说明 | 示例 | |--------|------|------|------| | asyncId | String | 异步操作 ID | `"09Sxx0000000001EAA"` | | status | String | 检索状态 | `"Succeeded"` | | success | Boolean | 是否成功 | `true` | | zipFile | String | ZIP 文件数据(Base64 编码) | `"UEsDBBQ..."` | | errorMessage | String | 错误消息(失败时) | `null` | | messages | Array | 检索消息列表 | 见下方说明 | | completedTime | Date | 完成时间 | `"2026-02-06T10:30:00"` | | done | Boolean | 是否完成 | `true` | ##### RetrieveMessageVo 对象 | 参数名 | 类型 | 说明 | 示例 | |--------|------|------|------| | fileName | String | 文件名 | `"objects/Account.object"` | | problem | String | 问题描述 | `"Entity is not found"` | | problemType | String | 问题类型 | `"Warning"` | #### 成功响应示例 ```json { "code": 200, "msg": "操作成功", "data": { "asyncId": "09Sxx0000000001EAA", "status": "Succeeded", "success": true, "zipFile": "UEsDBBQACAAI...", "errorMessage": null, "messages": [], "completedTime": "2026-02-06T10:30:00", "done": true } } ``` #### 超时响应示例 ```json { "code": 500, "msg": "检索操作超时", "data": null } ``` --- ### 接口 3:单次检查状态 #### 功能描述 单次检查检索状态,立即返回当前状态。适用于前端主动轮询的场景,由前端控制轮询间隔。 #### 请求方式 `GET` #### 请求路径 ``` /salesforce/metadata/retrieve/check/{asyncId} ``` #### 权限要求 - 权限标识:`salesforce:metadata:retrieve` #### 请求参数 ##### 路径参数 | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | asyncId | String | 是 | 异步操作 ID | `"09Sxx0000000001EAA"` | #### 请求示例 ``` GET /salesforce/metadata/retrieve/check/09Sxx0000000001EAA ``` #### 响应参数 ##### 成功响应(HTTP 200) 与"轮询检索状态"接口的响应参数相同,但只返回当前状态,不会等待完成。 #### 进行中响应示例 ```json { "code": 200, "msg": "操作成功", "data": { "asyncId": "09Sxx0000000001EAA", "status": "InProgress", "success": null, "zipFile": null, "errorMessage": null, "messages": [], "completedTime": null, "done": false } } ``` #### 已完成响应示例 ```json { "code": 200, "msg": "操作成功", "data": { "asyncId": "09Sxx0000000001EAA", "status": "Succeeded", "success": true, "zipFile": "UEsDBBQACAAI...", "errorMessage": null, "messages": [], "completedTime": "2026-02-06T10:30:00", "done": true } } ``` --- ### 接口 4:获取检索历史 #### 功能描述 获取检索操作的历史记录列表。返回最近的检索记录,支持限制返回数量。 #### 请求方式 `GET` #### 请求路径 ``` /salesforce/metadata/retrieve/history ``` #### 权限要求 - 权限标识:`salesforce:metadata:retrieve` #### 请求参数 ##### 查询参数 | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | limit | Integer | 否 | 返回数量限制,默认 50,最大 100 | `50` | #### 请求示例 ``` GET /salesforce/metadata/retrieve/history?limit=20 ``` #### 响应参数 ##### 成功响应(HTTP 200) | 参数名 | 类型 | 说明 | 示例 | |--------|------|------|------| | code | Integer | 状态码,200 表示成功 | `200` | | msg | String | 提示信息 | `"操作成功"` | | data | Array | 检索历史列表 | 见下方说明 | ##### DataiMetadataRetrieve 对象 | 参数名 | 类型 | 说明 | 示例 | |--------|------|------|------| | id | Long | 记录 ID | `1` | | asyncId | String | 异步操作 ID | `"09Sxx0000000001EAA"` | | status | String | 检索状态 | `"Succeeded"` | | done | Boolean | 是否完成 | `true` | | message | String | 消息 | `"Retrieve completed successfully"` | | errorMessage | String | 错误消息 | `null` | | retrieveTime | Date | 检索时间 | `"2026-02-06T10:30:00"` | | updateTime | Date | 更新时间 | `"2026-02-06T10:30:00"` | | userId | Long | 用户 ID | `1` | | createBy | String | 创建者 | `"admin"` | | createTime | Date | 创建时间 | `"2026-02-06T10:25:00"` | #### 成功响应示例 ```json { "code": 200, "msg": "操作成功", "data": [ { "id": 1, "asyncId": "09Sxx0000000001EAA", "status": "Succeeded", "done": true, "message": "Retrieve completed successfully", "errorMessage": null, "retrieveTime": "2026-02-06T10:30:00", "updateTime": "2026-02-06T10:30:00", "userId": 1, "createBy": "admin", "createTime": "2026-02-06T10:25:00" }, { "id": 2, "asyncId": "09Sxx0000000002EAA", "status": "Failed", "done": true, "message": null, "errorMessage": "Invalid API version", "retrieveTime": "2026-02-06T10:20:00", "updateTime": "2026-02-06T10:20:00", "userId": 1, "createBy": "admin", "createTime": "2026-02-06T10:15:00" } ] } ``` --- ### 接口 5:查询检索记录 #### 功能描述 根据 asyncId 查询具体的检索记录。用于获取某个特定检索操作的详细信息。 #### 请求方式 `GET` #### 请求路径 ``` /salesforce/metadata/retrieve/record/{asyncId} ``` #### 权限要求 - 权限标识:`salesforce:metadata:retrieve` #### 请求参数 ##### 路径参数 | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | asyncId | String | 是 | 异步操作 ID | `"09Sxx0000000001EAA"` | #### 请求示例 ``` GET /salesforce/metadata/retrieve/record/09Sxx0000000001EAA ``` #### 响应参数 ##### 成功响应(HTTP 200) 与"获取检索历史"接口中的单个对象结构相同。 #### 成功响应示例 ```json { "code": 200, "msg": "操作成功", "data": { "id": 1, "asyncId": "09Sxx0000000001EAA", "status": "Succeeded", "done": true, "message": "Retrieve completed successfully", "errorMessage": null, "retrieveTime": "2026-02-06T10:30:00", "updateTime": "2026-02-06T10:30:00", "userId": 1, "createBy": "admin", "createTime": "2026-02-06T10:25:00" } } ``` #### 记录不存在响应示例 ```json { "code": 200, "msg": "操作成功", "data": null } ``` --- ## 错误码 ### 业务错误码 | 错误码 | 说明 | 处理建议 | |--------|------|----------| | RETRIEVE_001 | 获取 MetadataConnection 失败 | 检查 Salesforce 连接配置 | | RETRIEVE_002 | 检索元数据操作失败 | 检查请求参数和 API 版本 | | RETRIEVE_003 | 检索操作超时 | 增加超时时间或稍后重试 | | RETRIEVE_004 | 检查检索状态失败 | 检查 asyncId 是否正确 | | RETRIEVE_005 | 获取检索历史失败 | 检查数据库连接 | | RETRIEVE_006 | 根据 asyncId 查询检索记录失败 | 检查 asyncId 是否正确 | | RETRIEVE_007 | 请求参数不能为空 | 检查请求体是否为空 | | RETRIEVE_008 | API 版本不能为空 | 检查 apiVersion 字段 | | RETRIEVE_009 | 未打包的元数据类型列表不能为空 | 检查 unpackaged.types 字段 | | RETRIEVE_010 | 检索元数据失败 | 查看详细错误信息 | ### HTTP 状态码 | 状态码 | 说明 | |--------|------| | 200 | 请求成功 | | 400 | 请求参数错误 | | 401 | 未授权,需要登录 | | 403 | 禁止访问,权限不足 | | 500 | 服务器内部错误 | --- ## 使用流程 ### 典型使用场景 1:简单检索并等待结果 ``` 1. 调用 POST /salesforce/metadata/retrieve 提交检索请求 2. 获取返回的 asyncId 3. 调用 GET /salesforce/metadata/retrieve/status/{asyncId} 轮询状态 4. 等待返回结果(包含 ZIP 文件 Base64 数据) 5. 前端解码 Base64 并下载 ZIP 文件 ``` ### 典型使用场景 2:前端主动轮询 ``` 1. 调用 POST /salesforce/metadata/retrieve 提交检索请求 2. 获取返回的 asyncId 3. 前端使用定时器,每隔 5 秒调用 GET /salesforce/metadata/retrieve/check/{asyncId} 4. 检查返回的 done 字段,为 true 时表示完成 5. 如果成功,获取 ZIP 文件数据;如果失败,显示错误信息 ``` ### 典型使用场景 3:查询历史记录 ``` 1. 调用 GET /salesforce/metadata/retrieve/history 获取检索历史列表 2. 用户选择某条历史记录 3. 调用 GET /salesforce/metadata/retrieve/record/{asyncId} 获取详细信息 4. 显示检索状态和结果 ``` --- ## 注意事项 ### 1. 异步操作特性 - 检索操作是异步的,提交请求后立即返回 asyncId - 需要使用 asyncId 轮询或查询状态 - 检索时间取决于元数据数量和复杂度,可能需要几秒到几分钟 ### 2. ZIP 文件处理 - ZIP 文件内容以 Base64 编码返回 - 不在数据库中存储 ZIP 文件内容 - 对于大文件,建议设置合理的超时时间 ### 3. 超时控制 - 轮询接口默认超时时间为 5 分钟 - 可以通过 timeout 参数调整超时时间 - 超时后会抛出异常,需要客户端处理 ### 4. 权限控制 - 所有接口都需要 `salesforce:metadata:retrieve` 权限 - 使用 Spring Security 的 `@PreAuthorize` 注解控制 - 确保用户有权限访问目标 Salesforce 组织的元数据 --- ## 相关文档 - [需求文档](../requirements/sub/2026-01-28-003-06-检索操作.md) - [设计文档](../design/2026-02-03-003-06-检索操作-设计.md) - [决策记录](../decisions/2026-02-03-003-06-ADR-检索操作技术选型.md) - [变更日志](../changelog/2026-02-06-003-06-changelog.md) - [复盘文档](../retros/2026-02-06-003-06-retro.md) - [会话记录](../sessions/2026-02-03-003-06-session.md)