From 36752d9098e0056b4c91a1d00a2ac475386f82ba Mon Sep 17 00:00:00 2001 From: kyeong-hyeok Date: Fri, 8 Sep 2023 11:39:33 +0900 Subject: [PATCH 1/3] =?UTF-8?q?chore:=20AWS=20S3=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80=20(#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index f88dc2d..97ff355 100644 --- a/build.gradle +++ b/build.gradle @@ -44,6 +44,8 @@ dependencies { implementation 'com.auth0:java-jwt:4.2.1' // Spring Data Redis implementation 'org.springframework.boot:spring-boot-starter-data-redis' + // AWS S3 + implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' } tasks.named('test') { From d506052fdba4e0160fd4091fac61f1624dadf298 Mon Sep 17 00:00:00 2001 From: kyeong-hyeok Date: Fri, 8 Sep 2023 11:40:13 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20S3=20=EA=B4=80=EB=A0=A8=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80=20(#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../teamA/hicardi/common/s3/FileService.java | 68 +++++++++++++++++++ .../com/teamA/hicardi/config/S3Config.java | 33 +++++++++ 2 files changed, 101 insertions(+) create mode 100644 src/main/java/com/teamA/hicardi/common/s3/FileService.java create mode 100644 src/main/java/com/teamA/hicardi/config/S3Config.java diff --git a/src/main/java/com/teamA/hicardi/common/s3/FileService.java b/src/main/java/com/teamA/hicardi/common/s3/FileService.java new file mode 100644 index 0000000..1c0ce55 --- /dev/null +++ b/src/main/java/com/teamA/hicardi/common/s3/FileService.java @@ -0,0 +1,68 @@ +package com.teamA.hicardi.common.s3; + +import com.amazonaws.services.s3.AmazonS3Client; +import com.amazonaws.services.s3.model.DeleteObjectRequest; +import com.amazonaws.services.s3.model.ObjectMetadata; +import com.teamA.hicardi.error.exception.custom.BusinessException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; + +import static com.teamA.hicardi.error.ErrorCode.INVALID_FILE_UPLOAD; + +@Slf4j +@Service +@RequiredArgsConstructor +public class FileService { + + private final AmazonS3Client amazonS3Client; + + @Value("${cloud.aws.s3.bucket.name}") + private String bucketName; + + @Value("${cloud.aws.s3.bucket.url}") + private String defaultUrl; + + public String uploadFile(MultipartFile multipartFile, String imageType) { + if (multipartFile == null || multipartFile.isEmpty()) return null; + + String savedFileName = getSavedFileName(multipartFile, imageType); + ObjectMetadata metadata = new ObjectMetadata(); + + try (InputStream inputStream = multipartFile.getInputStream()) { + amazonS3Client.putObject(bucketName, savedFileName, inputStream, metadata); + } catch (IOException e) { + log.error("Failed to upload image", e); + throw new BusinessException(INVALID_FILE_UPLOAD); + } + return getResourceUrl(savedFileName); + } + + public void deleteFile(String fileUrl) { + String fileName = getFileNameFromResourceUrl(fileUrl); + amazonS3Client.deleteObject(new DeleteObjectRequest(bucketName, fileName)); + } + + private String getSavedFileName(MultipartFile multipartFile, String imageType) { + return String.format("%s/%s-%s", + imageType, getRandomUUID(), multipartFile.getOriginalFilename()); + } + + private String getRandomUUID() { + return UUID.randomUUID().toString().replace("-", ""); + } + + private String getResourceUrl(String savedFileName) { + return amazonS3Client.getResourceUrl(bucketName, savedFileName); + } + + private String getFileNameFromResourceUrl(String fileUrl) { + return fileUrl.replace(defaultUrl + "/", ""); + } +} \ No newline at end of file diff --git a/src/main/java/com/teamA/hicardi/config/S3Config.java b/src/main/java/com/teamA/hicardi/config/S3Config.java new file mode 100644 index 0000000..a9eff85 --- /dev/null +++ b/src/main/java/com/teamA/hicardi/config/S3Config.java @@ -0,0 +1,33 @@ +package com.teamA.hicardi.config; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.services.s3.AmazonS3Client; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class S3Config { + + @Value("${cloud.aws.credentials.access-key}") + private String accessKey; + + @Value("${cloud.aws.credentials.secret-key}") + private String secretKey; + + @Value("${cloud.aws.region.static}") + private String region; + + @Bean + public AmazonS3Client amazonS3Client() { + BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey); + + return (AmazonS3Client) AmazonS3ClientBuilder + .standard() + .withRegion(region) + .withCredentials(new AWSStaticCredentialsProvider(credentials)) + .build(); + } +} \ No newline at end of file From 074b4e34805436928b114cb91c26d7a62568051b Mon Sep 17 00:00:00 2001 From: kyeong-hyeok Date: Fri, 8 Sep 2023 11:46:57 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20ErrorCode=20=EC=B6=94=EA=B0=80=20(#?= =?UTF-8?q?24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/teamA/hicardi/error/ErrorCode.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/teamA/hicardi/error/ErrorCode.java b/src/main/java/com/teamA/hicardi/error/ErrorCode.java index 4994f0c..a1d72ab 100644 --- a/src/main/java/com/teamA/hicardi/error/ErrorCode.java +++ b/src/main/java/com/teamA/hicardi/error/ErrorCode.java @@ -14,8 +14,10 @@ public enum ErrorCode { ALREADY_LOGOUT_MEMBER(BAD_REQUEST, "이미 로그아웃한 회원입니다"), ALREADY_EXIST_EMAIL(BAD_REQUEST, "이미 존재하는 이메일입니다."), ALREADY_EXIST_USERID(BAD_REQUEST, "이미 존재하는 아이디입니다."), + INVALID_FILE_UPLOAD(BAD_REQUEST, "파일 업로드에 실패하였습니다."), INVALID_TOKEN(UNAUTHORIZED, "잘못된 토큰입니다."); + private final int code; private final String message;