当前位置:   article > 正文

Spring Boot 集成 AmazonS3 存储服务教程_amazons3clientbuilder

amazons3clientbuilder

参考文档:https://docs.ceph.com/en/latest/radosgw/s3/java/#download-an-object-to-a-file

环境准备

  1. Java环境:JDK6以上版本
  2. SpringBoot 2.2.5
  3. 存储服务的 accessKey、secreKey 以及 地址:端口

使用

1. 引入依赖

在 pom.xml 文件中添加下列依赖:

  1. <dependency>
  2. <groupId>com.amazonaws</groupId>
  3. <artifactId>aws-java-sdk</artifactId>
  4. <version>1.11.433</version>
  5. </dependency>

2. 初始化

> 简单模式

  1. String accessKey = "your-accesskey";
  2. String secretKey = "your-secretKey";
  3. AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
  4. AmazonS3 conn = AmazonS3ClientBuilder.standard()
  5. .withCredentials(new AWSStaticCredentialsProvider(credentials))
  6. .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration("endpoint","region"))
  7. .build();

示例:

  1. String accessKey = "TPDDEA5PCT9C8RUPKAWW";
  2. String secretKey = "ryesPMSiSfOzaP1TkFe9TIOBnxpdrA2sw6isFwDZ";
  3. AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
  4. AmazonS3 conn = AmazonS3ClientBuilder.standard()
  5. .withCredentials(new AWSStaticCredentialsProvider(credentials))
  6. .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration("http://10.200.100.37:7480","region"))
  7. .build();

> 配置模式

  1. import com.amazonaws.ClientConfiguration;
  2. import com.amazonaws.Protocol;
  3. import com.amazonaws.auth.AWSCredentials;
  4. import com.amazonaws.auth.AWSStaticCredentialsProvider;
  5. import com.amazonaws.auth.BasicAWSCredentials;
  6. import com.amazonaws.client.builder.AwsClientBuilder;
  7. import com.amazonaws.services.s3.AmazonS3;
  8. import com.amazonaws.services.s3.AmazonS3ClientBuilder;
  9. String accessKey = "your-accesskey";
  10. String secretKey = "your-secretKey ";
  11. AWSCredentials credentials = new BasicAWSCredentials(accessKey,secretKey);
  12. ClientConfiguration conf = new ClientConfiguration();
  13. // 设置AmazonS3使用的最大连接数
  14. conf.setMaxConnections(200);
  15. // 设置socket超时时间
  16. conf.setSocketTimeout(10000);
  17. // 设置失败请求重试次数
  18. conf.setMaxErrorRetry(2);
  19. // 如果要用https协议,请加上下面语句
  20. conf.setProtocol(Protocol.HTTPS);
  21. //AmazonS3 s3Client = new AmazonS3Client(credentials,clientConfiguration);
  22. //s3Client.setEndpoint(endPoint);
  23. AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
  24. .withCredentials(new AWSStaticCredentialsProvider(credentials))
  25. .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration("endpoint","region"))
  26. .withClientConfiguration(conf)
  27. .build();//endpoint,region请指定为NOS支持的

示例:

Amazon3 是线程安全的,因此可以将其注入到 Spring 容器中进行管理。

