diff --git a/build.gradle b/build.gradle index 5e5e699..3b0d108 100644 --- a/build.gradle +++ b/build.gradle @@ -61,8 +61,7 @@ dependencies { implementation group: 'com.google.maps', name: 'google-maps-services', version: '2.2.0' // payment - implementation 'com.github.iamport:iamport-rest-client-java:0.2.23' - implementation 'com.siot:iamport-rest-client:1.2.0' + implementation 'io.portone:server-sdk:0.17.0' compileOnly 'org.projectlombok:lombok' diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 78192c9..96b82ba 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -27,6 +27,8 @@ http { listen [::]:80; server_name api.gongspot.site; + client_max_body_size 10M; + # Let's Encrypt 인증 요청은 HTTP로 유지 location ^~ /.well-known/acme-challenge/ { allow all; diff --git a/src/main/java/com/gongspot/project/domain/order/dto/OrderRequestDTO.java b/src/main/java/com/gongspot/project/domain/order/dto/OrderRequestDTO.java index d933061..27472a0 100644 --- a/src/main/java/com/gongspot/project/domain/order/dto/OrderRequestDTO.java +++ b/src/main/java/com/gongspot/project/domain/order/dto/OrderRequestDTO.java @@ -16,7 +16,7 @@ public class OrderRequestDTO { private Long userId; private Long productId; private PayMethod payMethod; - private BigDecimal totalPrice; + private Long totalPrice; private String merchantUid; } diff --git a/src/main/java/com/gongspot/project/domain/order/service/PortoneApiService.java b/src/main/java/com/gongspot/project/domain/order/service/PortoneApiService.java index 663dd18..fd2b76f 100644 --- a/src/main/java/com/gongspot/project/domain/order/service/PortoneApiService.java +++ b/src/main/java/com/gongspot/project/domain/order/service/PortoneApiService.java @@ -2,34 +2,35 @@ import com.gongspot.project.common.code.status.ErrorStatus; import com.gongspot.project.common.exception.GeneralException; -import com.siot.IamportRestClient.IamportClient; -import com.siot.IamportRestClient.exception.IamportResponseException; -import com.siot.IamportRestClient.response.Payment; + +import io.portone.sdk.server.payment.Payment; +import io.portone.sdk.server.payment.PaymentClient; import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; - -import java.io.IOException; -import java.math.BigDecimal; +import java.util.concurrent.CompletionException; @Slf4j @Service @RequiredArgsConstructor public class PortoneApiService { - private IamportClient iamportClient; + private PaymentClient iamportClient; @Value("${imp.api-key}") private String apiKey; + @Value("${imp.store-id}") + private String storeId; + @Value("${imp.api.secretkey}") private String secretKey; @PostConstruct public void init() { - this.iamportClient = new IamportClient(apiKey, secretKey); + this.iamportClient = new PaymentClient(secretKey,"https://api.portone.io", storeId); } /** @@ -38,27 +39,30 @@ public void init() { * @param impUid 클라이언트로부터 전달받은 결제 고유번호 * @param clientAmount 클라이언트가 요청한 결제 금액 */ - public void verifyPayment(String impUid, BigDecimal clientAmount) { + public void verifyPayment(String impUid, Long clientAmount) { try { - Payment payment = iamportClient.paymentByImpUid(impUid).getResponse(); + Payment payment = iamportClient.getPayment(impUid).join(); - if (payment == null) { - log.error("Payment not found for impUid: {}", impUid); + if (payment instanceof Payment.Unrecognized) { + log.error("Unrecognized payment type for impUid: {}", impUid); throw new GeneralException(ErrorStatus.PAYMENT_NOT_FOUND); } - // 서버 DB에 저장된 금액(clientAmount)과 아임포트 서버의 실제 결제 금액(payment.getAmount()) 비교 - BigDecimal portoneAmount = payment.getAmount(); - if (portoneAmount.compareTo(clientAmount) != 0) { - log.error("Payment amount mismatch. Portone amount: {}, Client amount: {}", portoneAmount, clientAmount); - throw new GeneralException(ErrorStatus.PAYMENT_AMOUNT_MISMATCH); - } + if (payment instanceof Payment.Recognized recognized) { + Long portoneAmount = recognized.getAmount().getTotal(); - log.info("Payment verification successful for impUid: {}", impUid); + if (portoneAmount.compareTo(clientAmount) != 0) { + log.error("Payment amount mismatch. Portone amount: {}, Client amount: {}", portoneAmount, clientAmount); + throw new GeneralException(ErrorStatus.PAYMENT_AMOUNT_MISMATCH); + } - } catch (IamportResponseException | IOException e) { + log.info("Payment verification successful for impUid: {}", impUid); + } + + } catch (CompletionException e) { log.error("Failed to verify payment with impUid: {}", impUid, e); throw new GeneralException(ErrorStatus.PAYMENT_VERIFICATION_FAILED); } } -} + +} \ No newline at end of file diff --git a/src/main/java/com/gongspot/project/domain/review/controller/ReviewController.java b/src/main/java/com/gongspot/project/domain/review/controller/ReviewController.java index 0e156b9..4535852 100644 --- a/src/main/java/com/gongspot/project/domain/review/controller/ReviewController.java +++ b/src/main/java/com/gongspot/project/domain/review/controller/ReviewController.java @@ -21,7 +21,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/reviews") -@Tag(name = "Review") +@Tag(name = "리뷰" , description = "리뷰 관련 API") @Validated public class ReviewController { diff --git a/src/main/java/com/gongspot/project/domain/review/service/ReviewCommandServiceImpl.java b/src/main/java/com/gongspot/project/domain/review/service/ReviewCommandServiceImpl.java index 60899b0..2387e5a 100644 --- a/src/main/java/com/gongspot/project/domain/review/service/ReviewCommandServiceImpl.java +++ b/src/main/java/com/gongspot/project/domain/review/service/ReviewCommandServiceImpl.java @@ -66,18 +66,20 @@ public void saveReview(Long userId, Long placeId, ReviewRequestDTO.ReviewRegiste likeRepository.save(newLike); } - for (MultipartFile picture : reviewPictures) { - String uuid = UUID.randomUUID().toString(); - Uuid savedUuid = uuidRepository.save(Uuid.builder() - .uuid(uuid).build()); + if (reviewPictures != null && !reviewPictures.isEmpty()) { + for (MultipartFile picture : reviewPictures) { + String uuid = UUID.randomUUID().toString(); + Uuid savedUuid = uuidRepository.save(Uuid.builder() + .uuid(uuid).build()); - ObjectMetadata metadata = new ObjectMetadata(); - metadata.setContentLength(picture.getSize()); - metadata.setContentType(picture.getContentType()); + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentLength(picture.getSize()); + metadata.setContentType(picture.getContentType()); - String pictureUrl = s3Manager.uploadFile(s3Manager.generateReviewKeyName(savedUuid), savedUuid.getUuid(), picture, metadata); + String pictureUrl = s3Manager.uploadFile(s3Manager.generateReviewKeyName(savedUuid), savedUuid.getUuid(), picture, metadata); - mediaRepository.save(ReviewConverter.toReviewImage(pictureUrl, picture.getOriginalFilename(), picture.getContentType(), newReview)); + mediaRepository.save(ReviewConverter.toReviewImage(pictureUrl, picture.getOriginalFilename(), picture.getContentType(), newReview)); + } } } catch (DataIntegrityViolationException e) { throw new BusinessException(ErrorStatus.REVIEW_SAVE_FAIL); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8194d4f..7e04618 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -70,4 +70,5 @@ spring.servlet.multipart.max-request-size=10MB # iamport payment imp.api-key = ${IMP_API_KEY} imp.api.secretkey = ${IMP_SECRET_KEY} -imp.imp_uid=${IMP_UID} \ No newline at end of file +imp.imp_uid=${IMP_UID} +imp.store-id=${IMP_SID} \ No newline at end of file