From aa02424741529e1d5801c04827b9591bdf0e3649 Mon Sep 17 00:00:00 2001 From: DaveLee-b Date: Fri, 2 Jan 2026 19:37:34 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20DiscountEventListener=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eventlistener/DiscountEventListener.java | 45 +++++++++++++++++++ .../kt/repository/cart/CartRepository.java | 13 ++++++ .../wishlist/WishlistRepository.java | 23 +++++++--- 3 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/kt/integration/eventlistener/DiscountEventListener.java diff --git a/src/main/java/com/kt/integration/eventlistener/DiscountEventListener.java b/src/main/java/com/kt/integration/eventlistener/DiscountEventListener.java new file mode 100644 index 00000000..94915be1 --- /dev/null +++ b/src/main/java/com/kt/integration/eventlistener/DiscountEventListener.java @@ -0,0 +1,45 @@ +package com.kt.integration.eventlistener; + +import com.kt.event.ProductDiscountEvent; +import com.kt.notification.EMailSendService; +import com.kt.notification.MailSendRequest; +import com.kt.repository.cart.CartRepository; +import com.kt.repository.wishlist.WishlistRepository; +import com.kt.service.discount.DiscountService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Component +@RequiredArgsConstructor +public class DiscountEventListener { + private final DiscountService discountService; + private final EMailSendService eMailSendService; + private final MailSendRequest mailSendRequest; + private final WishlistRepository wishlistRepository; + private final CartRepository cartRepository; + + @EventListener + public void sendMail(ProductDiscountEvent event){ + List wishlistEmails = wishlistRepository.findDistinctEmailsByProductId(event.productId()); + List cartEmails = cartRepository.findDistinctEmailsByProductId(event.productId()); + + Set distinct_emails = new HashSet<>(wishlistEmails); + distinct_emails.addAll(cartEmails); + + if (distinct_emails.isEmpty()) return; + + for(String email : distinct_emails){ + String title = "현재 상품" + event.productName() + "이(가) 할인중입니다."; + String content = "상품명: 에어팟 프로 2세대\n할인율: 15%\n할인가: 289,000원\n링크: https://your-shop.com/products/" + event.productId() + "\n\n지금 구매하면 혜택 적용됩니다."; + MailSendRequest request = new MailSendRequest(email,title,content); + eMailSendService.sendEmail(request); + } + + } +} diff --git a/src/main/java/com/kt/repository/cart/CartRepository.java b/src/main/java/com/kt/repository/cart/CartRepository.java index c2cb9559..879cc663 100644 --- a/src/main/java/com/kt/repository/cart/CartRepository.java +++ b/src/main/java/com/kt/repository/cart/CartRepository.java @@ -10,6 +10,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; public interface CartRepository extends JpaRepository { default Cart findByIdOrThrow(Long id, ErrorCode errorCode) { @@ -20,4 +21,16 @@ default Cart findByIdOrThrow(Long id, ErrorCode errorCode) { @EntityGraph(attributePaths = {"user", "product", "user.membership"}) Page findByUserId(Long userId, Pageable pageable); + + //상품을 찜한 유저 이메일만 뽑는 쿼리, jpa는 비효율적이라 사용x + @Query(""" + select distinct u.email + from Wishlist w + join w.user u + where w.productId = :productId + and w.isDeleted = false + and u.isDeleted = false + and u.email is not null + """) + List findDistinctEmailsByProductId(Long productId); } diff --git a/src/main/java/com/kt/repository/wishlist/WishlistRepository.java b/src/main/java/com/kt/repository/wishlist/WishlistRepository.java index d349d1fb..8c63b860 100644 --- a/src/main/java/com/kt/repository/wishlist/WishlistRepository.java +++ b/src/main/java/com/kt/repository/wishlist/WishlistRepository.java @@ -3,17 +3,30 @@ import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import com.kt.domain.wishlist.Wishlist; @Repository public interface WishlistRepository extends JpaRepository { - boolean existsByUserIdAndProductId(Long userId, Long productId); - List findByUserId(Long userId); - List findByProductId(Long productId); + boolean existsByUserIdAndProductId(Long userId, Long productId); + List findByUserId(Long userId); + List findByProductId(Long productId); - void deleteByUserIdAndProductId(Long userId, Long productId); + void deleteByUserIdAndProductId(Long userId, Long productId); - void deleteByUserId(Long userId); + void deleteByUserId(Long userId); + + //상품을 찜한 유저 이메일만 뽑는 쿼리, jpa는 비효율적이라 사용x + @Query(""" + select distinct u.email + from Wishlist w + join w.user u + where w.productId = :productId + and w.isDeleted = false + and u.isDeleted = false + and u.email is not null + """) + List findDistinctEmailsByProductId(Long productId); } From 7ff2e300c427f24548302b0777f059bfdb6575ca Mon Sep 17 00:00:00 2001 From: DaveLee-b Date: Sat, 3 Jan 2026 02:00:45 +0900 Subject: [PATCH 2/3] fix: modify query, delete MailSendRequest dependency --- .../kt/integration/eventlistener/DiscountEventListener.java | 5 ++--- src/main/java/com/kt/repository/cart/CartRepository.java | 3 +-- .../java/com/kt/repository/wishlist/WishlistRepository.java | 3 +-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/kt/integration/eventlistener/DiscountEventListener.java b/src/main/java/com/kt/integration/eventlistener/DiscountEventListener.java index 94915be1..d5ed30f5 100644 --- a/src/main/java/com/kt/integration/eventlistener/DiscountEventListener.java +++ b/src/main/java/com/kt/integration/eventlistener/DiscountEventListener.java @@ -20,7 +20,6 @@ public class DiscountEventListener { private final DiscountService discountService; private final EMailSendService eMailSendService; - private final MailSendRequest mailSendRequest; private final WishlistRepository wishlistRepository; private final CartRepository cartRepository; @@ -35,8 +34,8 @@ public void sendMail(ProductDiscountEvent event){ if (distinct_emails.isEmpty()) return; for(String email : distinct_emails){ - String title = "현재 상품" + event.productName() + "이(가) 할인중입니다."; - String content = "상품명: 에어팟 프로 2세대\n할인율: 15%\n할인가: 289,000원\n링크: https://your-shop.com/products/" + event.productId() + "\n\n지금 구매하면 혜택 적용됩니다."; + String title = "현재 상품" + event.productName() + " 이(가) 할인중입니다."; + String content = "상품명: " + event.productName() + "\n할인: " + event.discountValue() + "\n할인가: 289,000원\n링크: https://your-shop.com/products/" + event.productId() + "\n\n지금 구매하면 혜택 적용됩니다."; MailSendRequest request = new MailSendRequest(email,title,content); eMailSendService.sendEmail(request); } diff --git a/src/main/java/com/kt/repository/cart/CartRepository.java b/src/main/java/com/kt/repository/cart/CartRepository.java index 879cc663..07d217e3 100644 --- a/src/main/java/com/kt/repository/cart/CartRepository.java +++ b/src/main/java/com/kt/repository/cart/CartRepository.java @@ -27,8 +27,7 @@ default Cart findByIdOrThrow(Long id, ErrorCode errorCode) { select distinct u.email from Wishlist w join w.user u - where w.productId = :productId - and w.isDeleted = false + where w.product.id = :productId and u.isDeleted = false and u.email is not null """) diff --git a/src/main/java/com/kt/repository/wishlist/WishlistRepository.java b/src/main/java/com/kt/repository/wishlist/WishlistRepository.java index 8c63b860..258924ae 100644 --- a/src/main/java/com/kt/repository/wishlist/WishlistRepository.java +++ b/src/main/java/com/kt/repository/wishlist/WishlistRepository.java @@ -23,8 +23,7 @@ public interface WishlistRepository extends JpaRepository { select distinct u.email from Wishlist w join w.user u - where w.productId = :productId - and w.isDeleted = false + where w.product.id = :productId and u.isDeleted = false and u.email is not null """) From 1554a4055e22673b785bdaecbc3e3376d2581b61 Mon Sep 17 00:00:00 2001 From: DaveLee-b Date: Sat, 3 Jan 2026 03:05:06 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=A5=BC=20=EC=9C=84=ED=95=9C=20fake=EC=A3=BC=EC=9E=85,sendEma?= =?UTF-8?q?il=EC=9D=84=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4?= =?UTF-8?q?=EB=A5=BC=20=ED=86=B5=ED=95=B4=20=EC=A3=BC=EC=9E=85=EB=B0=9B?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eventlistener/DiscountEventListener.java | 34 +++++++++++-------- .../kt/notification/FakeMailSendService.java | 18 ++++++++++ 2 files changed, 38 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/kt/notification/FakeMailSendService.java diff --git a/src/main/java/com/kt/integration/eventlistener/DiscountEventListener.java b/src/main/java/com/kt/integration/eventlistener/DiscountEventListener.java index d5ed30f5..f4d21d81 100644 --- a/src/main/java/com/kt/integration/eventlistener/DiscountEventListener.java +++ b/src/main/java/com/kt/integration/eventlistener/DiscountEventListener.java @@ -1,8 +1,8 @@ package com.kt.integration.eventlistener; import com.kt.event.ProductDiscountEvent; -import com.kt.notification.EMailSendService; import com.kt.notification.MailSendRequest; +import com.kt.notification.MailSendService; import com.kt.repository.cart.CartRepository; import com.kt.repository.wishlist.WishlistRepository; import com.kt.service.discount.DiscountService; @@ -18,27 +18,33 @@ @Component @RequiredArgsConstructor public class DiscountEventListener { + private final DiscountService discountService; - private final EMailSendService eMailSendService; + private final MailSendService mailSendService; private final WishlistRepository wishlistRepository; private final CartRepository cartRepository; @EventListener - public void sendMail(ProductDiscountEvent event){ - List wishlistEmails = wishlistRepository.findDistinctEmailsByProductId(event.productId()); - List cartEmails = cartRepository.findDistinctEmailsByProductId(event.productId()); + public void sendMail(ProductDiscountEvent event) { - Set distinct_emails = new HashSet<>(wishlistEmails); - distinct_emails.addAll(cartEmails); + List wishlistEmails = + wishlistRepository.findDistinctEmailsByProductId(event.productId()); + List cartEmails = + cartRepository.findDistinctEmailsByProductId(event.productId()); - if (distinct_emails.isEmpty()) return; + Set distinct_Emails = new HashSet<>(wishlistEmails); + distinct_Emails.addAll(cartEmails); - for(String email : distinct_emails){ - String title = "현재 상품" + event.productName() + " 이(가) 할인중입니다."; - String content = "상품명: " + event.productName() + "\n할인: " + event.discountValue() + "\n할인가: 289,000원\n링크: https://your-shop.com/products/" + event.productId() + "\n\n지금 구매하면 혜택 적용됩니다."; - MailSendRequest request = new MailSendRequest(email,title,content); - eMailSendService.sendEmail(request); - } + if (distinct_Emails.isEmpty()) return; + for (String email : distinct_Emails) { + MailSendRequest request = new MailSendRequest( + email, + "현재 상품 " + event.productName() + " 이(가) 할인중입니다.", + "상품명: " + event.productName() + "\n할인금액: " + event.discountValue() + "\n할인가: 289,000원\n링크: https://your-shop.com/products/" + event.productId() + "\n\n지금 구매하면 혜택 적용됩니다." + ); + mailSendService.sendEmail(request); + } } } + diff --git a/src/main/java/com/kt/notification/FakeMailSendService.java b/src/main/java/com/kt/notification/FakeMailSendService.java new file mode 100644 index 00000000..e584ac25 --- /dev/null +++ b/src/main/java/com/kt/notification/FakeMailSendService.java @@ -0,0 +1,18 @@ +package com.kt.notification; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@Profile("test") +public class FakeMailSendService implements MailSendService { + + @Override + public void sendEmail(MailSendRequest mailSendRequest) { + log.info("[TEST] skip email send: to={}, subject={}", + mailSendRequest.email(), mailSendRequest.title()); + } +} +