1. 概述

本教程将介绍如何使用 JetS3t 库与 Amazon S3 交互。我们将完成以下核心操作:

  • 创建存储桶(Bucket)
  • 写入数据
  • 读取数据
  • 复制数据
  • 列表与删除操作

2. JetS3t 环境搭建

2.1 Maven 依赖

首先在 pom.xml 中添加 JetS3t 和 Apache HttpClient 依赖:

<dependency>
    <groupId>org.lucee</groupId>
    <artifactId>jets3t</artifactId>
    <version>0.9.4.0014L</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>

✅ 最新版本可在 Maven Central 获取
✅ 源码托管在 SourceForge

测试时需要 Apache Commons Codec,额外添加:

<dependency>
    <groupId>org.lucee</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.10.L001</version>
</dependency>

2.2 AWS 密钥配置

连接 S3 需要有效的 AWS 访问密钥

  1. 注册 免费 AWS 账户
  2. 创建安全密钥对(参考官方文档

⚠️ JetS3t 使用 Apache Commons Logging,建议统一日志框架

3. 连接存储服务

3.1 建立 AWS 连接

使用密钥创建连接:

AWSCredentials awsCredentials 
  = new AWSCredentials("your-access-key", "your-secret-key");
s3Service = new RestS3Service(awsCredentials);

RestS3Service 是核心连接类,通过 REST 协议与 S3 通信。

3.2 验证连接有效性

通过列出所有存储桶验证连接:

S3Bucket[] myBuckets = s3Service.listAllBuckets();

✅ 无异常抛出即表示连接成功
❌ 数组可能为空(首次使用无存储桶)

4. 存储桶管理

S3 是对象存储系统,数据以对象形式存储在存储桶中。所有 S3 存储桶共享全局命名空间,名称必须全局唯一

4.1 创建存储桶

尝试创建名为 mybucket 的存储桶:

S3Bucket bucket = s3Service.createBucket("mybucket");

❌ 会抛出异常(名称已被占用):

org.jets3t.service.S3ServiceException: Service Error Message.
  -- ResponseCode: 409, ResponseStatus: Conflict
  <code>BucketAlreadyExists</code> 
  The requested bucket name is not available.

改用唯一名称重试:

S3Bucket bucket = s3Service.createBucket("myuniquename");
log.info(bucket);

成功时输出:

[INFO] JetS3tClient - S3Bucket
[name=myuniquename,location=US,creationDate=Sat Mar 31 16:47:47 EDT 2018,owner=null]

4.2 删除存储桶

删除前必须清空存储桶

s3Service.deleteBucket("myuniquename");

❌ 非空存储桶会抛出异常

4.3 指定存储桶区域

默认区域为美国弗吉尼亚北部(us-east-1),可指定其他区域:

S3Bucket euBucket 
  = s3Service.createBucket("eu-bucket", S3Bucket.LOCATION_EUROPE);
S3Bucket usWestBucket = s3Service
  .createBucket("us-west-bucket", S3Bucket.LOCATION_US_WEST);
S3Bucket asiaPacificBucket = s3Service
  .createBucket("asia-pacific-bucket", S3Bucket.LOCATION_ASIA_PACIFIC);

✅ JetS3t 预定义了所有区域常量

5. 数据上传、下载与删除

存储桶创建后可添加对象。存储桶设计为长期持久化,无对象数量或大小限制

5.1 字符串数据

上传字符串数据:

S3Object stringObject = new S3Object("object name", "string object");
s3Service.putObject("myuniquebucket", stringObject);

✅ 对象名称仅需在桶内唯一(非全局唯一)
✅ JetS3t 自动设置 Content-Type: text/plain

获取对象元数据(不下载内容):

StorageObject objectDetailsOnly 
  = s3Service.getObjectDetails("myuniquebucket", "my string");
log.info("Content type: " + objectDetailsOnly.getContentType() 
  + " length: " + objectDetailsOnly.getContentLength());

输出:

[INFO] JetS3tClient - Content type: text/plain; charset=utf-8 length: 9

下载并验证数据:

S3Object downloadObject = 
  s3Service.getObject("myuniquebucket", "string object");
String downloadString = new BufferedReader(new InputStreamReader(
  object.getDataInputStream())).lines().collect(Collectors.joining("\n"));
 
assertTrue("string object".equals(downloadString));

5.2 文件数据

上传文件:

File file = new File("src/test/resources/test.jpg");
S3Object fileObject = new S3Object(file);
s3Service.putObject("myuniquebucket", fileObject);

✅ 对象名自动使用文件基名(如 test.jpg
✅ JetS3t 自动检测 MIME 类型(需 mime.types 文件)

获取文件元数据:

[INFO] JetS3tClient - Content type: application/octet-stream

下载并校验文件完整性:

String getFileMD5(String filename) throws IOException {
    try (FileInputStream fis = new FileInputStream(new File(filename))) {
        return DigestUtils.md5Hex(fis);
    }
}

S3Object fileObject = s3Service.getObject("myuniquebucket", "test.jpg"); 
File newFile = new File("/tmp/newtest.jpg"); 
Files.copy(fileObject.getDataInputStream(), newFile.toPath(), 
  StandardCopyOption.REPLACE_EXISTING);
String origMD5 = getFileMD5("src/test/resources/test.jpg");
String newMD5 = getFileMD5("src/test/resources/newtest.jpg");
assertTrue(origMD5.equals(newMD5));

5.3 流式数据

非字符串/文件类型需手动设置元数据

ArrayList<Integer> numbers = new ArrayList<>();
// 添加数据到列表...

ByteArrayOutputStream bytes = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(bytes);
objectOutputStream.writeObject(numbers);

ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes.toByteArray());

S3Object streamObject = new S3Object("stream");
streamObject.setDataInputStream(byteArrayInputStream);
streamObject.setContentLength(byteArrayInputStream.available());
streamObject.setContentType("binary/octet-stream");

s3Service.putObject(BucketName, streamObject);

⚠️ 必须显式设置 Content-TypeContent-Length

下载流数据并反序列化:

S3Object newStreamObject = s3Service.getObject(BucketName, "stream");

ObjectInputStream objectInputStream = new ObjectInputStream(
  newStreamObject.getDataInputStream());
ArrayList<Integer> newNumbers = (ArrayList<Integer>) objectInputStream
  .readObject();

assertEquals(2, (int) newNumbers.get(0));
assertEquals(3, (int) newNumbers.get(1));
assertEquals(5, (int) newNumbers.get(2));
assertEquals(7, (int) newNumbers.get(3));

6. 数据复制、移动与重命名

6.1 复制对象

可直接在 S3 内部复制对象(无需下载)

S3Object targetObject = new S3Object("testcopy.jpg");
s3Service.copyObject(
  BucketName, "test.jpg", 
  "myuniquebucket", targetObject, false);

// 验证复制结果
S3Object newFileObject = s3Service.getObject(
  "myuniquebucket", "testcopy.jpg");
File newFile = new File("src/test/resources/testcopy.jpg");
Files.copy(
  newFileObject.getDataInputStream(), 
  newFile.toPath(), 
  REPLACE_EXISTING);
String origMD5 = getFileMD5("src/test/resources/test.jpg");
String newMD5 = getFileMD5("src/test/resources/testcopy.jpg");
assertTrue(origMD5.equals(newMD5));

✅ 支持同桶/跨桶复制
✅ 末尾参数控制是否更新元数据(false 保留源元数据)

更新元数据示例:

targetObject = new S3Object("testcopy.jpg");
targetObject.addMetadata("My_Custom_Field", "Hello, World!");
s3Service.copyObject(
  "myuniquebucket", "test.jpg", 
  "myuniquebucket", targetObject, true);

6.2 移动对象

移动 = 复制 + 删除(仅支持同区域):

s3Service.moveObject(
  "myuniquebucket",
  "test.jpg",
  "myotheruniquebucket",
  new S3Object("spidey.jpg"),
  false);

✅ 复制失败时不会删除源对象
✅ 删除失败时源/目标对象均存在

6.3 重命名对象

使用便捷方法重命名:

s3Service.renameObject(
  "myuniquebucket", "test.jpg", new S3Object("spidey.jpg"));

7. 总结

本教程演示了使用 JetS3t 操作 Amazon S3 的核心流程:

  1. 连接配置与认证
  2. 存储桶的创建/删除与区域管理
  3. 多种数据类型(字符串/文件/流)的上传下载
  4. 对象的复制、移动与重命名

✅ JetS3t 提供了简洁的 API 封装,大幅简化 S3 操作
⚠️ 注意全局命名空间和区域限制等特性


原始标题:Using the JetS3t Java Client With Amazon S3 | Baeldung