From 02ceaadab9f26193dc5858d7da7f31f7f5fc61dc Mon Sep 17 00:00:00 2001 From: kihoo-ni Date: Wed, 31 Jul 2024 16:24:15 +0900 Subject: [PATCH] =?UTF-8?q?javadoc=20"=EC=BF=A0=ED=8F=B0=20javadoc=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomCategoryCouponRepository.java | 11 +++ .../controller/CouponPolicyController.java | 51 ++++++++++++ .../CustomCouponPolicyRepository.java | 23 ++++++ .../service/CouponPolicyService.java | 47 ++++++++++- .../controller/CouponTemplateController.java | 27 ++++++- .../CustomCouponTemplateRepository.java | 23 ++++++ .../service/CouponTemplateService.java | 28 +++++++ .../global/config/RabbitMQConfig.java | 71 +++++++++++++++++ .../global/controller/SwaggerController.java | 21 +++++ .../handler/GlobalExceptionHandler.java | 37 +++++++++ .../listener/CouponIssuanceListener.java | 16 ++++ .../controller/UserAndCouponController.java | 78 ++++++++++++++++++- .../feignclient/UserBirthdayFeignClient.java | 14 ++++ .../CustomUserAndCouponRepository.java | 47 +++++++++++ .../repository/UserAndCouponRepository.java | 19 +++++ .../service/UserAndCouponService.java | 75 ++++++++++++++++-- 16 files changed, 574 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/categorycoupon/repository/CustomCategoryCouponRepository.java b/src/main/java/com/nhnacademy/bookstorecoupon/categorycoupon/repository/CustomCategoryCouponRepository.java index f6eade8..772026e 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/categorycoupon/repository/CustomCategoryCouponRepository.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/categorycoupon/repository/CustomCategoryCouponRepository.java @@ -4,6 +4,17 @@ import com.nhnacademy.bookstorecoupon.categorycoupon.domain.entity.CategoryCoupon; + + +/** + * @author 이기훈 + * 카테고리 쿠폰 테이블에 있는 정보를 querydsl을 통해 가져오는 custom repository + */ public interface CustomCategoryCouponRepository { + + /** + * 카테고리 쿠폰 테이블에 있는 정보를 querydsl을 통해 가져오는 custom repository + * @return 쿠폰정책 아이디, 카테고리 아이디, 카테고리 이름 + */ Map fetchCategoryIdMap(); } \ No newline at end of file diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/couponpolicy/controller/CouponPolicyController.java b/src/main/java/com/nhnacademy/bookstorecoupon/couponpolicy/controller/CouponPolicyController.java index a6d9a21..f2c8c94 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/couponpolicy/controller/CouponPolicyController.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/couponpolicy/controller/CouponPolicyController.java @@ -29,6 +29,14 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; + + + + +/** + * @author 이기훈 + * 쿠폰정책관련 기능을 수행하는 컨트롤러입니다. + */ @Tag(name = "CouponPolicy", description = "쿠폰 정책관련 API") @RestController @RequestMapping("/coupons/policies") @@ -39,6 +47,12 @@ public CouponPolicyController(CouponPolicyService couponPolicyService) { this.couponPolicyService = couponPolicyService; } + + + /** + * 웰컴쿠폰 정책을 생성하는 컨트롤러 + * @param couponPolicyRequestDTO 쿠폰정책 생성 dto + */ @Operation( summary = "웰컴쿠폰정책 생성", description = "웰컴쿠폰정책을 생성합니다" @@ -55,6 +69,14 @@ public ResponseEntity issueWelcomeCoupon( couponPolicyService.issueWelcomeCoupon(couponPolicyRequestDTO); return ResponseEntity.status(HttpStatus.CREATED).build(); } + + + + + /** + * 생일쿠폰 정책을 생성하는 컨트롤러 + * @param couponPolicyRequestDTO 쿠폰정책 생성 dto + */ @Operation( summary = "생일쿠폰정책 생성", description = "생일쿠폰정책을 생성합니다" @@ -73,6 +95,10 @@ public ResponseEntity issueBirthdayCoupon( } + /** + * 도서쿠폰 정책을 생성하는 컨트롤러 + * @param couponPolicyRequestDTO 쿠폰정책 생성 dto + */ @Operation(summary = "도서 쿠폰 발행", description = "특정 도서에 대한 도서쿠폰을 발행합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "도서쿠폰이 성공적으로 발행되었습니다."), @@ -91,6 +117,12 @@ public ResponseEntity issueSpecificBookCoupon( return ResponseEntity.status(HttpStatus.CREATED).build(); } + + + /** + * 카테고리쿠폰 정책을 생성하는 컨트롤러 + * @param couponPolicyRequestDTO 쿠폰정책 생성 dto + */ @Operation(summary = "카테고리 쿠폰 발행", description = "특정 카테고리에 대한 카테고리쿠폰을 발행합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "카테고리쿠폰이 성공적으로 발행되었습니다."), @@ -110,6 +142,11 @@ public ResponseEntity issueSpecificCategoryCoupon( } + + /** + * 할인쿠폰 정책을 생성하는 컨트롤러 + * @param couponPolicyRequestDTO 쿠폰정책 생성 dto + */ @Operation(summary = "할인 쿠폰 발행", description = "할인 쿠폰을 발행합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "할인쿠폰이 성공적으로 발행되었습니다."), @@ -124,6 +161,12 @@ public ResponseEntity issueDiscountCoupon( return ResponseEntity.status(HttpStatus.CREATED).build(); } + + + /** + * 모든 쿠폰 정책을 불러오는 컨트롤러 + * @param pageable 페이지 정보 + */ @Operation(summary = "모든 쿠폰 정책 조회", description = "페이징을 통해 모든 쿠폰 정책을 조회합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "성공적으로 조회되었습니다.") @@ -137,6 +180,10 @@ public ResponseEntity> getAllCouponPolicies(@Param + /** + * 쿠폰정책을 수정하는 컨트롤러 + * @param requestDTO 쿠폰 업데이트 dto + */ @Operation(summary = "쿠폰 정책 업데이트", description = "쿠폰 정책을 업데이트합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "성공적으로 업데이트되었습니다."), @@ -159,6 +206,10 @@ public ResponseEntity updateCouponPolicy( } + /** + * 쿠폰정책생성 유효성을 검사하는 메소드 + * @param requestDTO 쿠폰정책생성 dto + */ // SalePrice와 SaleRate 유효성 검사 메서드 추가 private void validateSaleFields(CouponPolicyRequestDTO requestDTO) { if ((requestDTO.salePrice() == null && requestDTO.saleRate() == null && requestDTO.maxSalePrice() == null) || diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/couponpolicy/repository/CustomCouponPolicyRepository.java b/src/main/java/com/nhnacademy/bookstorecoupon/couponpolicy/repository/CustomCouponPolicyRepository.java index 6f0c28a..b65a08d 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/couponpolicy/repository/CustomCouponPolicyRepository.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/couponpolicy/repository/CustomCouponPolicyRepository.java @@ -11,7 +11,30 @@ import com.nhnacademy.bookstorecoupon.couponpolicy.domain.dto.response.CouponPolicyResponseDTO; import com.nhnacademy.bookstorecoupon.couponpolicy.domain.entity.CouponPolicy; + + + +/** + * @author 이기훈 + * 쿠폰정책 테이블에 있는 정보를 querydsl을 통해 가져오는 custom repository + */ public interface CustomCouponPolicyRepository { + + + /** + * 쿠폰 정책 테이블에 있는 정보를 querydsl을 통해 가져오는 custom repository method + * @param pageable 페이지정보 + * @param bookIdMap 도서관련 정보 + * @param categoryIdMap 카테고리관련 정보 + * @return 쿠폰정책 응답 dto + */ Page findAllWithBooksAndCategories(Pageable pageable, Map bookIdMap, Map categoryIdMap); + + + /** + * 해당 쿠폰타입에서 가장 최신의 정책을 불러오는 method + * @param type 쿠폰정책 타입 + * @return 쿠폰정책 entity + */ Optional findLatestCouponPolicyByType(String type); } diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/couponpolicy/service/CouponPolicyService.java b/src/main/java/com/nhnacademy/bookstorecoupon/couponpolicy/service/CouponPolicyService.java index bf3cb58..7b179ae 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/couponpolicy/service/CouponPolicyService.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/couponpolicy/service/CouponPolicyService.java @@ -7,22 +7,61 @@ import com.nhnacademy.bookstorecoupon.couponpolicy.domain.dto.request.CouponPolicyUpdateRequestDTO; import com.nhnacademy.bookstorecoupon.couponpolicy.domain.dto.response.CouponPolicyResponseDTO; + +/** + * 쿠폰 정책을 관리하는 서비스 레이어를 나타내는 인터페이스입니다. + * + * @author 이기훈 + */ public interface CouponPolicyService { + /** + * 주어진 요청 데이터에 기반하여 환영 쿠폰을 발급합니다. + * + * @param requestDTO 환영 쿠폰 발급에 필요한 데이터 전송 객체 + */ void issueWelcomeCoupon(CouponPolicyRequestDTO requestDTO); + /** + * 주어진 요청 데이터에 기반하여 생일 쿠폰을 발급합니다. + * + * @param requestDTO 생일 쿠폰 발급에 필요한 데이터 전송 객체 + */ void issueBirthdayCoupon(CouponPolicyRequestDTO requestDTO); + /** + * 주어진 요청 데이터에 기반하여 특정 도서에 대한 쿠폰을 발급합니다. + * + * @param requestDTO 특정 도서 쿠폰 발급에 필요한 데이터 전송 객체 + */ void issueSpecificBookCoupon(CouponPolicyRequestDTO requestDTO); + /** + * 주어진 요청 데이터에 기반하여 특정 카테고리에 대한 쿠폰을 발급합니다. + * + * @param requestDTO 특정 카테고리 쿠폰 발급에 필요한 데이터 전송 객체 + */ void issueSpecificCategoryCoupon(CouponPolicyRequestDTO requestDTO); + /** + * 주어진 요청 데이터에 기반하여 할인 쿠폰을 발급합니다. + * + * @param requestDTO 할인 쿠폰 발급에 필요한 데이터 전송 객체 + */ void issueDiscountCoupon(CouponPolicyRequestDTO requestDTO); + /** + * 페이지네이션을 지원하여 모든 쿠폰 정책을 조회합니다. + * + * @param pageable 페이지 번호, 페이지 크기, 정렬 정보 등을 포함하는 페이지네이션 정보 + * @return 쿠폰 정책 응답 데이터 전송 객체의 페이지 + */ Page getAllCouponPolicies(Pageable pageable); - - + /** + * 주어진 ID를 가진 기존 쿠폰 정책을 새 데이터로 업데이트합니다. + * + * @param id 업데이트할 쿠폰 정책의 ID + * @param requestDTO 쿠폰 정책에 대한 업데이트된 데이터 전송 객체 + */ void updateCouponPolicy(Long id, CouponPolicyUpdateRequestDTO requestDTO); - - } diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/coupontemplate/controller/CouponTemplateController.java b/src/main/java/com/nhnacademy/bookstorecoupon/coupontemplate/controller/CouponTemplateController.java index 78ec429..a2c2216 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/coupontemplate/controller/CouponTemplateController.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/coupontemplate/controller/CouponTemplateController.java @@ -23,6 +23,14 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; + + +/** + * 쿠폰 템플릿과 관련된 API를 제공하는 컨트롤러입니다. + * 쿠폰 템플릿 생성 및 조회를 위한 엔드포인트를 제공합니다. + * + * @author 이기훈 + */ @Tag(name = "CouponTemplate", description = "쿠폰템플릿관련 API") @RestController @RequestMapping("/coupons") @@ -38,6 +46,12 @@ public CouponTemplateController(CouponTemplateService couponTemplateService) { + /** + * 새로운 쿠폰 템플릿을 생성합니다. + * + * @param requestDTO 쿠폰 템플릿 발행에 필요한 데이터 전송 객체 + * @return 쿠폰 템플릿 생성 결과를 담고 있는 HTTP 응답 + */ @Operation(summary = "쿠폰 템플릿 생성", description = "새로운 쿠폰 템플릿을 생성합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "쿠폰 템플릿이 성공적으로 생성되었습니다."), @@ -51,6 +65,12 @@ public ResponseEntity createCouponTemplate(@Parameter(description = "쿠 } + /** + * 유저 기준으로 페이징된 모든 쿠폰 템플릿을 조회합니다. + * + * @param pageable 페이지 번호와 페이지 크기 정보 + * @return {@link ResponseEntity} 페이징된 쿠폰 템플릿 목록을 담고 있는 HTTP 응답 + */ @Operation(summary = "유저 페이징으로 모든 쿠폰 템플릿 조회", description = "유저 기준으로 페이징된 모든 쿠폰 템플릿을 조회합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "쿠폰 템플릿 조회 성공"), @@ -64,7 +84,12 @@ public ResponseEntity> getAllCouponTemplatesByUs } - + /** + * 관리자 기준으로 페이징된 모든 쿠폰 템플릿을 조회합니다. + * + * @param pageable 페이지 번호와 페이지 크기 정보 + * @return {@link ResponseEntity} 페이징된 쿠폰 템플릿 목록을 담고 있는 HTTP 응답 + */ @Operation(summary = "관리자 페이징으로 모든 쿠폰 템플릿 조회", description = "관리자 기준으로 페이징된 모든 쿠폰 템플릿을 조회합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "쿠폰 템플릿 조회 성공"), diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/coupontemplate/repository/CustomCouponTemplateRepository.java b/src/main/java/com/nhnacademy/bookstorecoupon/coupontemplate/repository/CustomCouponTemplateRepository.java index a943f36..4cbcbdc 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/coupontemplate/repository/CustomCouponTemplateRepository.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/coupontemplate/repository/CustomCouponTemplateRepository.java @@ -9,10 +9,33 @@ import com.nhnacademy.bookstorecoupon.categorycoupon.domain.entity.CategoryCoupon; import com.nhnacademy.bookstorecoupon.coupontemplate.domain.dto.response.CouponTemplateResponseDTO; +/** + * 쿠폰 템플릿과 관련된 사용자 정의 데이터 접근 레이어 인터페이스입니다. + * 이 인터페이스는 사용자와 관리자가 페이징된 쿠폰 템플릿을 조회할 수 있도록 하는 메소드를 제공합니다. + * + * @author 이기훈 + */ public interface CustomCouponTemplateRepository { + /** + * 사용자 기준으로 페이징된 모든 쿠폰 템플릿을 조회합니다. + * + * @param pageable 페이지 번호와 페이지 크기 정보 + * @param bookIdMap 책 ID와 관련된 쿠폰 정보 맵 + * @param categoryIdMap 카테고리 ID와 관련된 쿠폰 정보 맵 + * @return 페이징된 쿠폰 템플릿 목록 + */ Page findAllTemplatesByUserPaging(Pageable pageable, Map bookIdMap, Map categoryIdMap); + + /** + * 관리자 기준으로 페이징된 모든 쿠폰 템플릿을 조회합니다. + * + * @param pageable 페이지 번호와 페이지 크기 정보 + * @param bookIdMap 책 ID와 관련된 쿠폰 정보 맵 + * @param categoryIdMap 카테고리 ID와 관련된 쿠폰 정보 맵 + * @return 페이징된 쿠폰 템플릿 목록 + */ Page findAllTemplatesByManagerPaging(Pageable pageable, Map bookIdMap, Map categoryIdMap); diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/coupontemplate/service/CouponTemplateService.java b/src/main/java/com/nhnacademy/bookstorecoupon/coupontemplate/service/CouponTemplateService.java index 8e560d7..4a7b58c 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/coupontemplate/service/CouponTemplateService.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/coupontemplate/service/CouponTemplateService.java @@ -6,12 +6,40 @@ import com.nhnacademy.bookstorecoupon.coupontemplate.domain.dto.request.CouponTemplateRequestDTO; import com.nhnacademy.bookstorecoupon.coupontemplate.domain.dto.response.CouponTemplateResponseDTO; +/** + * 쿠폰 템플릿과 관련된 서비스 인터페이스입니다. + * 이 인터페이스는 쿠폰 템플릿을 생성하고, 페이징된 쿠폰 템플릿 목록을 관리하는 기능을 제공합니다. + * + * @author 이기훈 + */ + public interface CouponTemplateService { + + /** + * 새로운 쿠폰 템플릿을 생성합니다. + * + * @param requestDTO 생성할 쿠폰 템플릿의 요청 데이터 + */ void createCouponTemplate(CouponTemplateRequestDTO requestDTO); + + /** + * 관리자를 기준으로 페이징된 모든 쿠폰 템플릿을 조회합니다. + * + * @param pageable 페이지 번호와 페이지 크기 정보 + * @return 관리자가 조회할 수 있는 페이징된 쿠폰 템플릿 목록 + */ Page getAllCouponTemplatesByManagerPaging(Pageable pageable); + + + /** + * 사용자를 기준으로 페이징된 모든 쿠폰 템플릿을 조회합니다. + * + * @param pageable 페이지 번호와 페이지 크기 정보 + * @return 사용자가 조회할 수 있는 페이징된 쿠폰 템플릿 목록 + */ Page getAllCouponTemplatesByUserPaging(Pageable pageable); diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/global/config/RabbitMQConfig.java b/src/main/java/com/nhnacademy/bookstorecoupon/global/config/RabbitMQConfig.java index e8c47fc..4c1e9af 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/global/config/RabbitMQConfig.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/global/config/RabbitMQConfig.java @@ -16,6 +16,15 @@ import com.nhnacademy.bookstorecoupon.global.listener.CouponIssuanceListener; + +/** + * RabbitMQ 관련 설정을 정의하는 구성 클래스입니다. + *

