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事例

相关推荐
DuelCode1 分钟前
Windows VMWare Centos Docker部署Springboot 应用实现文件上传返回文件http链接
java·spring boot·mysql·nginx·docker·centos·mybatis
优创学社25 分钟前
基于springboot的社区生鲜团购系统
java·spring boot·后端
why技术9 分钟前
Stack Overflow,轰然倒下!
前端·人工智能·后端
幽络源小助理12 分钟前
SpringBoot基于Mysql的商业辅助决策系统设计与实现
java·vue.js·spring boot·后端·mysql·spring
猴哥源码14 分钟前
基于Java+springboot 的车险理赔信息管理系统
java·spring boot
YuTaoShao1 小时前
【LeetCode 热题 100】48. 旋转图像——转置+水平翻转
java·算法·leetcode·职场和发展
ai小鬼头1 小时前
AIStarter如何助力用户与创作者?Stable Diffusion一键管理教程!
后端·架构·github
Dcs1 小时前
超强推理不止“大”——手把手教你部署 Mistral Small 3.2 24B 大模型
java
简佐义的博客2 小时前
破解非模式物种GO/KEGG注释难题
开发语言·数据库·后端·oracle·golang
东阳马生架构2 小时前
订单初版—1.分布式订单系统的简要设计文档
java