@AmazonS3Config.java

  1. import com.amazonaws.ClientConfiguration;
  2. import com.amazonaws.Protocol;
  3. import com.amazonaws.auth.AWSCredentials;
  4. import com.amazonaws.auth.AWSStaticCredentialsProvider;
  5. import com.amazonaws.auth.BasicAWSCredentials;
  6. import com.amazonaws.client.builder.AwsClientBuilder;
  7. import com.amazonaws.services.s3.AmazonS3;
  8. import com.amazonaws.services.s3.AmazonS3ClientBuilder;
  9. import com.amazonaws.services.s3.model.CreateBucketRequest;
  10. import com.amazonaws.services.s3.transfer.TransferManager;
  11. import com.amazonaws.services.s3.transfer.TransferManagerBuilder;
  12. import org.springframework.beans.factory.annotation.Autowired;
  13. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  14. import org.springframework.context.annotation.Bean;
  15. import org.springframework.context.annotation.Configuration;
  16. /**
  17. * @Author: ChangXuan
  18. * @Decription: 初始化AmazonS3实例
  19. * @Date: 17:33 2020/6/3
  20. **/
  21. @Configuration
  22. @EnableConfigurationProperties(UploadConfig.class)
  23. public class AmazonS3Config {
  24. @Autowired
  25. private UploadConfig uploadConfig;
  26. @Bean(name = "amazonS3")
  27. public AmazonS3 getAmazonS3(){
  28. String accessKey = uploadConfig.getCeph().getAccessKey();
  29. String secretKey = uploadConfig.getCeph().getSecretKey();
  30. AWSCredentials credentials = new BasicAWSCredentials(accessKey,secretKey);
  31. ClientConfiguration conf = new ClientConfiguration();
  32. // 设置AmazonS3使用的最大连接数
  33. conf.setMaxConnections(uploadConfig.getCeph().getAmazonS3MaxConnections());
  34. // 设置socket超时时间
  35. conf.setSocketTimeout(uploadConfig.getCeph().getAmazonS3SocketTimeout());
  36. // 设置失败请求重试次数
  37. conf.setMaxErrorRetry(uploadConfig.getCeph().getAmazonS3MaxErrorRetry());
  38. // 设置协议
  39. if (!"blank".equals(uploadConfig.getCeph().getAmazonS3Protocol())){
  40. switch (uploadConfig.getCeph().getAmazonS3Protocol()){
  41. case "https":
  42. conf.setProtocol(Protocol.HTTPS);
  43. break;
  44. case "http":
  45. conf.setProtocol(Protocol.HTTP);
  46. break;
  47. default:
  48. break;
  49. }
  50. }
  51. AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
  52. .withCredentials(new AWSStaticCredentialsProvider(credentials))
  53. .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(uploadConfig.getCeph().getHosts().get(0),uploadConfig.getCeph().getRegion()))
  54. .withClientConfiguration(conf)
  55. .build();
  56. checkAndCreateBucket(s3Client);
  57. return s3Client;
  58. }
  59. @Bean(name = "transferManager")
  60. public TransferManager getTransferManager(){
  61. return TransferManagerBuilder.standard().withS3Client(getAmazonS3()).build();
  62. }
  63. /**
  64. * 检查桶是否存在,不存在则创建创建
  65. * @param s3Client
  66. */
  67. private void checkAndCreateBucket(AmazonS3 s3Client){
  68. boolean exists = s3Client.doesBucketExistV2(uploadConfig.getCeph().getBucketName());
  69. if (!exists){
  70. CreateBucketRequest request = new CreateBucketRequest(uploadConfig.getCeph().getBucketName());
  71. s3Client.createBucket(request);
  72. }
  73. }

@UploadConfig.java

  1. import lombok.Data;
  2. import org.springframework.boot.context.properties.ConfigurationProperties;
  3. /**
  4. * @Author: ChangXuan
  5. * @Decription: 上传 配置
  6. * @Date: 17:25 2020/6/3
  7. **/
  8. @ConfigurationProperties(prefix = "upload")
  9. @Data
  10. public class UploadConfig {
  11. private CephConfig ceph;
  12. }

@CephConfig.java

  1. import com.google.common.collect.Lists;
  2. import lombok.Data;
  3. import java.util.List;
  4. /**
  5. * @Author: ChangXuan
  6. * @Decription:配置
  7. * @Date: 17:28 2020/6/3
  8. **/
  9. @Data
  10. public class CephConfig {
  11. /**
  12. * 集群ip:port
  13. */
  14. private List<String> hosts = Lists.newArrayList();
  15. private String accessKey;
  16. private String secretKey;
  17. private String region;
  18. /**
  19. * 连接协议
  20. */
  21. private String amazonS3Protocol;
  22. /**
  23. * 失败请求重试次数
  24. */
  25. private Integer amazonS3MaxErrorRetry;
  26. /**
  27. * 超时时间
  28. */
  29. private Integer amazonS3SocketTimeout;
  30. /**
  31. * 最大连接数
  32. */
  33. private Integer amazonS3MaxConnections;
  34. /**
  35. * 桶名称
  36. */
  37. private String bucketName;
  38. }

@application.yml

  1. upload:
  2. ceph:
  3. bucketName: ic-storage-dev
  4. region: region
  5. hosts:
  6. - "10.200.100.37:7480"
  7. - "10.200.100.38:7480"
  8. - "10.200.100.39:7480"
  9. accessKey: TPDDEA5PCT9C8RUPKAWW
  10. secretKey: ryesPMSiSfOzaP1TkFe9TIWQnxpdrA2sw6isFwDZ
  11. amazonS3MaxConnections: 200
  12. amazonS3SocketTimeout: 10000
  13. amazonS3MaxErrorRetry: 2
  14. amazonS3Protocol: http

