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

概要

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

环境

  • 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

XML 复制代码
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.awspring.cloud</groupId>
            <artifactId>spring-cloud-aws-dependencies</artifactId>
            <version>3.1.1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>io.awspring.cloud</groupId>
        <artifactId>spring-cloud-aws-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>io.awspring.cloud</groupId>
        <artifactId>spring-cloud-aws-starter-s3</artifactId>
    </dependency>
</dependencies>

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

AwsStorageConfig.java

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

java 复制代码
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 的配置示例。

本地环境:

javascript 复制代码
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)用

javascript 复制代码
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<byte[]> 进行返回。

java 复制代码
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<GetObjectResponse> resInputStream = s3Client.getObject(getObjRequest);) {
            return resInputStream.readAllBytes();
  
        }
    }
}

官方示例

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

AWS事例

相关推荐
Ylucius26 分钟前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
凡人的AI工具箱38 分钟前
AI教你学Python 第11天 : 局部变量与全局变量
开发语言·人工智能·后端·python
是店小二呀1 小时前
【C++】C++ STL探索:Priority Queue与仿函数的深入解析
开发语言·c++·后端
七夜zippoe1 小时前
分布式系统实战经验
java·分布式
canonical_entropy1 小时前
金蝶云苍穹的Extension与Nop平台的Delta的区别
后端·低代码·架构
是梦终空1 小时前
JAVA毕业设计176—基于Java+Springboot+vue3的交通旅游订票管理系统(源代码+数据库)
java·spring boot·vue·毕业设计·课程设计·源代码·交通订票
落落落sss1 小时前
sharding-jdbc分库分表
android·java·开发语言·数据库·servlet·oracle
码爸1 小时前
flink doris批量sink
java·前端·flink
我叫啥都行2 小时前
计算机基础知识复习9.7
运维·服务器·网络·笔记·后端
工业互联网专业2 小时前
毕业设计选题:基于springboot+vue+uniapp的驾校报名小程序
vue.js·spring boot·小程序·uni-app·毕业设计·源码·课程设计