Spring Boot 与 Amazon S3:快速上传与下载文件的完整指南

2024-07-21 1172阅读

概要

在将 Spring Boot 更新到 3 系列时,由于 javax 需要被替换为 jakarta,因此原先依赖于 javax 的 spring-cloud-starter-aws1 将无法使用(虽然在我本地环境中仍然可以正常工作)。为了确保兼容性,我将依赖关系更改为 jakarta 的 io.awspring.cloud.spring-cloud-aws-starter,但由于信息较少,特此发布一个示例。

Spring Boot 与 Amazon S3:快速上传与下载文件的完整指南
(图片来源网络,侵删)

环境

  • Java 17
  • Spring Boot
    • spring-boot-starter-parent:3.2.6
    • spring-cloud-aws-dependencies:3.1.1
    • spring-cloud-aws-starter
    • spring-cloud-aws-starter-s3

    示例

    以下示例展示了如何将文件(对象)上传到 Amazon S3,并指定存储类为 Intelligent-Tiering。假设从本地环境上传时使用 Intelligent-Tiering,而在 EC2(服务器)环境中上传时使用 Standard(即不指定存储类时的默认值)。

    ※ 直接相关的部分将被省略。

    pom.xml

    虽然直接使用 AWS SDK For Java 也是一种选择,但本示例中我们将使用 spring-cloud-aws-starter。

        
            
                io.awspring.cloud
                spring-cloud-aws-dependencies
                3.1.1
                pom
                import
            
        
    
    
        
            io.awspring.cloud
            spring-cloud-aws-starter
        
        
            io.awspring.cloud
            spring-cloud-aws-starter-s3
        
    
    

    在 dependencyManagement 中指定 spring-cloud-aws-dependencies 可以统一管理版本。

    AwsStorageConfig.java

    为了在 Service 类中通过 Autowired 使用 S3Client,需要创建一个配置类并将其注册为 Bean。在 EC2 上可以通过 IAM Role 获取认证信息,但在本地环境中无法获取,因此需要显式指定认证信息。

     

    package com.tamorieeeen.sample.config;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Profile;
    import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
    import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
    import software.amazon.awssdk.regions.Region;
    import software.amazon.awssdk.services.s3.S3Client;
    /**
     *
     * @author rralucard
     *
     */
    @Configuration
    public class AwsStorageConfig {
        @Value("${spring.cloud.aws.credentials.access-key:unknown}")
        private String accessKey;
        @Value("${spring.cloud.aws.credentials.secret-key:unknown}")
        private String secretKey;
        @Value("${spring.cloud.aws.region.static:unknown}")
        private String region;
        /**
         * local用
         */
        @Bean("s3Client")
        @Profile("local")
        public S3Client s3ClientLocal() {
            StaticCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(
                    AwsBasicCredentials.create(accessKey, secretKey));
            return S3Client.builder()
                    .region(Region.of(region))
                    .credentialsProvider(credentialsProvider)
                    .build();
        }
        /**
         * EC2(server)用
         */
        @Bean("s3Client")
        @Profile("server")
        public S3Client s3Client() {
            return S3Client.create();
        }
    }
    

    application.yml

    本地使用的 application-local.yml 和 EC2(服务器)使用的 application-server.yml 的配置示例。

    本地环境:

    spring:
      cloud:
        aws:
          credentials:
            instance-profile: false
            access-key: SUMPLEACCESSKEY1234
            secret-key: SumpleSecretKey123456789
          stack.auto: false
          region:
            instance-profile: false
            static: ap-northeast-1
          s3:
            bucket: your-bucket-name
            storage-class: INTELLIGENT_TIERING
    

    EC2(Server)用

    spring:
      cloud:
        aws:
          credentials:
            instance-profile: true
            useDefaultAwsCredentialsChain: true
          stack.auto: false
          region:
            instance-profile: true
          s3:
            bucket: your-bucket-name
            storage-class: STANDARD
    

    AwsStorageService.java

    上传文件使用 MultipartFile 接收,下载时最终会将文件打包成 ResponseEntity 进行返回。

    package com.tamorieeeen.sample.service;
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.web.multipart.MultipartFile;
    import software.amazon.awssdk.core.ResponseInputStream;
    import software.amazon.awssdk.core.exception.SdkClientException;
    import software.amazon.awssdk.core.sync.RequestBody;
    import software.amazon.awssdk.services.s3.S3Client;
    import software.amazon.awssdk.services.s3.model.GetObjectRequest;
    import software.amazon.awssdk.services.s3.model.GetObjectResponse;
    import software.amazon.awssdk.services.s3.model.PutObjectRequest;
    /**
     *
     * @author rralucard
     *
     */
    @Service
    public class AwsStorageService {
        @Value("${spring.cloud.aws.s3.bucket}")
        private String bucket;
        @Value("${spring.cloud.aws.s3.storage-class}")
        private String storageClass;
        
        @Autowired
        private S3Client s3Client;
        /**
         * 向s3上传文件
         * @throws IOException
         * @throws SdkClientException
         */
        public void uploadFile(String s3Path, MultipartFile file) throws SdkClientException, IOException {
            PutObjectRequest putObjRequest = PutObjectRequest.builder()
                    .bucket(bucket)
                    .key(s3Path)
                    .storageClass(storageClass)
                    .contentType(file.getContentType())
                    .contentLength(file.getSize())
                    .build();
            byte[] bytes = file.getBytes();
            try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);) {
                s3Client.putObject(putObjRequest, RequestBody.fromInputStream(inputStream, bytes.length));
            }
        }
        /**
         * 从S3下载文件
         * @throws IOException
         */
        public byte[] download(String s3Path) throws IOException {
            GetObjectRequest getObjRequest = GetObjectRequest.builder()
                    .bucket(bucket)
                    .key(s3Path)
                    .build();
            try (ResponseInputStream resInputStream = s3Client.getObject(getObjRequest);) {
                return resInputStream.readAllBytes();
      
            }
        }
    }

    官方示例

    在解决问题后,我发现了AWS官方提供的示例代码。虽然资料很少,但这份官方样例实际上是AWS SDK for Java的代码示例。

    AWS事例

VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]