From 4ba6aad2de9a2caabee57ce49acc9f2a6138b856 Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 20:24:34 +0900 Subject: [PATCH 01/16] =?UTF-8?q?[#180]=20feat=20:=20AWS=20S3=20=EB=9D=BC?= =?UTF-8?q?=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=B6=94=EA=B0=80?= 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 c8697672..afcf4dda 100644 --- a/build.gradle +++ b/build.gradle @@ -57,6 +57,8 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-batch' // Retry implementation 'org.springframework.retry:spring-retry' + // AWS S3 + implementation 'io.awspring.cloud:spring-cloud-starter-aws-secrets-manager-config:2.4.4' /* DB */ // MySQL From 1e2f926f8c111df4d70d878a63d39abf3b809a2e Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 20:25:26 +0900 Subject: [PATCH 02/16] =?UTF-8?q?[#180]=20fix=20:=20=EA=B8=B0=ED=94=84?= =?UTF-8?q?=ED=8B=B0=EC=BD=98=20URL=20DB=20=EC=9E=90=EB=A3=8C=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=EB=A5=BC=20tinytext=20=EC=97=90=EC=84=9C=20text=20?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/bc1/gream/domain/gifticon/entity/Gifticon.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/bc1/gream/domain/gifticon/entity/Gifticon.java b/src/main/java/bc1/gream/domain/gifticon/entity/Gifticon.java index e90fc0c6..d2d56f1d 100644 --- a/src/main/java/bc1/gream/domain/gifticon/entity/Gifticon.java +++ b/src/main/java/bc1/gream/domain/gifticon/entity/Gifticon.java @@ -26,7 +26,7 @@ public class Gifticon extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(name = "gifticon_url") + @Column(name = "gifticon_url", columnDefinition = "TEXT") private String gifticonUrl; @OneToOne(cascade = CascadeType.PERSIST) From 1bccf41b88f3a41d0d9bac5b7b724f361867fa4d Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 20:25:48 +0900 Subject: [PATCH 03/16] =?UTF-8?q?[#180]=20feat=20:=20S3=20=EC=8B=A4?= =?UTF-8?q?=EC=A0=95=20=EA=B0=9D=EC=B2=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/bc1/gream/infra/s3/S3Config.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/bc1/gream/infra/s3/S3Config.java diff --git a/src/main/java/bc1/gream/infra/s3/S3Config.java b/src/main/java/bc1/gream/infra/s3/S3Config.java new file mode 100644 index 00000000..3914ec3f --- /dev/null +++ b/src/main/java/bc1/gream/infra/s3/S3Config.java @@ -0,0 +1,28 @@ +package bc1.gream.infra.s3; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.services.s3.AmazonS3; +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 AmazonS3 amazonS3() { + return AmazonS3ClientBuilder.standard() + .withRegion(region) + .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey))) + .build(); + } +} \ No newline at end of file From 32502b6b6cc231a51f7194117f75f33c83d14a35 Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 21:45:18 +0900 Subject: [PATCH 04/16] =?UTF-8?q?[#180]=20feat=20:=20S3=20=ED=99=98?= =?UTF-8?q?=EA=B2=BD=EB=B3=80=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 0e46bf01..d4988ea6 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -35,3 +35,13 @@ server: access-log: # ACESS 에 대한 로깅 enabled: true pattern: "%{yyyy-MM-dd HH:mm:ss}t\\t%s\\t%r\\t%{User-Agent}i\\t%{Referer}i\\t%a\\t%b" +# s3 +cloud: + aws: + s3: + bucket: ${BUCKET_NAME} + stack.auto: false + region.static: ${REGION} + credentials: + access-key: ${S3_ACCESS_KEY} + secret-key: ${S3_SECRET_ACCESS_KEY} \ No newline at end of file From a9e6f3899ed4c7b7bed0b585aad8e0e10b1183b7 Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 21:45:29 +0900 Subject: [PATCH 05/16] =?UTF-8?q?[#180]=20feat=20:=20S3=20=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bc1/gream/infra/s3/S3ImageService.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/main/java/bc1/gream/infra/s3/S3ImageService.java diff --git a/src/main/java/bc1/gream/infra/s3/S3ImageService.java b/src/main/java/bc1/gream/infra/s3/S3ImageService.java new file mode 100644 index 00000000..c03bdb6d --- /dev/null +++ b/src/main/java/bc1/gream/infra/s3/S3ImageService.java @@ -0,0 +1,62 @@ +package bc1.gream.infra.s3; + +import bc1.gream.global.common.ResultCase; +import bc1.gream.global.exception.GlobalException; +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 java.io.IOException; +import java.util.UUID; +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; + +@Slf4j(topic = "s3 image upload") +@Service +@RequiredArgsConstructor +public class S3ImageService { + + private static final String gifticonDirectoryName = "gifticon/"; + private final AmazonS3 amazonS3; + @Value("${cloud.aws.s3.bucket}") + private String bucketName; + + public String getUrlAfterUpload(MultipartFile image) { + + String originalName = image.getOriginalFilename(); + String randomImageName = getRandomImageName(originalName); + log.info("s3 upload name : {}", randomImageName); + + try { + PutObjectRequest request = new PutObjectRequest( + bucketName, + randomImageName, + image.getInputStream(), + createObjectMetadata(originalName) + ) + .withCannedAcl(CannedAccessControlList.PublicRead); + amazonS3.putObject(request); + } catch (IOException e) { + throw new GlobalException(ResultCase.SYSTEM_ERROR); + } + + String url = amazonS3.getUrl(bucketName, randomImageName).toString(); + log.info("s3 url : {}", url); + return url; + } + + private String getRandomImageName(String originalName) { + String random = UUID.randomUUID().toString(); + return gifticonDirectoryName + random + '-' + originalName; + } + + private ObjectMetadata createObjectMetadata(String originalName) { + ObjectMetadata metadata = new ObjectMetadata(); + String ext = originalName.substring(originalName.lastIndexOf(".")); + metadata.setContentType("image/" + ext); + return metadata; + } +} From 9628a76e949d324797c7d4877c0305649e7431e6 Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 21:46:31 +0900 Subject: [PATCH 06/16] =?UTF-8?q?[#180]=20feat=20:=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=EB=B0=94=EC=9D=B4=EB=8D=94=EC=97=90=20S3=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gream/domain/sell/provider/SellBidProvider.java | 10 +++++++++- .../gream/domain/sell/provider/SellNowProvider.java | 8 +++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/java/bc1/gream/domain/sell/provider/SellBidProvider.java b/src/main/java/bc1/gream/domain/sell/provider/SellBidProvider.java index 9e006b02..e4efd5f6 100644 --- a/src/main/java/bc1/gream/domain/sell/provider/SellBidProvider.java +++ b/src/main/java/bc1/gream/domain/sell/provider/SellBidProvider.java @@ -13,12 +13,15 @@ import bc1.gream.domain.sell.service.helper.deadline.Deadline; import bc1.gream.domain.sell.service.helper.deadline.DeadlineCalculator; import bc1.gream.domain.user.entity.User; +import bc1.gream.infra.s3.S3ImageService; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +@Slf4j @Service @RequiredArgsConstructor public class SellBidProvider { @@ -26,10 +29,15 @@ public class SellBidProvider { private final SellRepository sellRepository; private final GifticonCommandService gifticonCommandService; private final SellService sellService; + private final S3ImageService s3ImageService; public SellBidResponseDto createSellBid(User seller, SellBidRequestDto requestDto, Product product) { + + // 기프티콘 이미지 S3 저장 + String url = s3ImageService.getUrlAfterUpload(requestDto.file()); + // 기프티콘 생성, 저장 - Gifticon gifticon = gifticonCommandService.saveGifticon(requestDto.gifticonUrl(), null); + Gifticon gifticon = gifticonCommandService.saveGifticon(url, null); // 마감기한 지정 : LocalTime.Max :: 23시 59분 59초 Integer period = Deadline.getPeriod(requestDto.period()); LocalDateTime deadlineAt = DeadlineCalculator.calculateDeadlineBy(LocalDate.now(), LocalTime.MAX, diff --git a/src/main/java/bc1/gream/domain/sell/provider/SellNowProvider.java b/src/main/java/bc1/gream/domain/sell/provider/SellNowProvider.java index b34777f9..03e4e001 100644 --- a/src/main/java/bc1/gream/domain/sell/provider/SellNowProvider.java +++ b/src/main/java/bc1/gream/domain/sell/provider/SellNowProvider.java @@ -13,6 +13,7 @@ import bc1.gream.domain.sell.dto.request.SellNowRequestDto; import bc1.gream.domain.sell.dto.response.SellNowResponseDto; import bc1.gream.domain.user.entity.User; +import bc1.gream.infra.s3.S3ImageService; import java.util.Objects; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -27,9 +28,11 @@ public class SellNowProvider { private final CouponQueryService couponQueryService; private final OrderCommandService orderCommandService; private final GifticonCommandService gifticonCommandService; + private final S3ImageService s3ImageService; @Transactional public SellNowResponseDto sellNowProduct(User user, SellNowRequestDto requestDto, Long productId) { + // 해당상품과 가격에 대한 구매입찰 Buy buy = buyQueryService.getRecentBuyBidOf(productId, requestDto.price()); // 쿠폰 조회 @@ -37,8 +40,11 @@ public SellNowResponseDto sellNowProduct(User user, SellNowRequestDto requestDto // 새로운 주문 Order order = saveOrder(buy, user, coupon); + // 기프티콘 이미지 S3 저장 + String url = s3ImageService.getUrlAfterUpload(requestDto.file()); + // 새로운 기프티콘 저장 - gifticonCommandService.saveGifticon(requestDto.gifticonUrl(), order); + gifticonCommandService.saveGifticon(url, order); // 판매에 따른 사용자 포인트 충전 user.increasePoint(order.getExpectedPrice()); From 11de0b3174cc05602122fc084a5f7248638beed1 Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 21:47:47 +0900 Subject: [PATCH 07/16] =?UTF-8?q?[#180]=20fix=20:=20=EC=9A=94=EC=B2=AD=20D?= =?UTF-8?q?TO=EB=A5=BC=20multipart=20file=20=EB=A1=9C=20=EB=B0=9B=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gream/domain/sell/dto/request/SellBidRequestDto.java | 6 +++--- .../gream/domain/sell/dto/request/SellNowRequestDto.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/bc1/gream/domain/sell/dto/request/SellBidRequestDto.java b/src/main/java/bc1/gream/domain/sell/dto/request/SellBidRequestDto.java index de9b7d4a..eb5f0f9b 100644 --- a/src/main/java/bc1/gream/domain/sell/dto/request/SellBidRequestDto.java +++ b/src/main/java/bc1/gream/domain/sell/dto/request/SellBidRequestDto.java @@ -1,16 +1,16 @@ package bc1.gream.domain.sell.dto.request; -import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Builder; +import org.springframework.web.multipart.MultipartFile; @Builder public record SellBidRequestDto( @NotNull(message = "가격 필드는 비울 수 없습니다.") Long price, Integer period, - @NotBlank(message = "기프티콘을 업로드해 주세요") - String gifticonUrl + @NotNull(message = "기프티콘을 업로드해 주세요") + MultipartFile file ) { } diff --git a/src/main/java/bc1/gream/domain/sell/dto/request/SellNowRequestDto.java b/src/main/java/bc1/gream/domain/sell/dto/request/SellNowRequestDto.java index a68fc172..14ea9076 100644 --- a/src/main/java/bc1/gream/domain/sell/dto/request/SellNowRequestDto.java +++ b/src/main/java/bc1/gream/domain/sell/dto/request/SellNowRequestDto.java @@ -1,13 +1,13 @@ package bc1.gream.domain.sell.dto.request; -import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import org.springframework.web.multipart.MultipartFile; public record SellNowRequestDto( @NotNull(message = "가격 필드는 비울 수 없습니다.") Long price, - @NotBlank(message = "기프티콘을 업로드해 주세요") - String gifticonUrl + @NotNull(message = "기프티콘을 업로드해 주세요") + MultipartFile file ) { } From 5365d15b41639fe7f59eef4174bd3ccd1a638399 Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 21:48:16 +0900 Subject: [PATCH 08/16] =?UTF-8?q?[#180]=20fix=20:=20=EC=9A=94=EC=B2=AD=20D?= =?UTF-8?q?TO=20multipart=20=EB=A1=9C=20=EB=B0=9B=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bc1/gream/domain/sell/controller/SellBidController.java | 3 +-- .../bc1/gream/domain/sell/controller/SellNowController.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/bc1/gream/domain/sell/controller/SellBidController.java b/src/main/java/bc1/gream/domain/sell/controller/SellBidController.java index 6ecc8ef4..3bfa598a 100644 --- a/src/main/java/bc1/gream/domain/sell/controller/SellBidController.java +++ b/src/main/java/bc1/gream/domain/sell/controller/SellBidController.java @@ -15,7 +15,6 @@ import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -39,7 +38,7 @@ public class SellBidController { @Operation(summary = "판매입찰 체결 요청", description = "판매자의 상품에 대한 판매입찰 체결요청을 처리합니다.") public RestResponse createSellBid( @AuthenticationPrincipal UserDetailsImpl userDetails, - @Valid @RequestBody SellBidRequestDto requestDto, + @Valid SellBidRequestDto requestDto, @PathVariable Long productId ) { Product product = productValidator.validateBy(productId); diff --git a/src/main/java/bc1/gream/domain/sell/controller/SellNowController.java b/src/main/java/bc1/gream/domain/sell/controller/SellNowController.java index 813c392a..082ddea8 100644 --- a/src/main/java/bc1/gream/domain/sell/controller/SellNowController.java +++ b/src/main/java/bc1/gream/domain/sell/controller/SellNowController.java @@ -11,7 +11,6 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -35,7 +34,7 @@ public class SellNowController { public RestResponse sellNowProduct( @AuthenticationPrincipal UserDetailsImpl userDetails, @PathVariable Long productId, - @Valid @RequestBody SellNowRequestDto requestDto + @Valid SellNowRequestDto requestDto ) { SellNowResponseDto responseDto = sellNowProvider.sellNowProduct(userDetails.getUser(), requestDto, productId); return RestResponse.success(responseDto); From b901860152d63d3d75b284a45813136b67f3a2e0 Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 21:55:35 +0900 Subject: [PATCH 09/16] =?UTF-8?q?[#180]=20fix=20:=20ddl-auto=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=EC=9D=84=20none=20=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index d4988ea6..506eebec 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -10,7 +10,7 @@ spring: # JPA jpa: hibernate: - ddl-auto: update + ddl-auto: none properties: hibernate: auto_quote_keyword: true # 예약어 사용가능 From 3d0b068f0d595c98496745e0a23df72f90c13c66 Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 23:27:21 +0900 Subject: [PATCH 10/16] =?UTF-8?q?[#180]=20fix=20:=20columnDefinition=20?= =?UTF-8?q?=EC=9D=84=20TEXT=20=EB=A1=9C=20=EB=90=98=EC=96=B4=EC=9E=88?= =?UTF-8?q?=EB=8D=98=20=EA=B2=83=EC=9D=84=20@Lob=20=EC=96=B4=EB=85=B8?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EC=85=98=EC=9D=84=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/bc1/gream/domain/gifticon/entity/Gifticon.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/bc1/gream/domain/gifticon/entity/Gifticon.java b/src/main/java/bc1/gream/domain/gifticon/entity/Gifticon.java index d2d56f1d..911447ed 100644 --- a/src/main/java/bc1/gream/domain/gifticon/entity/Gifticon.java +++ b/src/main/java/bc1/gream/domain/gifticon/entity/Gifticon.java @@ -9,6 +9,7 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; import lombok.AccessLevel; @@ -26,7 +27,8 @@ public class Gifticon extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(name = "gifticon_url", columnDefinition = "TEXT") + @Lob + @Column(name = "gifticon_url") private String gifticonUrl; @OneToOne(cascade = CascadeType.PERSIST) From 6c31936ab35f62cf47baa301cbcb1998ff2671e5 Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 23:27:47 +0900 Subject: [PATCH 11/16] =?UTF-8?q?[#180]=20fix=20:=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EB=A5=BC=20=EC=9C=84=ED=95=9C=20H2=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/resources/application-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml index e65fb9ea..f818c1c0 100644 --- a/src/test/resources/application-test.yml +++ b/src/test/resources/application-test.yml @@ -6,11 +6,11 @@ spring: # JPA jpa: database: h2 - generate-ddl: off + generate-ddl: on defer-datasource-initialization: true properties: hibernate: - ddl-auto: none + ddl-auto: create auto_quote_keyword: true # 예약어 사용가능 globally_quoted_identifiers: true # 예약어 사용가능 show_sql: true # sql 로깅 From b989467f13ce3a74e8b604e6209335676d991959 Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 23:28:26 +0900 Subject: [PATCH 12/16] =?UTF-8?q?[#180]=20feat=20:=20=EA=B8=B0=ED=94=84?= =?UTF-8?q?=ED=8B=B0=EC=BD=98=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/bc1/gream/test/GifticonTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/bc1/gream/test/GifticonTest.java b/src/test/java/bc1/gream/test/GifticonTest.java index 4a7f221d..181bb579 100644 --- a/src/test/java/bc1/gream/test/GifticonTest.java +++ b/src/test/java/bc1/gream/test/GifticonTest.java @@ -1,12 +1,16 @@ package bc1.gream.test; import bc1.gream.domain.gifticon.entity.Gifticon; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.web.multipart.MultipartFile; public interface GifticonTest extends OrderTest { Long TEST_GIFTICON_ID = 1L; String TEST_GIFTICON_URL = "images/images.png"; + MultipartFile TEST_GIFTICON_FILE = new MockMultipartFile("file", "image.png", "image/png", "content".getBytes()); + String TEST_S3_IMAGE_URL = "https://cataas.com/cat"; Gifticon TEST_GIFTICON_END = Gifticon.builder() .gifticonUrl(TEST_GIFTICON_URL) From f8301363757c961d96877851fdf453c328cbdcf3 Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 23:29:41 +0900 Subject: [PATCH 13/16] =?UTF-8?q?[#180]=20fix=20:=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=EB=90=9C=20API=20=EC=9A=94=EC=B2=AD=20DTO=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gream/domain/sell/service/SellBidProviderTest.java | 8 ++++++-- .../sell/service/SellNowProviderIntegrationTest.java | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/test/java/bc1/gream/domain/sell/service/SellBidProviderTest.java b/src/test/java/bc1/gream/domain/sell/service/SellBidProviderTest.java index f864525f..bef74d5f 100644 --- a/src/test/java/bc1/gream/domain/sell/service/SellBidProviderTest.java +++ b/src/test/java/bc1/gream/domain/sell/service/SellBidProviderTest.java @@ -16,6 +16,7 @@ import bc1.gream.domain.sell.provider.SellBidProvider; import bc1.gream.domain.sell.repository.SellRepository; import bc1.gream.domain.user.entity.User; +import bc1.gream.infra.s3.S3ImageService; import bc1.gream.test.GifticonTest; import java.io.IOException; import org.junit.jupiter.api.Test; @@ -34,6 +35,8 @@ class SellBidProviderTest implements GifticonTest { GifticonCommandService gifticonCommandService; @Mock SellService sellService; + @Mock + S3ImageService s3ImageService; @InjectMocks SellBidProvider sellBidProvider; @@ -47,10 +50,11 @@ void sellBidProductTest() throws IOException { SellBidRequestDto requestDto = SellBidRequestDto.builder() .price(TEST_SELL_PRICE) - .gifticonUrl(fileResource.getURL().getPath()) + .file(TEST_GIFTICON_FILE) .build(); - given(gifticonCommandService.saveGifticon(requestDto.gifticonUrl(), null)).willReturn(TEST_GIFTICON); + given(s3ImageService.getUrlAfterUpload(requestDto.file())).willReturn(TEST_S3_IMAGE_URL); + given(gifticonCommandService.saveGifticon(TEST_S3_IMAGE_URL, null)).willReturn(TEST_GIFTICON); given(sellRepository.save(any(Sell.class))).willReturn(TEST_SELL); // when diff --git a/src/test/java/bc1/gream/domain/sell/service/SellNowProviderIntegrationTest.java b/src/test/java/bc1/gream/domain/sell/service/SellNowProviderIntegrationTest.java index dd497c14..bc7fcbe4 100644 --- a/src/test/java/bc1/gream/domain/sell/service/SellNowProviderIntegrationTest.java +++ b/src/test/java/bc1/gream/domain/sell/service/SellNowProviderIntegrationTest.java @@ -50,7 +50,7 @@ private void insertBuyByCount(int buyCount) { @Test public void 즉시판매조회() { // GIVEN - SellNowRequestDto requestDto = new SellNowRequestDto(TEST_BUY_PRICE, TEST_GIFTICON_URL); + SellNowRequestDto requestDto = new SellNowRequestDto(TEST_BUY_PRICE, TEST_GIFTICON_FILE); // WHEN SellNowResponseDto responseDto = sellNowProvider.sellNowProduct(savedSeller, requestDto, savedIcedAmericano.getId()); @@ -65,7 +65,7 @@ private void insertBuyByCount(int buyCount) { int threadCount = 100; ExecutorService executorService = Executors.newFixedThreadPool(32); CountDownLatch countDownLatch = new CountDownLatch(threadCount); - SellNowRequestDto requestDto = new SellNowRequestDto(TEST_BUY_PRICE, TEST_GIFTICON_URL); + SellNowRequestDto requestDto = new SellNowRequestDto(TEST_BUY_PRICE, TEST_GIFTICON_FILE); // WHEN List sellNowResponseDtos = new ArrayList<>(); From 17d126f74e1fbf49ea10162cae641198c49c3f6a Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 23:38:44 +0900 Subject: [PATCH 14/16] =?UTF-8?q?[#180]=20feat=20:=20=ED=8C=90=EB=A7=A4=20?= =?UTF-8?q?=EC=9E=85=EC=B0=B0=20=EC=83=9D=EC=84=B1=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=EC=97=90=20=ED=8A=B8=EB=9E=9C=EC=A0=9D=EC=85=98=20?= =?UTF-8?q?=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/bc1/gream/domain/sell/provider/SellBidProvider.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/bc1/gream/domain/sell/provider/SellBidProvider.java b/src/main/java/bc1/gream/domain/sell/provider/SellBidProvider.java index e4efd5f6..e4a6ff19 100644 --- a/src/main/java/bc1/gream/domain/sell/provider/SellBidProvider.java +++ b/src/main/java/bc1/gream/domain/sell/provider/SellBidProvider.java @@ -20,6 +20,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Slf4j @Service @@ -31,6 +32,7 @@ public class SellBidProvider { private final SellService sellService; private final S3ImageService s3ImageService; + @Transactional public SellBidResponseDto createSellBid(User seller, SellBidRequestDto requestDto, Product product) { // 기프티콘 이미지 S3 저장 From 75918d8b3d3cc52a073515f7138f6ed329ca857b Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 23:43:43 +0900 Subject: [PATCH 15/16] =?UTF-8?q?[#180]=20fix=20:=20S3=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EC=8B=A4?= =?UTF-8?q?=ED=8C=A8=20=EC=8B=9C=20=EB=AA=85=ED=99=95=ED=95=9C=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=EC=BD=94=EB=93=9C=EB=A5=BC=20=EB=B0=98=ED=99=98?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/bc1/gream/global/common/ResultCase.java | 6 +++++- src/main/java/bc1/gream/infra/s3/S3ImageService.java | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/bc1/gream/global/common/ResultCase.java b/src/main/java/bc1/gream/global/common/ResultCase.java index 82fc33f9..b3faabfb 100644 --- a/src/main/java/bc1/gream/global/common/ResultCase.java +++ b/src/main/java/bc1/gream/global/common/ResultCase.java @@ -67,7 +67,11 @@ public enum ResultCase { COUPON_ALREADY_IN_USED(HttpStatus.NOT_FOUND, 6002, "해당 쿠폰은 이미 사용중입니다."), COUPON_TYPE_NOT_FOUND(HttpStatus.NOT_FOUND, 6003, "해당 쿠폰 종류는 존재하지 않는 종류입니다."), COUPON_TYPE_INVALID_RATE(HttpStatus.CONFLICT, 6004, "올바른 형식의 고정할인가를 입력해주세요."), - COUPON_TYPE_INVALID_FIXED(HttpStatus.CONFLICT, 6005, "올바른 형식의 할인율을 입력해주세요."); + COUPON_TYPE_INVALID_FIXED(HttpStatus.CONFLICT, 6005, "올바른 형식의 할인율을 입력해주세요."), + + // S3 7000번대 + IMAGE_UPLOAD_FAIL(HttpStatus.INTERNAL_SERVER_ERROR, 7000, "이미지 업로드에 실패했습니다."); + private final HttpStatus httpStatus; private final Integer code; private final String message; diff --git a/src/main/java/bc1/gream/infra/s3/S3ImageService.java b/src/main/java/bc1/gream/infra/s3/S3ImageService.java index c03bdb6d..bdd873a7 100644 --- a/src/main/java/bc1/gream/infra/s3/S3ImageService.java +++ b/src/main/java/bc1/gream/infra/s3/S3ImageService.java @@ -40,7 +40,7 @@ public String getUrlAfterUpload(MultipartFile image) { .withCannedAcl(CannedAccessControlList.PublicRead); amazonS3.putObject(request); } catch (IOException e) { - throw new GlobalException(ResultCase.SYSTEM_ERROR); + throw new GlobalException(ResultCase.IMAGE_UPLOAD_FAIL); } String url = amazonS3.getUrl(bucketName, randomImageName).toString(); From 97e3c71b36185f507a41991ed83d9ebde5cb6775 Mon Sep 17 00:00:00 2001 From: barami62 Date: Sat, 20 Jan 2024 23:59:20 +0900 Subject: [PATCH 16/16] =?UTF-8?q?[#180]=20feat=20:=20S3=20=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=EC=97=90=20=ED=8A=B8=EB=9E=9C=EC=A0=9D?= =?UTF-8?q?=EC=85=94=EB=84=90=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4?= =?UTF-8?q?=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/bc1/gream/infra/s3/S3ImageService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/bc1/gream/infra/s3/S3ImageService.java b/src/main/java/bc1/gream/infra/s3/S3ImageService.java index bdd873a7..56757114 100644 --- a/src/main/java/bc1/gream/infra/s3/S3ImageService.java +++ b/src/main/java/bc1/gream/infra/s3/S3ImageService.java @@ -12,6 +12,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; @Slf4j(topic = "s3 image upload") @@ -24,6 +25,7 @@ public class S3ImageService { @Value("${cloud.aws.s3.bucket}") private String bucketName; + @Transactional public String getUrlAfterUpload(MultipartFile image) { String originalName = image.getOriginalFilename();