From b144c6e9d113ea9832ad3fe572a9e58ad9b398ae Mon Sep 17 00:00:00 2001 From: Minsu Kim Date: Fri, 31 Jan 2025 16:01:57 +0900 Subject: [PATCH] =?UTF-8?q?=EC=84=9C=EB=B2=84=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EC=B6=94=EA=B0=80=ED=95=9C?= =?UTF-8?q?=EB=8B=A4.=20(#42)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: spring cloud aws, aws-s3 의존성 추가 * feat: storage client 인터페이스 작성 * feat: aws cloud, s3 설정 추가 * feat: AwsS3Client upload, delete 메서드 구현 * feat: 테스트 aws s3 설정 추가 * chore: 빈 라인 정렬 --- server/build.gradle | 4 ++ .../storage/application/StorageClient.java | 10 +++ .../com/fluffy/storage/infra/AwsS3Client.java | 67 +++++++++++++++++++ server/src/main/resources/application.yml | 19 ++++++ .../src/test/resources/application-test.yml | 10 +++ 5 files changed, 110 insertions(+) create mode 100644 server/src/main/java/com/fluffy/storage/application/StorageClient.java create mode 100644 server/src/main/java/com/fluffy/storage/infra/AwsS3Client.java diff --git a/server/build.gradle b/server/build.gradle index d52049a..c6fc97c 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -71,6 +71,10 @@ dependencies { // monitoring implementation 'org.springframework.boot:spring-boot-starter-actuator' + // aws + implementation platform('io.awspring.cloud:spring-cloud-aws-dependencies:3.1.1') + implementation 'io.awspring.cloud:spring-cloud-aws-starter-s3' + // test testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' diff --git a/server/src/main/java/com/fluffy/storage/application/StorageClient.java b/server/src/main/java/com/fluffy/storage/application/StorageClient.java new file mode 100644 index 0000000..cdf9909 --- /dev/null +++ b/server/src/main/java/com/fluffy/storage/application/StorageClient.java @@ -0,0 +1,10 @@ +package com.fluffy.storage.application; + +import org.springframework.web.multipart.MultipartFile; + +public interface StorageClient { + + String upload(MultipartFile file); + + void delete(String fileName); +} diff --git a/server/src/main/java/com/fluffy/storage/infra/AwsS3Client.java b/server/src/main/java/com/fluffy/storage/infra/AwsS3Client.java new file mode 100644 index 0000000..b36841e --- /dev/null +++ b/server/src/main/java/com/fluffy/storage/infra/AwsS3Client.java @@ -0,0 +1,67 @@ +package com.fluffy.storage.infra; + +import com.fluffy.global.exception.BadRequestException; +import com.fluffy.global.exception.NotFoundException; +import com.fluffy.storage.application.StorageClient; +import io.awspring.cloud.s3.S3Exception; +import io.awspring.cloud.s3.S3Resource; +import io.awspring.cloud.s3.S3Template; +import java.io.IOException; +import java.io.InputStream; +import java.text.SimpleDateFormat; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +@Component +@RequiredArgsConstructor +public class AwsS3Client implements StorageClient { + + private final S3Template s3Template; + + @Value("${spring.cloud.aws.s3.bucket}") + private String bucketName; + + @Override + public String upload(MultipartFile file) { + + if (file.isEmpty()) { + throw new BadRequestException("파일이 비어있습니다."); + } + + String fileName = generateFileName(file.getOriginalFilename()); + + try (InputStream is = file.getInputStream()) { + S3Resource upload = s3Template.upload(bucketName, fileName, is); + + return upload.getURL().toString(); + } catch (IOException | S3Exception e) { + throw new BadRequestException("파일 업로드에 실패했습니다.", e); + } + } + + @Override + public void delete(String fileName) { + try { + s3Template.deleteObject(bucketName, fileName); + } catch (S3Exception e) { + throw new NotFoundException("파일을 찾을 수 없습니다.", e); + } + } + + private String generateFileName(String originalFileName) { + if (originalFileName == null) { + throw new NotFoundException("파일 이름을 찾을 수 없습니다."); + } + + int extensionIndex = originalFileName.lastIndexOf("."); + + String extension = originalFileName.substring(extensionIndex); + String fileName = originalFileName.substring(0, extensionIndex); + + String now = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss_SSS").format(System.currentTimeMillis()); + + return "%s-%s%s".formatted(fileName, now, extension); + } +} diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index 24a020b..4a7b616 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -27,6 +27,16 @@ spring: redis: host: localhost port: 6379 + cloud: + aws: + credentials: + access-key: ${AWS_ACCESS_KEY} + secret-key: ${AWS_SECRET_KEY} + region: + static: ${AWS_S3_REGION} + s3: + bucket: ${AWS_S3_BUCKET} + api-host: http://localhost:8080 client-host: http://localhost:5173 @@ -93,6 +103,15 @@ spring: redis: host: redis port: 6379 + cloud: + aws: + credentials: + access-key: ${AWS_ACCESS_KEY} + secret-key: ${AWS_SECRET_KEY} + region: + static: ${AWS_S3_REGION} + s3: + bucket: ${AWS_S3_BUCKET} api-host: https://api.fluffy.run client-host: https://www.fluffy.run diff --git a/server/src/test/resources/application-test.yml b/server/src/test/resources/application-test.yml index 57ff2f8..535e9c9 100644 --- a/server/src/test/resources/application-test.yml +++ b/server/src/test/resources/application-test.yml @@ -12,6 +12,16 @@ spring: redis: host: localhost port: 6379 + cloud: + aws: + credentials: + access-key: access-key + secret-key: secret-key + region: + static: ap-northeast-2 + s3: + bucket: bucket + api-host: http://localhost:8080 client-host: http://localhost:5173