From ea4ab94b86e5d17300162956d3bc0db7221d3009 Mon Sep 17 00:00:00 2001 From: bokyung Date: Sun, 4 Dec 2022 18:07:13 +0900 Subject: [PATCH 01/11] =?UTF-8?q?feat:=20Aws=20s3=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module-member/build.gradle | 2 ++ .../modulemember/ModuleMemberApplication.java | 4 +++ .../modulemember/config/AwsS3Config.java | 31 +++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 module-member/src/main/java/com/gaethering/modulemember/config/AwsS3Config.java diff --git a/module-member/build.gradle b/module-member/build.gradle index 7c9ca4f..5b5dc88 100644 --- a/module-member/build.gradle +++ b/module-member/build.gradle @@ -3,8 +3,10 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-mail' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-redis' + implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' runtimeOnly 'com.h2database:h2' testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'io.findify:s3mock_2.12:0.2.4' } tasks.register("prepareKotlinBuildScriptModel"){} \ No newline at end of file diff --git a/module-member/src/main/java/com/gaethering/modulemember/ModuleMemberApplication.java b/module-member/src/main/java/com/gaethering/modulemember/ModuleMemberApplication.java index 409c79e..cc385f8 100644 --- a/module-member/src/main/java/com/gaethering/modulemember/ModuleMemberApplication.java +++ b/module-member/src/main/java/com/gaethering/modulemember/ModuleMemberApplication.java @@ -14,4 +14,8 @@ public static void main(String[] args) { SpringApplication.run(ModuleMemberApplication.class, args); } + static { + System.setProperty("com.amazonaws.sdk.disableEc2Metadata", "true"); + } + } diff --git a/module-member/src/main/java/com/gaethering/modulemember/config/AwsS3Config.java b/module-member/src/main/java/com/gaethering/modulemember/config/AwsS3Config.java new file mode 100644 index 0000000..09481ea --- /dev/null +++ b/module-member/src/main/java/com/gaethering/modulemember/config/AwsS3Config.java @@ -0,0 +1,31 @@ +package com.gaethering.modulemember.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 AwsS3Config { + + @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 awsCreds = new BasicAWSCredentials(accessKey, secretKey); + return (AmazonS3Client) AmazonS3ClientBuilder.standard() + .withRegion(region) + .withCredentials(new AWSStaticCredentialsProvider(awsCreds)) + .build(); + } +} From 8000673c77e6e40338cd297977f520e95ae111d8 Mon Sep 17 00:00:00 2001 From: bokyung Date: Sun, 4 Dec 2022 18:53:01 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20Aws=20s3=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EB=B0=8F=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ImageUploadService.java | 16 +++ .../service/ImageUploadServiceImpl.java | 99 +++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadService.java create mode 100644 module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadServiceImpl.java diff --git a/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadService.java b/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadService.java new file mode 100644 index 0000000..a521932 --- /dev/null +++ b/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadService.java @@ -0,0 +1,16 @@ +package com.gaethering.modulemember.service; + +import org.springframework.web.multipart.MultipartFile; + +public interface ImageUploadService { + + String uploadPetImage(MultipartFile multipartFile); + + void removePetImage(String filename); + + String createFileName(String filename); + + String getFileExtension(String filename); + + void validateFileExtension(String filename); +} diff --git a/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadServiceImpl.java b/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadServiceImpl.java new file mode 100644 index 0000000..862155e --- /dev/null +++ b/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadServiceImpl.java @@ -0,0 +1,99 @@ +package com.gaethering.modulemember.service; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.CannedAccessControlList; +import com.amazonaws.services.s3.model.ObjectMetadata; +import com.amazonaws.services.s3.model.PutObjectRequest; +import com.gaethering.modulemember.exception.pet.FailedUploadImageException; +import com.gaethering.modulemember.exception.pet.ImageNotFoundException; +import com.gaethering.modulemember.exception.pet.InvalidImageTypeException; +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.util.ArrayList; +import java.util.UUID; + +@Service +@RequiredArgsConstructor +@Slf4j +public class ImageUploadServiceImpl implements ImageUploadService { + + private final AmazonS3 amazonS3; + + @Value("${cloud.aws.s3.bucket}") + private String bucket; + + @Value("${dir}") + private String dir; + + @Override + public String uploadPetImage(MultipartFile multipartFile) { + + String fileName = createFileName(multipartFile.getOriginalFilename()); + + ObjectMetadata objectMetadata = new ObjectMetadata(); + objectMetadata.setContentLength(multipartFile.getSize()); + objectMetadata.setContentType(multipartFile.getContentType()); + + log.info("multipartFile contentType={}", multipartFile.getContentType()); + + try { + log.info("multipartFile.getInputStream={}", multipartFile.getInputStream()); + log.info("objectMetadata={}", objectMetadata.getContentLength()); + + amazonS3.putObject(new PutObjectRequest(bucket + "/" + dir, fileName, multipartFile.getInputStream(), objectMetadata) + .withCannedAcl(CannedAccessControlList.PublicRead)); + + } catch(IOException e) { + throw new FailedUploadImageException(); + } + + log.info("uuid={}", UUID.randomUUID().toString()); + log.info("uuid concat={}", UUID.randomUUID().toString().concat(getFileExtension(fileName))); + log.info("file url={}", amazonS3.getUrl(bucket, "pet-profile/" + fileName)); + + return amazonS3.getUrl(bucket, dir + "/" + fileName).toString(); + } + + @Override + public void removePetImage(String filename) { + amazonS3.deleteObject(bucket, + dir + "/" + filename.substring( filename.lastIndexOf("/") + 1)); + } + + @Override + public String createFileName(String filename) { + return UUID.randomUUID().toString().concat(getFileExtension(filename)); + } + + @Override + public String getFileExtension(String filename) { + if (filename.length() == 0) { + throw new ImageNotFoundException(); + } + validateFileExtension(filename); + + return filename.substring(filename.lastIndexOf(".")); + } + + @Override + public void validateFileExtension(String filename) { + ArrayList fileValidate = new ArrayList<>(); + fileValidate.add(".jpg"); + fileValidate.add(".jpeg"); + fileValidate.add(".png"); + fileValidate.add(".JPG"); + fileValidate.add(".JPEG"); + fileValidate.add(".PNG"); + + String idxFileName = filename.substring(filename.lastIndexOf(".")); + + if (!fileValidate.contains(idxFileName)) { + throw new InvalidImageTypeException(); + } + } +} From c1ef5ce1321c1b839664f2a36fe1c9c16762f979 Mon Sep 17 00:00:00 2001 From: bokyung Date: Sun, 4 Dec 2022 18:57:04 +0900 Subject: [PATCH 03/11] =?UTF-8?q?refactor:=20Aws=20s3=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modulemember/service/ImageUploadServiceImpl.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadServiceImpl.java b/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadServiceImpl.java index 862155e..23a2723 100644 --- a/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadServiceImpl.java +++ b/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadServiceImpl.java @@ -19,7 +19,6 @@ @Service @RequiredArgsConstructor -@Slf4j public class ImageUploadServiceImpl implements ImageUploadService { private final AmazonS3 amazonS3; @@ -39,12 +38,7 @@ public String uploadPetImage(MultipartFile multipartFile) { objectMetadata.setContentLength(multipartFile.getSize()); objectMetadata.setContentType(multipartFile.getContentType()); - log.info("multipartFile contentType={}", multipartFile.getContentType()); - try { - log.info("multipartFile.getInputStream={}", multipartFile.getInputStream()); - log.info("objectMetadata={}", objectMetadata.getContentLength()); - amazonS3.putObject(new PutObjectRequest(bucket + "/" + dir, fileName, multipartFile.getInputStream(), objectMetadata) .withCannedAcl(CannedAccessControlList.PublicRead)); @@ -52,10 +46,6 @@ public String uploadPetImage(MultipartFile multipartFile) { throw new FailedUploadImageException(); } - log.info("uuid={}", UUID.randomUUID().toString()); - log.info("uuid concat={}", UUID.randomUUID().toString().concat(getFileExtension(fileName))); - log.info("file url={}", amazonS3.getUrl(bucket, "pet-profile/" + fileName)); - return amazonS3.getUrl(bucket, dir + "/" + fileName).toString(); } From 5fd0fc0eb34109c7a8c1a321db33ba3f1598bc1c Mon Sep 17 00:00:00 2001 From: bokyung Date: Sun, 4 Dec 2022 20:25:08 +0900 Subject: [PATCH 04/11] =?UTF-8?q?refactor:=20=ED=8E=AB=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pet Entity 수정 Pet Controller, Service 생성 --- .../moduledomain/domain/member/Pet.java | 4 ++ .../controller/PetController.java | 26 +++++++++++++ .../modulemember/service/pet/PetService.java | 8 ++++ .../service/pet/PetServiceImpl.java | 39 +++++++++++++++++++ 4 files changed, 77 insertions(+) create mode 100644 module-member/src/main/java/com/gaethering/modulemember/controller/PetController.java create mode 100644 module-member/src/main/java/com/gaethering/modulemember/service/pet/PetService.java create mode 100644 module-member/src/main/java/com/gaethering/modulemember/service/pet/PetServiceImpl.java diff --git a/module-domain/src/main/java/com/gaethering/moduledomain/domain/member/Pet.java b/module-domain/src/main/java/com/gaethering/moduledomain/domain/member/Pet.java index 7e288ef..558c0e3 100644 --- a/module-domain/src/main/java/com/gaethering/moduledomain/domain/member/Pet.java +++ b/module-domain/src/main/java/com/gaethering/moduledomain/domain/member/Pet.java @@ -56,4 +56,8 @@ public class Pet { public void setMember(Member member) { this.member = member; } + + public void updateImage(String imageUrl) { + this.imageUrl = imageUrl; + } } diff --git a/module-member/src/main/java/com/gaethering/modulemember/controller/PetController.java b/module-member/src/main/java/com/gaethering/modulemember/controller/PetController.java new file mode 100644 index 0000000..129fd25 --- /dev/null +++ b/module-member/src/main/java/com/gaethering/modulemember/controller/PetController.java @@ -0,0 +1,26 @@ +package com.gaethering.modulemember.controller; + +import com.gaethering.modulemember.exception.pet.ImageNotFoundException; +import com.gaethering.modulemember.service.pet.PetServiceImpl; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +@RestController +@RequestMapping("${api-prefix}") +@RequiredArgsConstructor +public class PetController { + + private final PetServiceImpl petService; + + @PatchMapping("/mypage/pets/{petId}/image") + public ResponseEntity updatePetImage(@PathVariable("petId") Long id, + @RequestPart("file") MultipartFile multipartFile) { + if (multipartFile.isEmpty()) { + throw new ImageNotFoundException(); + } + + return ResponseEntity.ok(petService.updatePetImage(id, multipartFile)); + } +} diff --git a/module-member/src/main/java/com/gaethering/modulemember/service/pet/PetService.java b/module-member/src/main/java/com/gaethering/modulemember/service/pet/PetService.java new file mode 100644 index 0000000..201efa4 --- /dev/null +++ b/module-member/src/main/java/com/gaethering/modulemember/service/pet/PetService.java @@ -0,0 +1,8 @@ +package com.gaethering.modulemember.service.pet; + +import org.springframework.web.multipart.MultipartFile; + +public interface PetService { + + String updatePetImage(Long id, MultipartFile multipartFile); +} diff --git a/module-member/src/main/java/com/gaethering/modulemember/service/pet/PetServiceImpl.java b/module-member/src/main/java/com/gaethering/modulemember/service/pet/PetServiceImpl.java new file mode 100644 index 0000000..d027286 --- /dev/null +++ b/module-member/src/main/java/com/gaethering/modulemember/service/pet/PetServiceImpl.java @@ -0,0 +1,39 @@ +package com.gaethering.modulemember.service.pet; + +import com.gaethering.moduledomain.domain.member.Pet; +import com.gaethering.moduledomain.repository.pet.PetRepository; +import com.gaethering.modulemember.exception.pet.PetNotFoundException; +import com.gaethering.modulemember.service.ImageUploadService; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +@Service +@Transactional +@RequiredArgsConstructor +public class PetServiceImpl implements PetService { + + private final ImageUploadService imageUploadService; + private final PetRepository petRepository; + + @Value("${default.image-url}") + private String defaultImageUrl; + + @Override + public String updatePetImage(Long id, MultipartFile multipartFile) { + Pet pet = petRepository.findById(id) + .orElseThrow(PetNotFoundException::new); + + if (!defaultImageUrl.equals(pet.getImageUrl())) { + imageUploadService.removePetImage(pet.getImageUrl()); + } + + String newImageUrl = imageUploadService.uploadPetImage(multipartFile); + pet.updateImage(newImageUrl); + + return newImageUrl; + } + +} From a693dd74fb7828d1bd1d1df58a9d8a90a1efa2b5 Mon Sep 17 00:00:00 2001 From: bokyung Date: Sun, 4 Dec 2022 20:35:58 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20=ED=8E=AB=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EC=8B=9C=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FailedUploadImageException : 이미지 업로드 실패시 예외 ImageNotFoundException : 이미지 파일이 존재하지 않을 시 예외 InvalidImageTypeException : 이미지 확장가 아닐 때 예외 PetNotFoundException : 반려동물 프로필이 존재하지 않을 때의 예외 --- .../exception/errorcode/PetErrorCode.java | 17 +++++++++++++++++ .../handler/GlobalExceptionHandler.java | 12 ++++++++++++ .../pet/FailedUploadImageException.java | 10 ++++++++++ .../exception/pet/ImageNotFoundException.java | 10 ++++++++++ .../pet/InvalidImageTypeException.java | 10 ++++++++++ .../exception/pet/PetException.java | 15 +++++++++++++++ .../exception/pet/PetNotFoundException.java | 10 ++++++++++ 7 files changed, 84 insertions(+) create mode 100644 module-member/src/main/java/com/gaethering/modulemember/exception/errorcode/PetErrorCode.java create mode 100644 module-member/src/main/java/com/gaethering/modulemember/exception/pet/FailedUploadImageException.java create mode 100644 module-member/src/main/java/com/gaethering/modulemember/exception/pet/ImageNotFoundException.java create mode 100644 module-member/src/main/java/com/gaethering/modulemember/exception/pet/InvalidImageTypeException.java create mode 100644 module-member/src/main/java/com/gaethering/modulemember/exception/pet/PetException.java create mode 100644 module-member/src/main/java/com/gaethering/modulemember/exception/pet/PetNotFoundException.java diff --git a/module-member/src/main/java/com/gaethering/modulemember/exception/errorcode/PetErrorCode.java b/module-member/src/main/java/com/gaethering/modulemember/exception/errorcode/PetErrorCode.java new file mode 100644 index 0000000..91279e0 --- /dev/null +++ b/module-member/src/main/java/com/gaethering/modulemember/exception/errorcode/PetErrorCode.java @@ -0,0 +1,17 @@ +package com.gaethering.modulemember.exception.errorcode; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum PetErrorCode { + + IMAGE_NOT_FOUND("E1001", "사진이 존재하지 않습니다."), + INVALID_IMAGE_TYPE("E1002", "사진 형식이 잘못되었습니다."), + FAILED_UPLOAD_IMAGE("E1003", "사진 업로드에 실패하였습니다."), + PET_NOT_FOUND("E1004", "반려동물이 존재하지 않습니다."); + + private final String code; + private final String message; +} diff --git a/module-member/src/main/java/com/gaethering/modulemember/exception/handler/GlobalExceptionHandler.java b/module-member/src/main/java/com/gaethering/modulemember/exception/handler/GlobalExceptionHandler.java index 93de8ea..eaec135 100644 --- a/module-member/src/main/java/com/gaethering/modulemember/exception/handler/GlobalExceptionHandler.java +++ b/module-member/src/main/java/com/gaethering/modulemember/exception/handler/GlobalExceptionHandler.java @@ -3,6 +3,7 @@ import com.gaethering.modulecore.exception.ErrorResponse; import com.gaethering.modulemember.exception.errorcode.MemberErrorCode; import com.gaethering.modulemember.exception.member.MemberException; +import com.gaethering.modulemember.exception.pet.PetException; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -36,4 +37,15 @@ public ResponseEntity handleMailSendException(MailSendException e return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); } + @ExceptionHandler(PetException.class) + public ResponseEntity handlePetException(PetException e) { + + ErrorResponse response = ErrorResponse.builder() + .code(e.getErrorCode().getCode()) + .message(e.getMessage()) + .build(); + + return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); + } + } diff --git a/module-member/src/main/java/com/gaethering/modulemember/exception/pet/FailedUploadImageException.java b/module-member/src/main/java/com/gaethering/modulemember/exception/pet/FailedUploadImageException.java new file mode 100644 index 0000000..e79b831 --- /dev/null +++ b/module-member/src/main/java/com/gaethering/modulemember/exception/pet/FailedUploadImageException.java @@ -0,0 +1,10 @@ +package com.gaethering.modulemember.exception.pet; + +import com.gaethering.modulemember.exception.errorcode.PetErrorCode; + +public class FailedUploadImageException extends PetException { + + public FailedUploadImageException() { + super(PetErrorCode.FAILED_UPLOAD_IMAGE); + } +} diff --git a/module-member/src/main/java/com/gaethering/modulemember/exception/pet/ImageNotFoundException.java b/module-member/src/main/java/com/gaethering/modulemember/exception/pet/ImageNotFoundException.java new file mode 100644 index 0000000..fb2f6c6 --- /dev/null +++ b/module-member/src/main/java/com/gaethering/modulemember/exception/pet/ImageNotFoundException.java @@ -0,0 +1,10 @@ +package com.gaethering.modulemember.exception.pet; + +import com.gaethering.modulemember.exception.errorcode.PetErrorCode; + +public class ImageNotFoundException extends PetException { + + public ImageNotFoundException() { + super(PetErrorCode.IMAGE_NOT_FOUND); + } +} diff --git a/module-member/src/main/java/com/gaethering/modulemember/exception/pet/InvalidImageTypeException.java b/module-member/src/main/java/com/gaethering/modulemember/exception/pet/InvalidImageTypeException.java new file mode 100644 index 0000000..ef1811b --- /dev/null +++ b/module-member/src/main/java/com/gaethering/modulemember/exception/pet/InvalidImageTypeException.java @@ -0,0 +1,10 @@ +package com.gaethering.modulemember.exception.pet; + +import com.gaethering.modulemember.exception.errorcode.PetErrorCode; + +public class InvalidImageTypeException extends PetException { + + public InvalidImageTypeException() { + super(PetErrorCode.INVALID_IMAGE_TYPE); + } +} diff --git a/module-member/src/main/java/com/gaethering/modulemember/exception/pet/PetException.java b/module-member/src/main/java/com/gaethering/modulemember/exception/pet/PetException.java new file mode 100644 index 0000000..b1277db --- /dev/null +++ b/module-member/src/main/java/com/gaethering/modulemember/exception/pet/PetException.java @@ -0,0 +1,15 @@ +package com.gaethering.modulemember.exception.pet; + +import com.gaethering.modulemember.exception.errorcode.PetErrorCode; +import lombok.Getter; + +@Getter +public class PetException extends RuntimeException { + + private final PetErrorCode errorCode; + + protected PetException(PetErrorCode petErrorCode) { + super(petErrorCode.getMessage()); + this.errorCode = petErrorCode; + } +} \ No newline at end of file diff --git a/module-member/src/main/java/com/gaethering/modulemember/exception/pet/PetNotFoundException.java b/module-member/src/main/java/com/gaethering/modulemember/exception/pet/PetNotFoundException.java new file mode 100644 index 0000000..e20adae --- /dev/null +++ b/module-member/src/main/java/com/gaethering/modulemember/exception/pet/PetNotFoundException.java @@ -0,0 +1,10 @@ +package com.gaethering.modulemember.exception.pet; + +import com.gaethering.modulemember.exception.errorcode.PetErrorCode; + +public class PetNotFoundException extends PetException { + + public PetNotFoundException() { + super(PetErrorCode.PET_NOT_FOUND); + } +} From 200dc144f81064c8e8a7914dfd2977eaa836e352 Mon Sep 17 00:00:00 2001 From: bokyung Date: Sun, 4 Dec 2022 21:04:28 +0900 Subject: [PATCH 06/11] =?UTF-8?q?feat:=20Aws=20S3=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modulemember/config/AwsS3MockConfig.java | 46 +++++++++++++ .../service/ImageUploadServiceTest.java | 65 +++++++++++++++++++ .../src/test/resources/application.yml | 19 +++++- 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 module-member/src/test/java/com/gaethering/modulemember/config/AwsS3MockConfig.java create mode 100644 module-member/src/test/java/com/gaethering/modulemember/service/ImageUploadServiceTest.java diff --git a/module-member/src/test/java/com/gaethering/modulemember/config/AwsS3MockConfig.java b/module-member/src/test/java/com/gaethering/modulemember/config/AwsS3MockConfig.java new file mode 100644 index 0000000..5178363 --- /dev/null +++ b/module-member/src/test/java/com/gaethering/modulemember/config/AwsS3MockConfig.java @@ -0,0 +1,46 @@ +package com.gaethering.modulemember.config; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.AnonymousAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import io.findify.s3mock.S3Mock; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; + +@TestConfiguration +public class AwsS3MockConfig { + + @Value("${cloud.aws.s3.bucket}") + public String bucket; + + @Value("${cloud.aws.region.static}") + private String region; + + @Bean + public S3Mock s3Mock() { + return new S3Mock.Builder().withPort(8001).withInMemoryBackend().build(); + } + + @Primary + @Bean + public AmazonS3 amazonS3(S3Mock s3Mock){ + s3Mock.start(); + + AwsClientBuilder.EndpointConfiguration endpoint = + new AwsClientBuilder.EndpointConfiguration("http://127.0.0.1:8001", region); + + AmazonS3 client = AmazonS3ClientBuilder + .standard() + .withPathStyleAccessEnabled(true) + .withEndpointConfiguration(endpoint) + .withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials())) + .build(); + client.createBucket(bucket); + + return client; + } +} diff --git a/module-member/src/test/java/com/gaethering/modulemember/service/ImageUploadServiceTest.java b/module-member/src/test/java/com/gaethering/modulemember/service/ImageUploadServiceTest.java new file mode 100644 index 0000000..20ef6df --- /dev/null +++ b/module-member/src/test/java/com/gaethering/modulemember/service/ImageUploadServiceTest.java @@ -0,0 +1,65 @@ +package com.gaethering.modulemember.service; + +import com.gaethering.modulemember.config.AwsS3MockConfig; +import com.gaethering.modulemember.exception.errorcode.PetErrorCode; +import com.gaethering.modulemember.exception.pet.InvalidImageTypeException; +import io.findify.s3mock.S3Mock; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.mock.web.MockMultipartFile; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; + +@Import(AwsS3MockConfig.class) +@SpringBootTest +class ImageUploadServiceTest { + + @Autowired + S3Mock s3Mock; + + @Autowired + ImageUploadServiceImpl imageUploadService; + + @AfterEach + public void shutdownMockS3(){ + s3Mock.stop(); + } + + @Test + void uploadPetImageFailure_fileExtension() throws IOException { + // given + String filename = "test.txt"; + String contentType = "image/png"; + + MockMultipartFile file = new MockMultipartFile("test", filename, contentType, "test".getBytes()); + + // when + InvalidImageTypeException exception = Assertions.assertThrows(InvalidImageTypeException.class, + () -> imageUploadService.uploadPetImage(file)); + + // then + assertThat(exception.getErrorCode()).isEqualTo(PetErrorCode.INVALID_IMAGE_TYPE); + } + + @Test + void uploadPetImageSuccess() throws IOException { + // given + String filename = "test.png"; + String contentType = "image/png"; + String path = "http://127.0.0.1:8001/test-bucket/test-dir/"; + + MockMultipartFile file = new MockMultipartFile("test", filename, contentType, "test".getBytes()); + + // when + String urlPath = imageUploadService.uploadPetImage(file); + + // then + assertThat(urlPath.substring(0, urlPath.lastIndexOf("/") + 1)).isEqualTo("http://127.0.0.1:8001/test-bucket/test-dir/"); + } +} \ No newline at end of file diff --git a/module-member/src/test/resources/application.yml b/module-member/src/test/resources/application.yml index 8ac14d5..de85847 100644 --- a/module-member/src/test/resources/application.yml +++ b/module-member/src/test/resources/application.yml @@ -11,4 +11,21 @@ spring : ddl-auto: update properties: hibernate: - format_sql: true \ No newline at end of file + format_sql: true + +cloud: + aws: + credentials: + access-key: test + secret-key: test + s3: + bucket: test-bucket + region: + static: ap-northeast-2 + auto: false + stack: + auto: false + +dir: test-dir +default: + image-url: http://127.0.0.1:8001/test-bucket/test-dir/4a95753d-1827-43c5-b9a0-2359186aedec.png From d7fe5485ff1372372e4d3baa41abcf6fb8c72309 Mon Sep 17 00:00:00 2001 From: bokyung Date: Sun, 4 Dec 2022 21:52:53 +0900 Subject: [PATCH 07/11] =?UTF-8?q?refactor:=20Aws=20S3=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gaethering/modulemember/service/ImageUploadServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module-member/src/test/java/com/gaethering/modulemember/service/ImageUploadServiceTest.java b/module-member/src/test/java/com/gaethering/modulemember/service/ImageUploadServiceTest.java index 20ef6df..ed1435c 100644 --- a/module-member/src/test/java/com/gaethering/modulemember/service/ImageUploadServiceTest.java +++ b/module-member/src/test/java/com/gaethering/modulemember/service/ImageUploadServiceTest.java @@ -60,6 +60,6 @@ void uploadPetImageSuccess() throws IOException { String urlPath = imageUploadService.uploadPetImage(file); // then - assertThat(urlPath.substring(0, urlPath.lastIndexOf("/") + 1)).isEqualTo("http://127.0.0.1:8001/test-bucket/test-dir/"); + assertThat(urlPath.substring(0, urlPath.lastIndexOf("/") + 1)).isEqualTo(path); } } \ No newline at end of file From 1df9e65cde097657d6f56393dda48eaa212fbde6 Mon Sep 17 00:00:00 2001 From: bokyung Date: Sun, 4 Dec 2022 23:55:13 +0900 Subject: [PATCH 08/11] =?UTF-8?q?refactor:=20=EC=9D=B4=EB=AF=B8=EC=A7=80?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=97=AC=EB=B6=80=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20Service=20=EB=8B=A8=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gaethering/modulemember/controller/PetController.java | 3 --- .../gaethering/modulemember/service/pet/PetServiceImpl.java | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/module-member/src/main/java/com/gaethering/modulemember/controller/PetController.java b/module-member/src/main/java/com/gaethering/modulemember/controller/PetController.java index 129fd25..d0a418c 100644 --- a/module-member/src/main/java/com/gaethering/modulemember/controller/PetController.java +++ b/module-member/src/main/java/com/gaethering/modulemember/controller/PetController.java @@ -17,9 +17,6 @@ public class PetController { @PatchMapping("/mypage/pets/{petId}/image") public ResponseEntity updatePetImage(@PathVariable("petId") Long id, @RequestPart("file") MultipartFile multipartFile) { - if (multipartFile.isEmpty()) { - throw new ImageNotFoundException(); - } return ResponseEntity.ok(petService.updatePetImage(id, multipartFile)); } diff --git a/module-member/src/main/java/com/gaethering/modulemember/service/pet/PetServiceImpl.java b/module-member/src/main/java/com/gaethering/modulemember/service/pet/PetServiceImpl.java index d027286..199ccb6 100644 --- a/module-member/src/main/java/com/gaethering/modulemember/service/pet/PetServiceImpl.java +++ b/module-member/src/main/java/com/gaethering/modulemember/service/pet/PetServiceImpl.java @@ -2,6 +2,7 @@ import com.gaethering.moduledomain.domain.member.Pet; import com.gaethering.moduledomain.repository.pet.PetRepository; +import com.gaethering.modulemember.exception.pet.ImageNotFoundException; import com.gaethering.modulemember.exception.pet.PetNotFoundException; import com.gaethering.modulemember.service.ImageUploadService; import lombok.RequiredArgsConstructor; @@ -23,6 +24,10 @@ public class PetServiceImpl implements PetService { @Override public String updatePetImage(Long id, MultipartFile multipartFile) { + if (multipartFile.isEmpty()) { + throw new ImageNotFoundException(); + } + Pet pet = petRepository.findById(id) .orElseThrow(PetNotFoundException::new); From 7f21ec71b87a5a895fafc225e7de05f510f92b37 Mon Sep 17 00:00:00 2001 From: bokyung Date: Sun, 4 Dec 2022 23:57:46 +0900 Subject: [PATCH 09/11] =?UTF-8?q?refactor:=20=EC=9D=B4=EB=AF=B8=EC=A7=80?= =?UTF-8?q?=20=EC=97=85=EB=A1=9C=EB=93=9C,=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EB=A9=94=EC=86=8C=EB=93=9C=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ImageUploadService, ImageUploadServiceImpl, PetServiceImpl ImageUploadServiceTest --- .../gaethering/modulemember/service/ImageUploadService.java | 4 ++-- .../modulemember/service/ImageUploadServiceImpl.java | 6 ++++-- .../gaethering/modulemember/service/pet/PetServiceImpl.java | 4 ++-- .../modulemember/service/ImageUploadServiceTest.java | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadService.java b/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadService.java index a521932..5b028b1 100644 --- a/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadService.java +++ b/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadService.java @@ -4,9 +4,9 @@ public interface ImageUploadService { - String uploadPetImage(MultipartFile multipartFile); + String uploadImage(MultipartFile multipartFile); - void removePetImage(String filename); + void removeImage(String filename); String createFileName(String filename); diff --git a/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadServiceImpl.java b/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadServiceImpl.java index 23a2723..00a8b4c 100644 --- a/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadServiceImpl.java +++ b/module-member/src/main/java/com/gaethering/modulemember/service/ImageUploadServiceImpl.java @@ -11,6 +11,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; @@ -19,6 +20,7 @@ @Service @RequiredArgsConstructor +@Transactional public class ImageUploadServiceImpl implements ImageUploadService { private final AmazonS3 amazonS3; @@ -30,7 +32,7 @@ public class ImageUploadServiceImpl implements ImageUploadService { private String dir; @Override - public String uploadPetImage(MultipartFile multipartFile) { + public String uploadImage(MultipartFile multipartFile) { String fileName = createFileName(multipartFile.getOriginalFilename()); @@ -50,7 +52,7 @@ public String uploadPetImage(MultipartFile multipartFile) { } @Override - public void removePetImage(String filename) { + public void removeImage(String filename) { amazonS3.deleteObject(bucket, dir + "/" + filename.substring( filename.lastIndexOf("/") + 1)); } diff --git a/module-member/src/main/java/com/gaethering/modulemember/service/pet/PetServiceImpl.java b/module-member/src/main/java/com/gaethering/modulemember/service/pet/PetServiceImpl.java index 199ccb6..a2546c4 100644 --- a/module-member/src/main/java/com/gaethering/modulemember/service/pet/PetServiceImpl.java +++ b/module-member/src/main/java/com/gaethering/modulemember/service/pet/PetServiceImpl.java @@ -32,10 +32,10 @@ public String updatePetImage(Long id, MultipartFile multipartFile) { .orElseThrow(PetNotFoundException::new); if (!defaultImageUrl.equals(pet.getImageUrl())) { - imageUploadService.removePetImage(pet.getImageUrl()); + imageUploadService.removeImage(pet.getImageUrl()); } - String newImageUrl = imageUploadService.uploadPetImage(multipartFile); + String newImageUrl = imageUploadService.uploadImage(multipartFile); pet.updateImage(newImageUrl); return newImageUrl; diff --git a/module-member/src/test/java/com/gaethering/modulemember/service/ImageUploadServiceTest.java b/module-member/src/test/java/com/gaethering/modulemember/service/ImageUploadServiceTest.java index ed1435c..45b8921 100644 --- a/module-member/src/test/java/com/gaethering/modulemember/service/ImageUploadServiceTest.java +++ b/module-member/src/test/java/com/gaethering/modulemember/service/ImageUploadServiceTest.java @@ -41,7 +41,7 @@ void uploadPetImageFailure_fileExtension() throws IOException { // when InvalidImageTypeException exception = Assertions.assertThrows(InvalidImageTypeException.class, - () -> imageUploadService.uploadPetImage(file)); + () -> imageUploadService.uploadImage(file)); // then assertThat(exception.getErrorCode()).isEqualTo(PetErrorCode.INVALID_IMAGE_TYPE); @@ -57,7 +57,7 @@ void uploadPetImageSuccess() throws IOException { MockMultipartFile file = new MockMultipartFile("test", filename, contentType, "test".getBytes()); // when - String urlPath = imageUploadService.uploadPetImage(file); + String urlPath = imageUploadService.uploadImage(file); // then assertThat(urlPath.substring(0, urlPath.lastIndexOf("/") + 1)).isEqualTo(path); From 34eaa4eb721cedf8a1966fb07160e6725a68059c Mon Sep 17 00:00:00 2001 From: bokyung Date: Mon, 5 Dec 2022 00:04:02 +0900 Subject: [PATCH 10/11] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=ED=8C=8C=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gaethering/modulemember/config/AwsS3MockConfig.java | 2 +- module-member/src/test/resources/application.yml | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/module-member/src/test/java/com/gaethering/modulemember/config/AwsS3MockConfig.java b/module-member/src/test/java/com/gaethering/modulemember/config/AwsS3MockConfig.java index 5178363..f8be0b9 100644 --- a/module-member/src/test/java/com/gaethering/modulemember/config/AwsS3MockConfig.java +++ b/module-member/src/test/java/com/gaethering/modulemember/config/AwsS3MockConfig.java @@ -15,7 +15,7 @@ public class AwsS3MockConfig { @Value("${cloud.aws.s3.bucket}") - public String bucket; + private String bucket; @Value("${cloud.aws.region.static}") private String region; diff --git a/module-member/src/test/resources/application.yml b/module-member/src/test/resources/application.yml index de85847..183d397 100644 --- a/module-member/src/test/resources/application.yml +++ b/module-member/src/test/resources/application.yml @@ -28,4 +28,6 @@ cloud: dir: test-dir default: - image-url: http://127.0.0.1:8001/test-bucket/test-dir/4a95753d-1827-43c5-b9a0-2359186aedec.png + test-image-url: http://127.0.0.1:8001/test-bucket/test-dir/4a95753d-1827-43c5-b9a0-2359186aedec.png + +api-prefix: /api \ No newline at end of file From 7d92e08e4cde80096b74a76abebabd8e5efc6f27 Mon Sep 17 00:00:00 2001 From: bokyung Date: Mon, 5 Dec 2022 00:07:53 +0900 Subject: [PATCH 11/11] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20yml=20=ED=8C=8C=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module-member/src/test/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module-member/src/test/resources/application.yml b/module-member/src/test/resources/application.yml index 183d397..c6e2ea8 100644 --- a/module-member/src/test/resources/application.yml +++ b/module-member/src/test/resources/application.yml @@ -28,6 +28,6 @@ cloud: dir: test-dir default: - test-image-url: http://127.0.0.1:8001/test-bucket/test-dir/4a95753d-1827-43c5-b9a0-2359186aedec.png + image-url: http://127.0.0.1:8001/test-bucket/test-dir/4a95753d-1827-43c5-b9a0-2359186aedec.png api-prefix: /api \ No newline at end of file