From c56cd6bb6633b9122c25cc9a8e2e8878aa0d38ef Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Fri, 31 May 2024 05:10:24 +0900 Subject: [PATCH] =?UTF-8?q?[Setting]=20S3=20=EC=84=B8=ED=8C=85(#14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sopt/carrotMarket/external/AwsConfig.java | 48 +++++++++++ .../sopt/carrotMarket/external/S3Service.java | 80 +++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 carrotMarket/src/main/java/org/sopt/carrotMarket/external/AwsConfig.java create mode 100644 carrotMarket/src/main/java/org/sopt/carrotMarket/external/S3Service.java diff --git a/carrotMarket/src/main/java/org/sopt/carrotMarket/external/AwsConfig.java b/carrotMarket/src/main/java/org/sopt/carrotMarket/external/AwsConfig.java new file mode 100644 index 0000000..bb549e5 --- /dev/null +++ b/carrotMarket/src/main/java/org/sopt/carrotMarket/external/AwsConfig.java @@ -0,0 +1,48 @@ +package org.sopt.carrotMarket.external; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import software.amazon.awssdk.auth.credentials.SystemPropertyCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +@Configuration +public class AwsConfig { + + private static final String AWS_ACCESS_KEY_ID = "aws.accessKeyId"; + private static final String AWS_SECRET_ACCESS_KEY = "aws.secretAccessKey"; + + private final String accessKey; + private final String secretKey; + private final String regionString; + + public AwsConfig(@Value("${aws-property.access-key}") final String accessKey, + @Value("${aws-property.secret-key}") final String secretKey, + @Value("${aws-property.aws-region}") final String regionString) { + this.accessKey = accessKey; + this.secretKey = secretKey; + this.regionString = regionString; + } + + + @Bean + public SystemPropertyCredentialsProvider systemPropertyCredentialsProvider() { + System.setProperty(AWS_ACCESS_KEY_ID, accessKey); + System.setProperty(AWS_SECRET_ACCESS_KEY, secretKey); + return SystemPropertyCredentialsProvider.create(); + } + + @Bean + public Region getRegion() { + return Region.of(regionString); + } + + @Bean + public S3Client getS3Client() { + return S3Client.builder() + .region(getRegion()) + .credentialsProvider(systemPropertyCredentialsProvider()) + .build(); + } +} diff --git a/carrotMarket/src/main/java/org/sopt/carrotMarket/external/S3Service.java b/carrotMarket/src/main/java/org/sopt/carrotMarket/external/S3Service.java new file mode 100644 index 0000000..0b86ab7 --- /dev/null +++ b/carrotMarket/src/main/java/org/sopt/carrotMarket/external/S3Service.java @@ -0,0 +1,80 @@ +package org.sopt.carrotMarket.external; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +@Component +public class S3Service { + + private final String bucketName; + private final AwsConfig awsConfig; + private static final List IMAGE_EXTENSIONS = Arrays.asList("image/jpeg", "image/png", "image/jpg", "image/webp"); + + + public S3Service(@Value("${aws-property.s3-bucket-name}") final String bucketName, AwsConfig awsConfig) { + this.bucketName = bucketName; + this.awsConfig = awsConfig; + } + + + public String uploadImage(String directoryPath, MultipartFile image) throws IOException { + final String key = directoryPath + generateImageFileName(); + final S3Client s3Client = awsConfig.getS3Client(); + + validateExtension(image); + validateFileSize(image); + + PutObjectRequest request = PutObjectRequest.builder() + .bucket(bucketName) + .key(key) + .contentType(image.getContentType()) + .contentDisposition("inline") + .build(); + + RequestBody requestBody = RequestBody.fromBytes(image.getBytes()); + s3Client.putObject(request, requestBody); + return key; + } + + public void deleteImage(String key) throws IOException { + final S3Client s3Client = awsConfig.getS3Client(); + + s3Client.deleteObject((DeleteObjectRequest.Builder builder) -> + builder.bucket(bucketName) + .key(key) + .build() + ); + } + + + private String generateImageFileName() { + return UUID.randomUUID() + ".jpg"; + } + + + private void validateExtension(MultipartFile image) { + String contentType = image.getContentType(); + if (!IMAGE_EXTENSIONS.contains(contentType)) { + throw new RuntimeException("이미지 확장자는 jpg, png, webp만 가능합니다."); + } + } + + private static final Long MAX_FILE_SIZE = 5 * 1024 * 1024L; + + private void validateFileSize(MultipartFile image) { + if (image.getSize() > MAX_FILE_SIZE) { + throw new RuntimeException("이미지 사이즈는 5MB를 넘을 수 없습니다."); + } + } + +}