こんにちは、Sawa です。

前回のブログでは AWS CLI から S3 へファイルをアップロードできるようにしてみました。

Spring Boot から S3 にファイルをアップロードしてみよう!AWS セットアップ編(AWS SDK for Java)

今回はいよいよ Spring Boot で作成したアプリケーションから S3 にアップロードできるような実装をしていきます。

プロジェクトの作成

私はビルドツールとして Gradle を使用しています。

また、今回は Java 17, Spring Boot 3.5.3 を使用します。

build.grale ファイルの中身を載せておきます。

今回は web 上のページからファイルをアップロードするためにThymeleaf, AWS SDK for Java も S3 操作に必要なので入れおきます。

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.5.3'
	id 'io.spring.dependency-management' version '1.1.7'
}

group = 'com.s3'
version = '0.0.1-SNAPSHOT'

java {
	toolchain {
		languageVersion = JavaLanguageVersion.of(17)
	}
}

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
	implementation platform('software.amazon.awssdk:bom:2.27.21')
	implementation 'software.amazon.awssdk:s3'
	testImplementation platform('org.junit:junit-bom:5.10.0')
	testImplementation 'org.junit.jupiter:junit-jupiter'
}

tasks.named('test') {
	useJUnitPlatform()
}

実装

まず今回作成したアプリのディレクトリ構造を画像として載せておきます。

S3 アップロードの実装

アップロードする機能は S3Service に実装しました。

S3Service.java

package com.s3.awsapp.service;

import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;

import java.io.IOException;

@Service
public class S3Service {

    // 作成したバケットの名前
    private final String bucketName = "sawa-test-bucket";

    //  クライアントの定義
    private final S3Client s3 = S3Client.builder()
            .region(Region.US_WEST_2) // 適宜リージョンを変更してください
            .credentialsProvider(DefaultCredentialsProvider.create())
            .build();

    // 引数で受け取ったファイルを S3 にアップロード
    public void putS3Object(MultipartFile file) {
        String keyName = file.getOriginalFilename();

        PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                .bucket(bucketName)
                .key(keyName)
                .build();

        try {
            s3.putObject(putObjectRequest,
                    RequestBody.fromInputStream(file.getInputStream(), file.getSize()));
        } catch (IOException e) {
            throw new RuntimeException("S3アップロードでエラー発生", e);
        }
    }
}

ファイルを受け取る Form の実装

Thymeleaf がユーザから受け取った ファイルをオブジェクトと扱うための Form を実装します。

とてもシンプルです。

UploadFileForm.java

package com.s3.awsapp.form;

import lombok.Data;
import org.springframework.web.multipart.MultipartFile;

@Data
public class UploadFileForm {
    private MultipartFile uploadFile;
}

Controller の作成

Controller は Thymeleaf(画面側)とシステム側の架け橋となります。

アップロードが成功すると成功後のページに遷移するようにしました。

S3Controller.java

package com.s3.awsapp.controller;

import com.s3.awsapp.form.UploadFileForm;
import com.s3.awsapp.service.S3Service;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;

@RequiredArgsConstructor
@Controller
public class S3Controller {

    private final S3Service s3Service;

    @GetMapping("/")
    public ModelAndView home(ModelAndView mav) {
        mav.addObject("uploadFileForm", new UploadFileForm());
        mav.setViewName("upload");
        return mav;
    }

    @PostMapping("/upload")
    public ModelAndView uploadFile(@ModelAttribute UploadFileForm form, ModelAndView mav) {
        s3Service.putS3Object(form.getUploadFile());
        mav.setViewName("success");
        return mav;
    }
}

画面の作成

今回はアップロード画面とアップロード成功画面を作成しました。

upload.html

<!DOCTYPE html>
<html xmlns:th="<http://www.thymeleaf.org>">
<head>
    <title>S3 ファイルアップロード</title>
</head>
<body>
<h1>S3 へのアップロード</h1>
<form th:action="@{/upload}" th:object="${uploadFileForm}" method="post" enctype="multipart/form-data">
    <label for="uploadFile">ファイルを選択:</label>
    <input type="file" id="uploadFile" th:field="*{uploadFile}" />
    <button type="submit">アップロード</button>
</form>
</body>
</html>

success.html

<!DOCTYPE html>
<html xmlns:th="<http://www.thymeleaf.org>">
<head>
    <title>アップロード成功</title>
</head>
<body>
<h1>アップロード成功しました!</h1>
<a th:href="@{/}">戻る</a>
</body>
</html>

実際画面がこちらです。

upload.html

success.html

動かしてみる

では実際に動かしてみます。

booRun でアプリケーションを実行します。

ローカルで起動しているので localhost:8080 でアクセス可能です。

今回アプロードするファイルは 「Success!」と記載されている upload_test.txt にします。

選択したら「アップロード」を押します。

成功したようです。

では S3バケットの中身を見てみましょう!

ちゃんとアップロードされていますね

ではこのオブジェクトをダウンロードして中身を確認します。

中身も確認できたのでこれで完成です!

いかがだったでしょうか?

AWS SDK for Java を使用することで簡単に S3 を組み込ませたアプリケーションを構築することが可能です。

今回作成 S3 バケットを今後使わないのであれば削除するのをお忘れなく。

バケットのアクセス制御周りも今回は緩めに設定してしまいましたが、しっかりと意識して設定することが大切です。

これからも楽しく開発していきましょう!

投稿者 Sawa