3. 依赖注入

  1. @Autowired
  2. private AmazonS3 amazonS3;
  3. //或
  4. @Autowired
  5. private TransferManager transferManager;

4. 文件操作

文件上传

1. 直接内容上传

  1. //要上传文件内容
  2. String content = "Object content";
  3. try {
  4. amazonS3.putObject("your-bucketname","your-objectname",content);
  5. }catch (Exception e){
  6. System.out.println(e.getMessage());
  7. }

2. 本地文件普通上传

对于小对象可以使用putObject接口进行上传,putObject上传支持的最大文件大小为100M,如果上传大于100M的文件需要使用分块上传。本地文件普通上传的示例代码如下:

  1. //要上传文件的路径
  2. String filePath = "your-local-file-path";
  3. try {
  4. amazonS3.putObject("your-bucketname","your-objectname", new File(filePath));
  5. }catch (Exception e){
  6. System.out.println(e.getMessage());
  7. }

3. 上传文件时设置文件元数据信息

  1. String filePath = "your-local-file-path";
  2. ObjectMetadata objectMetadata = new ObjectMetadata();
  3. //设置Content-Type
  4. objectMetadata.setContentType("application/xml");
  5. //设置标准http消息头(元数据)
  6. objectMetadata.setHeader("Cache-Control", "no-cache");
  7. //设置用户自定义元数据信息
  8. Map<String, String> userMeta = new HashMap<String, String>();
  9. userMeta.put("ud", "test");
  10. objectMetadata.setUserMetadata(userMeta);
  11. PutObjectRequest putObjectRequest = new PutObjectRequest("your-bucketname","your-objectname", new File(filePath));
  12. putObjectRequest.setMetadata(objectMetadata);
  13. amazonS3.putObject(putObjectRequest);

4. 流式上传

  1. try {
  2. ObjectMetadata objectMetadata = new ObjectMetadata();
  3. //设置流的长度,您还可以设置其他文件元数据信息
  4. objectMetadata.setContentLength(streamLength);
  5. amazonS3.putObject("your-bucketname","your-objectname", inputStream, objectMetadata)
  6. }catch (Exception e){
  7. System.out.println(e.getMessage());
  8. }

文件下载

1. 流式下载

  1. S3Object fileObject = amazonS3.getObject("your-bucketname","your-objectname");
  2. //可以通过getObjectMetadata方法获取对象的ContentType等元数据信息
  3. String contentType = fileObject.getObjectMetadata().getContentType();
  4. //流式获取文件内容
  5. InputStream in = fileObject.getObjectContent();
  6. BufferedReader reader = new BufferedReader(new InputStreamReader(in));
  7. while (true) {
  8. String line;
  9. try {
  10. line = reader.readLine();
  11. if (line == null) break;
  12. System.out.println("\n" + line);
  13. } catch (IOException e) {
  14. e.printStackTrace();
  15. }
  16. }
  17. try {
  18. reader.close();
  19. } catch (IOException e) {
  20. e.printStackTrace();
  21. }

2. 下载到本地文件

  1. String destinationFile = "your-local-filepath";
  2. GetObjectRequest getObjectRequest = new GetObjectRequest("your-bucketname","your-objectname");
  3. ObjectMetadata objectMetadata = amazonS3.getObject(getObjectRequest, new File(destinationFile));