+ * 이 클래스는 RabbitMQ와의 연결, 큐, 교환기, 바인딩 및 메시지 컨버터를 설정합니다. + *

+ * + * @author 이기훈 + */ @Configuration @EnableRabbit public class RabbitMQConfig { @@ -36,26 +45,68 @@ public class RabbitMQConfig { + /** + * 쿠폰 발급을 위한 큐를 생성합니다. + *

+ * 큐는 기본적으로 내구성이 없으며, 큐 이름은 {@link #COUPON_ISSUE_QUEUE}입니다. + *

+ * + * @return 생성된 {@link Queue} 객체 + */ @Bean public Queue couponIssueQueue() { return new Queue(COUPON_ISSUE_QUEUE, false); } + /** + * 메시지를 JSON 형식으로 변환하는 {@link Jackson2JsonMessageConverter}를 생성합니다. + * + * @return 생성된 {@link Jackson2JsonMessageConverter} 객체 + */ @Bean public Jackson2JsonMessageConverter jsonMessageConverter() { return new Jackson2JsonMessageConverter(); } + /** + * RabbitMQ의 직접 교환기를 생성합니다. + *

+ * 교환기 이름은 "5ritang.coupon.exchange"입니다. + *

+ * + * @return 생성된 {@link DirectExchange} 객체 + */ @Bean DirectExchange directExchange() { return new DirectExchange("5ritang.coupon.exchange"); } + /** + * 큐와 교환기를 바인딩하는 {@link Binding}을 생성합니다. + *

+ * 큐는 {@link #couponIssueQueue()}에서 생성되며, 교환기는 {@link #directExchange()}에서 생성됩니다. + * 바인딩 키는 "5ritang.coupon.key"입니다. + *

+ * + * @param directExchange 직접 교환기 + * @param couponIssueQueue 쿠폰 발급 큐 + * @return 생성된 {@link Binding} 객체 + */ @Bean Binding binding(DirectExchange directExchange, Queue couponIssueQueue) { return BindingBuilder.bind(couponIssueQueue).to(directExchange).with("5ritang.coupon.key"); } + + /** + * RabbitTemplate을 생성합니다. + *

+ * 이 템플릿은 메시지 변환기로 {@link #jsonMessageConverter()}를 사용합니다. + *

+ * + * @param connectionFactory RabbitMQ 연결 팩토리 + * @return 생성된 {@link RabbitTemplate} 객체 + */ @Bean public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); @@ -63,6 +114,17 @@ public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { return rabbitTemplate; } + + /** + * 메시지 리스너 컨테이너를 생성합니다. + *

+ * 이 컨테이너는 {@link #couponIssueQueue()}에서 생성된 큐와 {@link CouponIssuanceListener}를 사용합니다. + *

+ * + * @param connectionFactory RabbitMQ 연결 팩토리 + * @param couponIssuanceListener 쿠폰 발급 리스너 + * @return 생성된 {@link SimpleMessageListenerContainer} 객체 + */ @Bean public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory, CouponIssuanceListener couponIssuanceListener) { @@ -73,6 +135,15 @@ public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory return container; } + + /** + * RabbitMQ와의 연결을 위한 {@link ConnectionFactory}를 생성합니다. + *

+ * 이 팩토리는 호스트, 포트, 사용자 이름 및 비밀번호를 설정합니다. + *

+ * + * @return 생성된 {@link ConnectionFactory} 객체 + */ @Bean ConnectionFactory connectionFactory() { CachingConnectionFactory connectionFactory = new CachingConnectionFactory(); diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/global/controller/SwaggerController.java b/src/main/java/com/nhnacademy/bookstorecoupon/global/controller/SwaggerController.java index f62c24a..393fb3f 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/global/controller/SwaggerController.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/global/controller/SwaggerController.java @@ -14,6 +14,16 @@ import jakarta.servlet.http.HttpServletRequest; + + +/** + * Swagger 문서에 대한 API를 제공하는 컨트롤러입니다. + *

+ * 이 컨트롤러는 Swagger API 문서를 JSON 형식으로 반환합니다. + *

+ * + * @author 이기훈 + */ @RestController @RequestMapping("/coupons/api") public class SwaggerController { @@ -21,6 +31,17 @@ public class SwaggerController { @Autowired private OpenApiResource openApiResource; + + /** + * Swagger API 문서를 JSON 형식으로 반환합니다. + *

+ * 이 메소드는 현재 요청의 Locale을 사용하여 Swagger 문서의 JSON 형식을 결정합니다. + *

+ * + * @param request HTTP 요청 객체 + * @return Swagger 문서의 JSON 표현을 포함한 {@link ResponseEntity} + * @throws JsonProcessingException JSON 처리 중 오류가 발생한 경우 + */ @GetMapping() public ResponseEntity getSwaggerJson(HttpServletRequest request) throws JsonProcessingException { String apiDocsUrl = "/coupon-docs/coupon-api"; // Swagger 문서 URL diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/global/handler/GlobalExceptionHandler.java b/src/main/java/com/nhnacademy/bookstorecoupon/global/handler/GlobalExceptionHandler.java index 6ed4226..79397db 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/global/handler/GlobalExceptionHandler.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/global/handler/GlobalExceptionHandler.java @@ -15,11 +15,28 @@ import lombok.extern.slf4j.Slf4j; + + +/** + * 글로벌 예외를 처리하는 클래스입니다. + * 이 클래스는 애플리케이션 전역에서 발생하는 예외를 처리하여 적절한 HTTP 응답을 반환합니다. + * + * @author 이기훈 + */ @Slf4j @RestControllerAdvice public class GlobalExceptionHandler { + + /** + * MethodArgumentNotValidException 예외를 처리합니다. + * 요청 파라미터의 유효성 검증 실패 시 발생하는 예외를 처리합니다. + * 오류 메시지를 생성하여 ErrorStatus 객체로 응답합니다. + * + * @param exception 발생한 MethodArgumentNotValidException + * @return ResponseEntity containing ErrorStatus with validation error details + */ @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity processValidationError(MethodArgumentNotValidException exception) { BindingResult bindingResult = exception.getBindingResult(); @@ -51,6 +68,15 @@ public ResponseEntity processValidationError(MethodArgumentNotValid + /** + * GlobalException 예외를 처리합니다. + *

+ * 애플리케이션의 전역적인 예외를 처리하고, 해당 예외에 대한 ErrorStatus 객체를 응답합니다. + *

+ * + * @param ex 발생한 GlobalException + * @return ResponseEntity containing ErrorStatus with global error details + */ @ExceptionHandler({GlobalException.class}) public ResponseEntity handleGlobalException(GlobalException ex) { ErrorStatus errorStatus=ex.getErrorStatus(); @@ -61,6 +87,17 @@ public ResponseEntity handleGlobalException(GlobalException ex) { + + + /** + * 모든 {@link Exception} 예외를 처리합니다. + *

+ * 처리되지 않은 예외를 포괄적으로 처리하여 500 상태 코드와 함께 응답합니다. + *

+ * + * @param ex 발생한 {@link Exception} + * @return {@link ResponseEntity} with HTTP status 500 + */ @ExceptionHandler({Exception.class}) public ResponseEntity handleException(Exception ex) { diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/global/listener/CouponIssuanceListener.java b/src/main/java/com/nhnacademy/bookstorecoupon/global/listener/CouponIssuanceListener.java index c25d93a..5794b8b 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/global/listener/CouponIssuanceListener.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/global/listener/CouponIssuanceListener.java @@ -20,6 +20,14 @@ import lombok.extern.slf4j.Slf4j; + + +/** + * 쿠폰 발급을 처리하는 리스너입니다. + * 메시지를 수신하여 쿠폰 템플릿을 조회하고, 쿠폰 발급 및 수량 업데이트를 수행합니다. + * + * @author 이기훈 + */ @Slf4j @Component public class CouponIssuanceListener implements MessageListener { @@ -34,6 +42,14 @@ public CouponIssuanceListener(UserAndCouponRepository userAndCouponRepository, this.couponTemplateRepository = couponTemplateRepository; } + + /** + * 메시지를 수신하여 쿠폰 발급을 처리합니다. + * 메시지에서 쿠폰 발급 정보를 추출하고, 쿠폰 템플릿을 조회하여 수량을 확인합니다. + * 수량이 충분한 경우, 쿠폰을 발급하고 쿠폰 템플릿의 수량을 업데이트합니다. + * + * @param message 수신한 메시지 + */ @Override @Transactional public void onMessage(Message message) { diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/controller/UserAndCouponController.java b/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/controller/UserAndCouponController.java index 9a1ab67..83e5ff8 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/controller/UserAndCouponController.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/controller/UserAndCouponController.java @@ -35,6 +35,16 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; + + +/** + * 사용자와 쿠폰 관련 API를 제공하는 컨트롤러 클래스입니다. + *

+ * 이 클래스는 사용자에게 쿠폰을 발행하거나 조회하는 등의 기능을 제공합니다. + *

+ * + * @author 이기훈 + */ @RestController @RequestMapping("/coupons") @Tag(name = "UserAndCoupon", description = "사용자 쿠폰관련 API") @@ -48,6 +58,14 @@ public UserAndCouponController(UserAndCouponService userAndCouponService, Rabbit this.rabbitMQUserAndCouponService = rabbitMQUserAndCouponService; } + + /** + * 특정 쿠폰 ID로 사용자에게 쿠폰을 발행합니다. + * + * @param couponId 쿠폰 ID + * @param currentUser 현재 인증된 사용자 정보 + * @return 쿠폰 발행 결과 + */ @Operation(summary = "사용자와 쿠폰 생성", description = "특정 쿠폰 ID로 사용자에게 쿠폰을 발행합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "쿠폰이 성공적으로 발행되었습니다."), @@ -62,6 +80,13 @@ public ResponseEntity createUserAndCoupon(@Parameter(description = "쿠폰 } + + /** + * 특정 사용자에게 웰컴 쿠폰을 발행합니다. + * + * @param userId 사용자 ID + * @return 웰컴 쿠폰 발행 결과 + */ @Operation(summary = "웰컴 쿠폰 생성", description = "특정 사용자에게 웰컴 쿠폰을 발행합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "웰컴 쿠폰이 성공적으로 발행되었습니다."), @@ -80,6 +105,13 @@ public ResponseEntity createUserWelcomeCouponIssue(@Parameter(description + /** + * 특정 사용자 기준으로 페이징된 모든 쿠폰을 조회합니다. + * + * @param currentUser 현재 인증된 사용자 정보 + * @param pageable 페이지 요청 정보 + * @return 페이징된 사용자 쿠폰 목록 + */ @Operation(summary = "마이페이지 쿠폰 조회", description = "특정 사용자 기준으로 페이징된 모든 쿠폰을 조회합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "쿠폰 조회 성공"), @@ -98,7 +130,14 @@ public ResponseEntity> getAllUserAndCouponsByUser return ResponseEntity.status(HttpStatus.OK).body(coupons); } - + /** + * 관리자 기준으로 페이징된 모든 사용자 쿠폰을 조회합니다. + * + * @param pageable 페이지 요청 정보 + * @param type 정책 타입 (선택 사항) + * @param userId 사용자 ID (선택 사항) + * @return 페이징된 사용자 쿠폰 목록 + */ @Operation(summary = "관리자 기준 페이징된 사용자 쿠폰 조회", description = "관리자 기준으로 페이징된 모든 사용자 쿠폰을 조회합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "쿠폰 조회 성공"), @@ -117,6 +156,15 @@ public ResponseEntity> getAllUsersAndCouponsByMan } + /** + * 특정 주문에 대한 쿠폰을 조회합니다. + * + * @param currentUserDetails 현재 인증된 사용자 정보 + * @param bookIds 도서 ID 목록 (선택 사항) + * @param categoryIds 카테고리 ID 목록 (선택 사항) + * @param bookPrice 도서 가격 + * @return 특정 주문에 대한 쿠폰 목록 + */ @Operation(summary = "단건 주문에 대한 쿠폰 조회", description = "특정 주문에 대한 쿠폰을 조회합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "쿠폰 조회 성공"), @@ -142,6 +190,13 @@ public ResponseEntity> findCouponByOrder( + /** + * 특정 장바구니 주문에 대한 쿠폰을 조회합니다. + * + * @param currentUserDetails 현재 인증된 사용자 정보 + * @param bookDetails 도서 주문 정보 (선택 사항) + * @return 특정 장바구니 주문에 대한 쿠폰 목록 + */ @Operation(summary = "장바구니 주문에 대한 쿠폰 조회", description = "특정 장바구니 주문에 대한 쿠폰을 조회합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "쿠폰 조회 성공"), @@ -165,6 +220,12 @@ public ResponseEntity> findCouponByCartOrder( } + /** + * 특정 사용자 쿠폰 ID로 쿠폰을 결제 후 사용됨 처리합니다. + * + * @param userAndCouponId 사용자 쿠폰 ID + * @return 쿠폰 사용됨 처리 결과 + */ @Operation(summary = "결제 후 쿠폰 사용됨처리", description = "특정 사용자 쿠폰 ID로 쿠폰을 결제 후 사용됨 처리합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "쿠폰이 성공적으로 업데이트되었습니다."), @@ -188,7 +249,12 @@ public ResponseEntity updateCouponAfterPayment( - + /** + * 특정 쿠폰 ID로 선택된 쿠폰을 조회합니다. + * + * @param couponId 쿠폰 ID + * @return 선택된 쿠폰 정보 + */ @Operation(summary = "선택된 쿠폰 조회", description = "특정 쿠폰 ID로 선택된 쿠폰을 조회합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "쿠폰 조회 성공"), @@ -207,8 +273,12 @@ public ResponseEntity getSelectedCoupon( return ResponseEntity.status(HttpStatus.OK).body(coupon); } - - + /** + * 비회원인지 회원인지 검사합니다. + * + * @param currentUserDetails 현재 인증된 사용자 정보 + * @return 사용자의 회원 여부 + */ @Operation(summary = "회원인지 아닌지 검사", description = "비회원인지 회원인지 검사합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "검사결과를 true or false로 반환"), diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/feignclient/UserBirthdayFeignClient.java b/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/feignclient/UserBirthdayFeignClient.java index bbdf381..1cee320 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/feignclient/UserBirthdayFeignClient.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/feignclient/UserBirthdayFeignClient.java @@ -10,10 +10,24 @@ import com.nhnacademy.bookstorecoupon.userandcoupon.domain.dto.response.BirthdayCouponTargetResponse; +/** + * 사용자 생일 정보를 조회하는 Feign 클라이언트 인터페이스입니다. + *

+ * 이 클라이언트는 외부 서비스에서 사용자 생일 정보를 가져오기 위해 사용됩니다. + *

+ * + * @FeignClient(name = "user-birthday-feign-client", url = "...") + */ @FeignClient(name = "user-birthday-feign-client", url = "http://localhost:8083") public interface UserBirthdayFeignClient { + /** + * 주어진 날짜에 생일을 가진 사용자 목록을 조회합니다. + * + * @param date 조회할 날짜 (생일) + * @return 주어진 날짜에 생일을 가진 사용자 목록이 포함된 {@link ResponseEntity} + */ @GetMapping("/api/users/birthday") ResponseEntity> getUsersWithBirthday( @RequestParam("date") LocalDate date); diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/repository/CustomUserAndCouponRepository.java b/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/repository/CustomUserAndCouponRepository.java index 1465dc3..c4f6e06 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/repository/CustomUserAndCouponRepository.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/repository/CustomUserAndCouponRepository.java @@ -12,19 +12,66 @@ import com.nhnacademy.bookstorecoupon.userandcoupon.domain.dto.response.GetBookByOrderCouponResponse; import com.nhnacademy.bookstorecoupon.userandcoupon.domain.dto.response.UserAndCouponResponseDTO; +/** + * 사용자와 쿠폰 관련 데이터에 대한 커스텀 리포지토리 인터페이스입니다. + *

+ * 이 인터페이스는 사용자와 쿠폰 관련 데이터를 조회하기 위한 메소드들을 정의하고 있습니다. + *

+ */ public interface CustomUserAndCouponRepository { + + /** + * 주어진 사용자 ID와 페이징 정보를 기준으로 사용자 쿠폰을 조회합니다. + * + * @param pageable 페이징 정보 (페이지 번호와 페이지 크기) + * @param userId 사용자 ID + * @param bookIdMap 도서 ID와 도서 정보를 매핑한 맵 + * @param categoryIdMap 카테고리 ID와 카테고리 정보를 매핑한 맵 + * @return 사용자 쿠폰에 대한 페이징된 결과가 포함된 {@link Page} + */ + Page findAllByUserPaging(Pageable pageable, Long userId, Map bookIdMap, Map categoryIdMap); + /** + * 관리자 기준으로 페이징된 사용자 쿠폰을 조회합니다. + * + * @param pageable 페이징 정보 (페이지 번호와 페이지 크기) + * @param type 쿠폰 정책 타입 + * @param userId (선택적) 사용자 ID + * @param bookIdMap 도서 ID와 도서 정보를 매핑한 맵 + * @param categoryIdMap 카테고리 ID와 카테고리 정보를 매핑한 맵 + * @return 사용자 쿠폰에 대한 페이징된 결과가 포함된 {@link Page} + */ Page findAllByManagerPaging(Pageable pageable, String type, Long userId, Map bookIdMap, Map categoryIdMap); + /** + * 주문에 대한 쿠폰을 조회합니다. + * + * @param userId 사용자 ID + * @param bookIdMap 도서 ID와 도서 정보를 매핑한 맵 + * @param categoryIdMap 카테고리 ID와 카테고리 정보를 매핑한 맵 + * @param bookIds (선택적) 도서 ID 목록 + * @param categoryIds (선택적) 카테고리 ID 목록 + * @param bookPrice 도서 가격 + * @return 주문에 대한 쿠폰 목록 + */ List findCouponByOrder(Long userId, Map bookIdMap, Map categoryIdMap, List bookIds, List categoryIds, BigDecimal bookPrice); + /** + * 장바구니 주문에 대한 쿠폰을 조회합니다. + * + * @param userId 사용자 ID + * @param bookIdMap 도서 ID와 도서 정보를 매핑한 맵 + * @param categoryIdMap 카테고리 ID와 카테고리 정보를 매핑한 맵 + * @param bookDetails (선택적) 도서 주문 정보 + * @return 장바구니 주문에 대한 쿠폰 목록 + */ List findCouponByCartOrder( Long userId, Map bookIdMap, diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/repository/UserAndCouponRepository.java b/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/repository/UserAndCouponRepository.java index 29e8b98..dfea8d7 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/repository/UserAndCouponRepository.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/repository/UserAndCouponRepository.java @@ -8,10 +8,29 @@ import com.nhnacademy.bookstorecoupon.couponpolicy.domain.entity.CouponPolicy; import com.nhnacademy.bookstorecoupon.userandcoupon.domain.entity.UserAndCoupon; +/** + * {@link UserAndCoupon} 엔티티에 대한 JPA 리포지토리입니다. + *

+ * 이 리포지토리는 사용자와 쿠폰 간의 관계를 관리하며, 사용자와 쿠폰에 대한 CRUD 연산을 지원합니다. + * 또한 커스텀 리포지토리 인터페이스 {@link CustomUserAndCouponRepository}를 확장하여 커스텀 쿼리 메소드를 제공합니다. + *

+ */ public interface UserAndCouponRepository extends JpaRepository, CustomUserAndCouponRepository { + /** + * 현재 시간 기준으로 만료된 쿠폰 중 사용되지 않은 쿠폰을 조회합니다. + * + * @param currentDateTime 현재 날짜와 시간 + * @return 만료된 시간 이전이며 사용되지 않은 쿠폰 목록 + */ List findByExpiredDateBeforeAndIsUsedIsFalse(LocalDateTime currentDateTime); + /** + * 특정 쿠폰 정책에 연결된 쿠폰을 조회합니다. + * + * @param couponPolicy 쿠폰 정책 엔티티 + * @return 특정 쿠폰 정책에 연결된 쿠폰 목록 + */ List findByCouponPolicy(CouponPolicy couponPolicy); diff --git a/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/service/UserAndCouponService.java b/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/service/UserAndCouponService.java index dbc67c5..4d28f20 100644 --- a/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/service/UserAndCouponService.java +++ b/src/main/java/com/nhnacademy/bookstorecoupon/userandcoupon/service/UserAndCouponService.java @@ -10,30 +10,95 @@ import com.nhnacademy.bookstorecoupon.userandcoupon.domain.dto.response.UserAndCouponOrderResponseDTO; import com.nhnacademy.bookstorecoupon.userandcoupon.domain.dto.response.UserAndCouponResponseDTO; +/** + * 사용자와 쿠폰 관련 비즈니스 로직을 정의하는 서비스 인터페이스입니다. + *

+ * 이 인터페이스는 사용자와 쿠폰 간의 상호작용을 관리하며, 쿠폰 발행, 조회, 업데이트 등의 다양한 기능을 제공합니다. + *

+ */ public interface UserAndCouponService { - // void createUserAndCoupon(Long couponId, Long userId); - + /** + * 특정 사용자에게 웰컴 쿠폰을 발행합니다. + * + * @param userId 쿠폰을 발행할 사용자 ID + */ void createUserWelcomeCouponIssue(Long userId); - + /** + * 특정 사용자에 대한 페이징된 쿠폰 목록을 조회합니다. + * + * @param userId 사용자 ID + * @param pageable 페이지 요청 정보 (페이지 번호, 페이지 크기 등) + * @return 특정 사용자에 대한 페이징된 쿠폰 목록 + */ Page getAllUsersAndCouponsByUserPaging(Long userId, Pageable pageable); + + /** + * 관리자를 기준으로 페이징된 모든 사용자 쿠폰을 조회합니다. + * + * @param pageable 페이지 요청 정보 (페이지 번호, 페이지 크기 등) + * @param type 정책 유형 (옵션) + * @param userId 사용자 ID (옵션) + * @return 관리자를 기준으로 페이징된 사용자 쿠폰 목록 + */ Page getAllUsersAndCouponsByManagerPaging(Pageable pageable, String type, Long userId); + /** + * 만료된 쿠폰을 처리합니다. + *

+ * 만료된 쿠폰을 찾아서 적절한 처리를 수행합니다. 예를 들어, 쿠폰을 비활성화하거나 삭제하는 작업이 포함될 수 있습니다. + *

+ */ void findExpiredCoupons(); - void issueBirthdayCoupon(); + /** + * 생일 쿠폰을 발행합니다. + *

+ * 사용자 생일에 맞춰 생일 쿠폰을 발행하는 작업을 수행합니다. + *

+ */ + void issueBirthdayCoupon(); + /** + * 특정 주문에 대해 사용할 수 있는 쿠폰을 조회합니다. + * + * @param userId 사용자 ID + * @param bookIds 도서 ID 목록 (옵션) + * @param categoryIds 카테고리 ID 목록 (옵션) + * @param bookPrice 도서 가격 + * @return 주어진 주문에 대해 사용할 수 있는 쿠폰 목록 + */ List findCouponByOrder(Long userId, List bookIds, List categoryIds, BigDecimal bookPrice); + + /** + * 장바구니 주문에 대해 사용할 수 있는 쿠폰을 조회합니다. + * + * @param userId 사용자 ID + * @param bookDetails 도서 주문 정보 목록 + * @return 장바구니 주문에 대해 사용할 수 있는 쿠폰 목록 + */ List findCouponByCartOrder(Long userId, List bookDetails); - void updateCouponAfterPayment(Long userAndCouponId); + /** + * 결제 후 쿠폰을 사용됨 상태로 업데이트합니다. + * + * @param userAndCouponId 사용자 쿠폰 ID + */ + void updateCouponAfterPayment(Long userAndCouponId); + + /** + * 특정 쿠폰 ID로 쿠폰을 조회합니다. + * + * @param couponIds 쿠폰 ID + * @return 특정 쿠폰 ID에 대한 쿠폰 정보 + */ UserAndCouponOrderResponseDTO findUserAndCouponsById(Long couponIds); }