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

3.8 KiB
Raw Blame History

1. 准备工作 (Salesforce 端)

在开始写代码之前,你需要在 Salesforce 中创建一个 Connected App 以获取集成权限:

  • 获取凭证: 记录下 ClientIdClientSecretUsernamePassword(通常还需要 Security Token)。

  • 权限范围 (Scopes) 确保勾选了 apirefresh_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 错误,请检查该集成用户是否拥有对应记录的查看权限。