3. Range 下载

  1. GetObjectRequest getObjectRequest = new GetObjectRequest("your-bucketname","your-objectname");
  2. getObjectRequest.setRange(0, 100);
  3. S3Object nosObject = amazonS3.getObject(getObjectRequest);
  4. BufferedReader reader = new BufferedReader(new InputStreamReader(in));
  5. while (true) {
  6. String line;
  7. try {
  8. line = reader.readLine();
  9. if (line == null) break;
  10. System.out.println("\n" + line);
  11. } catch (IOException e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. try {
  16. reader.close();
  17. } catch (IOException e) {
  18. e.printStackTrace();
  19. }

文件管理

判断文件是否存在

您可以通过AmazonS3.doesObjectExist判断文件是否存在。

boolean isExist = amazonS3.doesObjectExist("your-bucketname","your-objectname");

文件删除

您可以通过AmazonS3.deleteObject删除单个文件

amazonS3.deleteObject("your-bucketname","your-objectname");

您还可以通过AmazonS3.deleteObjects一次删除多个文件

  1. try {
  2. DeleteObjectsResult result = amazonS3.deleteObjects(deleteObjectsRequest);
  3. List<DeletedObject> deleteObjects = result.getDeletedObjects();
  4. //print the delete results
  5. for (DeletedObject items: deleteObjects){
  6. System.out.println(items.getKey());
  7. }
  8. // 部分对象删除失败
  9. } catch (MultiObjectDeleteException e) {
  10. List<DeleteError> deleteErrors = e.getErrors();
  11. for (DeleteError error : deleteErrors) {
  12. System.out.println(error.getKey());
  13. }
  14. } catch (AmazonServiceException e) {
  15. //捕捉服务器异常错误
  16. } catch (AmazonClientException ace) {
  17. //捕捉客户端错误
  18. }

获取文件元数据信息

您可以通过AmazonS3.getObjectMetadata获取文件元数据信息

amazonS3.getObjectMetadata("your-bucketname","your-objectname");

文件复制(copy)

您可以通过AmazonS3.copyObject接口实现文件拷贝功能。

amazonS3.copyObject("source-bucket", "source-object", "dst-bucket", "dst-object");

列举桶内文件

您可以通过AmazonS3.listObjects列出桶里的文件。listObjects接口如果调用成功,会返回一个ObjectListing对象,列举的结果保持在该对象中。

ObjectListing的具体信息如下表所示:

方法含义
List getObjectSummaries()返回的文件列表(包含文件的名称、Etag的元数据信息)
String getPrefix()本次查询的文件名前缀
String getDelimiter()文件分界符
String getMarker()这次List Objects的起点
int getMaxKeys()响应请求内返回结果的最大数目
String getNextMarker()下一次List Object的起点
boolean isTruncated()是否截断,如果因为设置了limit导致不是所有的数据集都返回,则该值设置为true
List getCommonPrefixes()如果请求中指定了delimiter参数,则返回的包含CommonPrefixes元素。该元素标明以delimiter结尾,并有共同前缀的对象的集合

AmazonS3.listObjects接口提供两种调用方式:简单列举、通过ListObjectsRequest列举

简单列举

简单列举只需指定需要列举的桶名,最多返回100条对象记录,建议桶内对象数较少时(小于100)使用。

  1. ObjectListing objectListing = amazonS3.listObjects("your-bucketname");
  2. List<S3ObjectSummary> sums = objectListing.getObjectSummaries();
  3. for (S3ObjectSummary s : sums) {
  4. System.out.println("\t" + s.getKey());
  5. }

通过ListObjectsRequest列举

您还可以通过设置ListObjectsReques参数实现各种灵活的查询功能。ListObjectsReques的可设置的参数如下:

设置方法作用
setPrefix(String prefix)限定返回的object key必须以prefix作为前缀
setDelimiter(String delimiter)是一个用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter字符之间的object作为一组元素——CommonPrefixes
setMarker(String marker)字典序的起始标记,只列出该标记之后的部分
setMaxKeys(Integer maxKeys)限定返回的数量,返回的结果小于或等于该值(默认值为100)

1、分页列举桶内的所有文件:

  1. List<S3ObjectSummary> listResult = new ArrayList<S3ObjectSummary>();
  2. ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
  3. listObjectsRequest.setBucketName("your-bucketname");
  4. listObjectsRequest.setMaxKeys(50);
  5. ObjectListing listObjects = amazonS3.listObjects(listObjectsRequest);
  6. do {
  7. listResult.addAll(listObjects.getObjectSummaries());
  8. if (listObjects.isTruncated()) {
  9. ListObjectsRequest request = new ListObjectsRequest();
  10. request.setBucketName(listObjectsRequest.getBucketName());
  11. request.setMarker(listObjects.getNextMarker());
  12. listObjects = amazonS3.listObjects(request);
  13. } else {
  14. break;
  15. }
  16. } while (listObjects != null);

2、使用Delimiter模拟文件夹功能

假设桶内有如下对象:a/1.jpg、a/2.jpg、a/b/1.txt、a/b/2.txt,列举a文件夹下的文件及子文件夹的示例代码如下:

  1. ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
  2. listObjectsRequest.setBucketName("your-bucketname");
  3. listObjectsRequest.setDelimiter("/");
  4. listObjectsRequest.setPrefix("a/");
  5. ObjectListing listing = amazonS3.listObjects(listObjectsRequest);
  6. // 遍历所有Object
  7. System.out.println("Objects:");
  8. for (S3ObjectSummary objectSummary : listing.getObjectSummaries()) {
  9. System.out.println(objectSummary.getKey());
  10. }
  11. // 遍历所有CommonPrefix
  12. System.out.println("CommonPrefixs:");
  13. for (String commonPrefix : listing.getCommonPrefixes()) {
  14. System.out.println(commonPrefix);
  15. }

示例代码的输出如下:

Objects:

a/1.jpg

a/2.jpg

CommonPrefixs:

a/b/

生成私有对象可下载的URL链接

AWS Java SDK支持生成可下载私有对象的URL连接,您可以将该链接提供给第三方进行文件下载:

  1. GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, key);
  2. // 设置可下载URL的过期时间为1天后
  3. generatePresignedUrlRequest.setExpiration(new Date(System.currentTimeMillis()+3600*1000*24));
  4. URL url = amazonS3.generatePresignedUrl(generatePresignedUrlRequest);//生成URL
  5. System.out.println(url);//可以用这个url来下载文件

文件上传下载工具类 TransferManager

前文提到的是 Java SDK提供的基础接口,为方便用户进行文件上传下载,Java SDK提供了封装更好、使用更方便的工具类:TransferManager。

TransferManager的初始化

注:在 SpringBoot 项目中 TransferManager 的初始化 参考上述 [配置模式](#### 配置模式)

  1. //先实例化一个AmazonS3
  2. String accessKey = "your-accesskey";
  3. String secretKey = "your-secretKey ";
  4. Credentials credentials = new BasicCredentials(accessKey, secretKey);
  5. AmazonS3 amazonS3 = new AmazonS3(credentials);
  6. amazonS3.setEndpoint(endPoint);
  7. //然后通过AmazonS3对象来初始化TransferManager
  8. TransferManager transferManager = new TransferManager(amazonS3);
  9. Download download = transferManager.download(TestConfig.bucketName,key,new File("localFilePath"));
  10. try {
  11. download.waitForCompletion();
  12. } catch (InterruptedException e) {
  13. e.printStackTrace();
  14. }

使用TransferManager进行文件上传

TransferManager会根据文件大小,选择是否进行分块上传。当文件小于等于16M时,TransferManager会自动调用PutObject接口,否则TransferManager会自动对文件进行分块上传。

1、上传本地文件:

如果指定上传的本地文件大于16M,TransferManager会自动对文件进行分块,并发调用分块上传接口进行上传,大大提高上传文件的速度。

  1. //上传文件
  2. Upload upload = transferManager.upload("your-bucketname", "your-objectname", new File("your-file"));
  3. try {
  4. upload.waitForUploadResult();
  5. } catch (InterruptedException e) {
  6. e.printStackTrace();
  7. }

2、流式上传:

您也可以使用TransferManager进行流式上传,但是相比本地文件上传,流式上传无法做到多个分块并发上传,只能一个分块一个分块顺序上传。

  1. //流式上传文件
  2. ObjectMetadata objectMetadata = new ObjectMetadata();
  3. objectMetadata.setContentLength(file.length());
  4. Upload upload = transferManager.upload("your-bucketname", "your-objectname", inputStream, objectMetadata);
  5. UploadResult result = upload.waitForUploadResult();

3、上传目录

您可以使用TransferManager将某个目录下的文件全部上传到NOS,对象名即文件名

  • 3.1 不支持多级目录
  1. MultipleFileUpload result = transferManager.uploadDirectory("your-buckename", null, new File("dirPath"), false);
  2. result.waitForCompletion();
  • 3.2 支持多级目录,会递归的上传目录下的所有文件
  1. MultipleFileUpload result = transferManager.uploadDirectory("your-buckename", null, new File("dirPath"), true);
  2. result.waitForCompletion();

4、下载文件

  1. File file = new File("your-destFile");
  2. Download download = transferManager.download("your-bucketname", "your-objectname", file);
  3. download.waitForCompletion();

参考资料

[1] 网易数帆S3 Java SDK 手册

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/285742
推荐阅读
相关标签
  

闽ICP备14008679号