From 22d01152c660c1f29bdad5b5f0e5103116824d54 Mon Sep 17 00:00:00 2001 From: TaeHyeon Kim Date: Sun, 14 Jan 2024 19:39:00 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20S3=20=EC=98=A4=EB=B8=8C=EC=A0=9D?= =?UTF-8?q?=ED=8A=B8=20=EB=B2=8C=ED=81=AC=20=EC=82=AD=EC=A0=9C=20=EC=8B=9C?= =?UTF-8?q?=201000=EA=B1=B4=20=EB=8B=A8=EC=9C=84=EB=A1=9C=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=EB=90=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD=20(#1?= =?UTF-8?q?53)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: List 파티셔닝을 위한 Guava 라이브러리 추가 mvn: https://mvnrepository.com/artifact/com.google.guava/guava/32.1.3-jre * feat: S3 오브젝트 삭제 시, 1000건 단위로 삭제하도록 기능 구현 --------- Co-authored-by: 김태현 --- build.gradle | 1 + .../server/support/AwsS3Uploader.java | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 0b06568b..2c48f224 100644 --- a/build.gradle +++ b/build.gradle @@ -38,6 +38,7 @@ dependencies { implementation 'com.slack.api:slack-api-client:1.29.0' implementation platform("org.springframework.cloud:spring-cloud-dependencies:2021.0.5") implementation "org.springframework.cloud:spring-cloud-starter-openfeign" + implementation 'com.google.guava:guava:32.1.3-jre' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' runtimeOnly 'com.mysql:mysql-connector-j' diff --git a/src/main/java/mocacong/server/support/AwsS3Uploader.java b/src/main/java/mocacong/server/support/AwsS3Uploader.java index bc5db32b..4b486a8f 100644 --- a/src/main/java/mocacong/server/support/AwsS3Uploader.java +++ b/src/main/java/mocacong/server/support/AwsS3Uploader.java @@ -1,7 +1,13 @@ package mocacong.server.support; import com.amazonaws.services.s3.AmazonS3Client; -import com.amazonaws.services.s3.model.*; +import com.amazonaws.services.s3.model.CannedAccessControlList; +import com.amazonaws.services.s3.model.DeleteObjectsRequest; +import com.amazonaws.services.s3.model.DeleteObjectsRequest.KeyVersion; +import com.amazonaws.services.s3.model.DeleteObjectsResult; +import com.amazonaws.services.s3.model.ObjectMetadata; +import com.amazonaws.services.s3.model.PutObjectRequest; +import com.google.common.collect.Lists; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -23,6 +29,8 @@ public class AwsS3Uploader { private static final String S3_BUCKET_DIRECTORY_NAME = "static"; + private static final int IMAGE_CHUNK_SIZE = 1000; + private final AmazonS3Client amazonS3Client; @@ -36,7 +44,8 @@ public String uploadImage(MultipartFile multipartFile) { objectMetadata.setContentType(multipartFile.getContentType()); objectMetadata.setContentLength(multipartFile.getSize()); - String fileName = S3_BUCKET_DIRECTORY_NAME + "/" + UUID.randomUUID() + "." + multipartFile.getOriginalFilename(); + String fileName = + S3_BUCKET_DIRECTORY_NAME + "/" + UUID.randomUUID() + "." + multipartFile.getOriginalFilename(); try (InputStream inputStream = multipartFile.getInputStream()) { amazonS3Client.putObject(new PutObjectRequest(bucket, fileName, inputStream, objectMetadata) @@ -58,10 +67,15 @@ private void checkInvalidUploadFile(MultipartFile multipartFile) { @EventListener public void deleteImages(DeleteNotUsedImagesEvent event) { List imgUrls = event.getImgUrls(); + Lists.partition(imgUrls, IMAGE_CHUNK_SIZE) + .forEach(this::deleteImagesByChunk); + } + + private void deleteImagesByChunk(List imgUrls) { List keys = new ArrayList<>(); for (String imgUrl : imgUrls) { String fileName = S3_BUCKET_DIRECTORY_NAME + imgUrl.substring(imgUrl.lastIndexOf("/")); - keys.add(new DeleteObjectsRequest.KeyVersion(fileName)); + keys.add(new KeyVersion(fileName)); } DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucket).withKeys(keys); DeleteObjectsResult result = amazonS3Client.deleteObjects(deleteObjectsRequest);