From 31522a37ae212f5a1f8a5ac2fb84fff92cec279e Mon Sep 17 00:00:00 2001 From: seheonnn Date: Sun, 21 Jan 2024 22:54:27 +0900 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=20feat:=20S3=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 7 ++- .../sponus/sponusbe/domain/s3/S3Config.java | 56 ++++++++++++++++++ .../sponusbe/domain/s3/S3Controller.java | 42 +++++++++++++ .../sponus/sponusbe/domain/s3/S3Service.java | 59 +++++++++++++++++++ .../global/config/SecurityConfig.java | 3 +- 5 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/sponus/sponusbe/domain/s3/S3Config.java create mode 100644 src/main/java/com/sponus/sponusbe/domain/s3/S3Controller.java create mode 100644 src/main/java/com/sponus/sponusbe/domain/s3/S3Service.java diff --git a/build.gradle b/build.gradle index 732df747..b2ef398d 100644 --- a/build.gradle +++ b/build.gradle @@ -54,6 +54,9 @@ dependencies { // Validation implementation 'org.springframework.boot:spring-boot-starter-validation' + + // S3 + implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' } tasks.named('test') { @@ -61,6 +64,6 @@ tasks.named('test') { } // enable plain.jar -jar{ - enabled=false +jar { + enabled = false } diff --git a/src/main/java/com/sponus/sponusbe/domain/s3/S3Config.java b/src/main/java/com/sponus/sponusbe/domain/s3/S3Config.java new file mode 100644 index 00000000..edf35c82 --- /dev/null +++ b/src/main/java/com/sponus/sponusbe/domain/s3/S3Config.java @@ -0,0 +1,56 @@ +package com.sponus.sponusbe.domain.s3; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; + +import jakarta.annotation.PostConstruct; +import lombok.Getter; + +@Configuration +@Getter +public class S3Config { + + private AWSCredentials awsCredentials; + + @Value("${cloud.aws.credentials.accessKey}") + private String accessKey; + + @Value("${cloud.aws.credentials.secretKey}") + private String secretKey; + + @Value("${cloud.aws.region.static}") + private String region; + + @Value("${cloud.aws.s3.bucket}") + private String bucket; + + @Value("${cloud.aws.s3.folder}") + private String folder; + + @PostConstruct + public void init() { + this.awsCredentials = new BasicAWSCredentials(accessKey, secretKey); + } + + @Bean + public AmazonS3 amazonS3() { + AWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey); + return AmazonS3ClientBuilder.standard() + .withRegion(region) + .withCredentials(new AWSStaticCredentialsProvider(awsCredentials)) + .build(); + } + + @Bean + public AWSCredentialsProvider awsCredentialsProvider() { + return new AWSStaticCredentialsProvider(awsCredentials); + } +} diff --git a/src/main/java/com/sponus/sponusbe/domain/s3/S3Controller.java b/src/main/java/com/sponus/sponusbe/domain/s3/S3Controller.java new file mode 100644 index 00000000..133f5130 --- /dev/null +++ b/src/main/java/com/sponus/sponusbe/domain/s3/S3Controller.java @@ -0,0 +1,42 @@ +package com.sponus.sponusbe.domain.s3; + +import java.util.List; + +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import com.sponus.sponusbe.global.common.ApiResponse; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RequiredArgsConstructor +@RestController +@RequestMapping("/api/v1/s3") +public class S3Controller { + + private final S3Service s3Service; + + @PostMapping(value = "/uploadImage", consumes = "multipart/form-data") + public ApiResponse uploadImage(@RequestPart(value = "file", required = false) MultipartFile file) { + return ApiResponse.onSuccess(s3Service.uploadFile(file)); + } + + @DeleteMapping(value = "/deleteImage", consumes = "multipart/form-data") + public ApiResponse deleteImage(@RequestPart(value = "path", required = false) String path) { + String image = path.substring(path.lastIndexOf('/') + 1); + return ApiResponse.onSuccess(s3Service.deleteImage(image)); + } + + @PostMapping(value = "/uploadImages", consumes = "multipart/form-data") + public ApiResponse> uploadImages( + @RequestPart(value = "files", required = false) List files) { + return ApiResponse.onSuccess(s3Service.uploadFiles(files)); + } + +} diff --git a/src/main/java/com/sponus/sponusbe/domain/s3/S3Service.java b/src/main/java/com/sponus/sponusbe/domain/s3/S3Service.java new file mode 100644 index 00000000..7aed2b30 --- /dev/null +++ b/src/main/java/com/sponus/sponusbe/domain/s3/S3Service.java @@ -0,0 +1,59 @@ +package com.sponus.sponusbe.domain.s3; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.ObjectMetadata; +import com.amazonaws.services.s3.model.PutObjectRequest; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +@RequiredArgsConstructor +public class S3Service { + + private final AmazonS3 amazonS3; + + private final S3Config s3Config; + + public String uploadFile(MultipartFile file) { + String filePath = + UUID.randomUUID() + file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")); + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentLength(file.getSize()); + try { + amazonS3.putObject( + new PutObjectRequest(s3Config.getBucket(), s3Config.getFolder() + filePath, file.getInputStream(), + metadata)); + } catch (IOException e) { + log.error("error at AmazonS3Manager uploadFile : {}", (Object)e.getStackTrace()); + } + + return amazonS3.getUrl(s3Config.getBucket(), filePath).toString(); + } + + public String deleteImage(String image) { + amazonS3.deleteObject(s3Config.getBucket(), s3Config.getFolder() + image); + return "삭제 성공"; + } + + public List uploadFiles(List files) { + List fileUrls = new ArrayList<>(); + + files.stream().map(file -> { + fileUrls.add(uploadFile(file)); + return fileUrls; + }).collect(Collectors.toList()); + return fileUrls; + } + +} diff --git a/src/main/java/com/sponus/sponusbe/global/config/SecurityConfig.java b/src/main/java/com/sponus/sponusbe/global/config/SecurityConfig.java index d314d618..636d7458 100644 --- a/src/main/java/com/sponus/sponusbe/global/config/SecurityConfig.java +++ b/src/main/java/com/sponus/sponusbe/global/config/SecurityConfig.java @@ -31,7 +31,8 @@ public class SecurityConfig { private final String[] swaggerUrls = {"/swagger-ui/**", "/v3/**"}; - private final String[] authUrls = {"/", "/api/v1/organizations/join/**", "/api/v1/organizations/login/**"}; + private final String[] authUrls = {"/", "/api/v1/organizations/join/**", "/api/v1/organizations/login/**", + "/api/v1/s3/**"}; private final String[] allowedUrls = Stream.concat(Arrays.stream(swaggerUrls), Arrays.stream(authUrls)) .toArray(String[]::new);