概要
Spring Bootを3系にアップデートするとjavax
→jakarta
に置き換える必要があるため、javax
が依存関係に含まれるspring-cloud-starter-aws
1が使えなくなる(と思ったのですが、手元の環境では普通に動きました…)。
念のため依存関係がjakarta
になっているio.awspring.cloud.spring-cloud-aws-starter
に変更したのですが、情報が少なかったのでサンプルを公開します。
環境
- Java17
- SpringBoot
- spring-boot-starter-parent:3.2.6
- spring-cloud-aws-dependencies:3.1.1
- spring-cloud-aws-starter
- spring-cloud-aws-starter-s3
サンプル
ストレージクラスにIntelligent-Tieringを指定してAmazon S3にファイル(オブジェクト)をアップロードするサンプルです。
ローカル環境からのアップロードはIntelligent-Tiering、EC2(サーバー)環境からのアップロードはStandard(何も指定しない場合と同じ)で指定する想定です。
※直接関係ない部分は省略しています
pom.xml
AWS SDK For Javaを直接使っても良いと思いますが、今回はspring-cloud-aws-starter
を使います。
<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
を指定すると一括でversion指定ができます。
AwsStorageConfig.java
S3Client
をSeriveクラスでAutowiredして使いたいのでConfigを作ってBeanに登録します。EC2上ではIAM Roleで認証情報を取得できます2が、ローカル環境では情報が取れないので明示的に指定します。
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 tamorieeeen
*
*/
@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;
/**
* ローカル用
*/
@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(サーバー)用
*/
@Bean("s3Client")
@Profile("server")
public S3Client s3Client() {
return S3Client.create();
}
}
application.yml
ローカル用のapplication-local.yml
とEC2(サーバー)用のapplication-sever.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(サーバー)用
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[]>
に詰めて返す想定です。
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 tamorieeeen
*
*/
@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();
/*
* ちなみに
* ContentType は resInputStream.response().contentType()
* ContentLength は resInputStream.response().contentLength()
* で取れます
*/
}
}
}
公式のサンプル
情報少ないな~と思いつつ解決した後にAWS公式のサンプルが公開されていることに気付きました。
AWS SDK For Javaのサンプルコードだと思いますが大枠は多分一緒なので、 最初からこれ見てれば楽勝だったのに…! かなり参考になります。
参考
- [アップデート] Amazon S3 Intelligent-Tiering がより使いやすくなりました(最小ストレージ期間 / 小さなオブジェクトの監視・オートメーションコストの撤廃)
- Amazon S3 ストレージクラス
- Amazon EC2 での IAM ロールを使用した AWS リソースへのアクセスの許可
- Enum StorageClass