datai/datai-scenes/datai-scene-salesforce/docs/reference-code/data-dump/Attachment文件下载.md
Kris 2e6f087732 docs: 完成REQ-010-17和REQ-010-2的文档创建
- 完成REQ-010-17(性能优化和限流处理)的所有6个阶段
  - 创建ADR文档:0026-performance-optimization.md
  - 创建Prompt文档:027-performance-optimization.md
  - 创建会话记录:20260119-performance-optimization.md
  - 创建变更记录:20260119-performance-optimization.md
  - 创建复盘报告:20260119-performance-optimization-retro.md
  - 更新index.md和CHANGELOG.md

- 完成REQ-010-2(基础实体类和Mapper创建)的前3个阶段
  - 更新ADR文档:0011-entity-mapper-create.md
  - 创建Prompt文档:002-entity-mapper-create.md
  - 更新index.md

所有文档均按照SSOT方法论创建,包括需求定义、架构决策、提示词资产化、执行会话、变更记录和闭环复盘。
2026-01-19 10:06:09 +08:00

104 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

### 1. 准备工作 (Salesforce 端)
在开始写代码之前,你需要在 Salesforce 中创建一个 **Connected App** 以获取集成权限:
- **获取凭证:** 记录下 `ClientId`、`ClientSecret`、`Username` 和 `Password`(通常还需要 `Security Token`)。
- **权限范围 (Scopes)** 确保勾选了 `api``refresh_token, offline_access`
---
### 2. 核心实现流程
#### 第一步:获取 Access Token
使用 OAuth 2.0(推荐 Password 流或 JWT 流)获取访问令牌。
#### 第二步:查询 Attachment 信息
通过 SOQL 查询你需要下载的附件 ID。
SQL
```
SELECT Id, Name, Body, ContentType FROM Attachment WHERE Id = '00PXXXXXXXXXXXX'
```
> **注意:** 在 REST API 中,`Body` 字段返回的不是 Base64 字符串,而是一个**指向文件内容的相对路径**(例如:`/services/data/v58.0/sobjects/Attachment/00P.../Body`)。
#### 第三步:请求二进制流并保存
使用获取到的 `Body` 路径发送 GET 请求,并将响应流写入本地文件。
---
### 3. Java 代码实现示例
这里使用 Java 11+ 自带的 `HttpClient` 演示核心逻辑。
Java
```
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class SalesforceFileDownloader {
private static final String INSTANCE_URL = "https://your-instance.my.salesforce.com";
private static final String ACCESS_TOKEN = "YOUR_ACCESS_TOKEN";
public void downloadAttachment(String attachmentId, String savePath) throws Exception {
// 1. 构建附件 Body 的 URL
// 注意:可以通过先查询获取具体的 Body URL或者直接拼接
String endpoint = INSTANCE_URL + "/services/data/v58.0/sobjects/Attachment/" + attachmentId + "/Body";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(endpoint))
.header("Authorization", "Bearer " + ACCESS_TOKEN)
.GET()
.build();
// 2. 发送请求并处理响应流
HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
if (response.statusCode() == 200) {
try (InputStream is = response.body();
FileOutputStream fos = new FileOutputStream(savePath)) {
byte[] buffer = new byte[8192];
int read;
while ((read = is.read(buffer)) != -1) {
fos.write(buffer, 0, read);
}
System.out.println("文件下载成功,保存至: " + savePath);
}
} else {
System.err.println("下载失败,状态码: " + response.statusCode());
}
}
}
```
---
### 4. 关键技术细节与优化
|**维度**|**解决方案**|
|---|---|
|**内存管理**|**务必使用流 (InputStream)** 读写。避免将整个文件读入字节数组,防止大文件导致 `OutOfMemoryError`。|
|**现代替代方案**|如果可能,建议检查你的系统是否在使用 **Salesforce Files (ContentVersion)**。`Attachment` 是旧版对象,现代开发通常推荐使用 `ContentVersion`。|
|**大批量下载**|考虑到 Salesforce 的 API 调用限制 (Limits),如果需要批量下载,建议先通过查询获取列表,再使用线程池并发处理。|
|**安全性**|生产环境建议使用 **JWT Bearer Token** 认证,避免在代码中明文存储用户密码。|
---
### 5. 常见问题
- **URL 拼接:** 如果你通过查询 API 得到了 `Body` 字段的值,它通常是 `/services/data/...` 这种相对路径,你需要手动加上 `Instance URL` 前缀。
- **权限报错:** 如果报 403 错误,请检查该集成用户是否拥有对应记录的查看权限。