diff --git a/src/main/java/com/sesac/boheommong/domain/tosspayment/controller/WidgetController.java b/src/main/java/com/sesac/boheommong/domain/tosspayment/controller/WidgetController.java index 83c42a7..7120430 100644 --- a/src/main/java/com/sesac/boheommong/domain/tosspayment/controller/WidgetController.java +++ b/src/main/java/com/sesac/boheommong/domain/tosspayment/controller/WidgetController.java @@ -1,7 +1,5 @@ package com.sesac.boheommong.domain.tosspayment.controller; -import com.sesac.boheommong.domain.notification.service.NotificationService; -import lombok.RequiredArgsConstructor; import net.minidev.json.JSONObject; import net.minidev.json.parser.JSONParser; import net.minidev.json.parser.ParseException; @@ -23,13 +21,10 @@ import java.util.Base64; @Controller -@RequiredArgsConstructor public class WidgetController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final NotificationService notificationService; - @RequestMapping(value = "/confirm") public ResponseEntity confirmPayment(@RequestBody String jsonBody) throws Exception { @@ -80,28 +75,6 @@ public ResponseEntity confirmPayment(@RequestBody String jsonBody) t JSONObject jsonObject = (JSONObject) parser.parse(reader); responseStream.close(); - // (3) 결제가 성공했다면 SSE 알림 발송 - if (isSuccess) { - logger.info("결제 성공: orderId={}, amount={}", orderId, amount); - - // 예: orderId로 사용자 이메일이나 userId를 DB에서 찾아오거나, - // 일단 임시로 하드코딩한 이메일로 알림 전송: - String userEmail = "dummyUser@somewhere.com"; - - // 알림 메시지 예시 - String content = String.format("결제가 성공적으로 완료되었습니다. 결제금액: %s원", amount); - - // SSE 알림 발행 - notificationService.send( - userEmail, // 기존의 SSE 구독이 userEmail로 되어 있다면 이 값 사용 - null, // 알림 타입 (사용한다면 ENUM 넣기) - content, - null // 클릭 시 이동할 URL - ); - } else { - logger.warn("결제 실패: code={}, response={}", code, jsonObject); - } - return ResponseEntity.status(code).body(jsonObject); } -} +} \ No newline at end of file diff --git a/src/main/java/com/sesac/boheommong/domain/tosspayment/scheduler/AutoPaymentScheduler.java b/src/main/java/com/sesac/boheommong/domain/tosspayment/scheduler/AutoPaymentScheduler.java index 74cf7df..7c29e7d 100644 --- a/src/main/java/com/sesac/boheommong/domain/tosspayment/scheduler/AutoPaymentScheduler.java +++ b/src/main/java/com/sesac/boheommong/domain/tosspayment/scheduler/AutoPaymentScheduler.java @@ -25,6 +25,8 @@ public class AutoPaymentScheduler { * 매일 오전 0시(혹은 원하는 시각)에 실행 * - “내일 자동결제 예정”인 AutoPayment 찾아서, 알림 발행 */ + +// @Scheduled(cron = "0 */1 * * * *") @Scheduled(cron = "0 0 0 * * *") public void notifyBeforeAutoPayment() { log.info("자동결제 전날 알림 스케줄러 실행..."); @@ -44,8 +46,8 @@ public void notifyBeforeAutoPayment() { for (AutoPayment ap : autoPayments) { Long userId = ap.getUser().getUserId(); - // 메시지 예시 - String content = "내일 (" + tomorrowDay + "일) 자동결제가 예정되어 있습니다. (상품ID: " + ap.getProduct().getProductId() + ")"; + String productName = ap.getProduct().getProductName(); // 상품 이름 + String content = String.format("내일 (%d일) 자동결제가 예정되어 있습니다. (상품명: %s)", tomorrowDay, productName); // Redis를 통해 발행(멀티 서버) notificationService.publishNotification( diff --git a/src/main/java/com/sesac/boheommong/domain/user/controller/UserController.java b/src/main/java/com/sesac/boheommong/domain/user/controller/UserController.java index 03f8840..f69533a 100644 --- a/src/main/java/com/sesac/boheommong/domain/user/controller/UserController.java +++ b/src/main/java/com/sesac/boheommong/domain/user/controller/UserController.java @@ -1,6 +1,7 @@ package com.sesac.boheommong.domain.user.controller; import com.sesac.boheommong.domain.user.dto.request.UserRequestDto; +import com.sesac.boheommong.domain.user.dto.response.UserProductResponseDto; import com.sesac.boheommong.domain.user.dto.response.UserResponseDto; import com.sesac.boheommong.domain.user.entity.User; import com.sesac.boheommong.domain.user.entity.UserProduct; @@ -175,10 +176,12 @@ public Response purchaseProduct( ), }) @GetMapping("/products") - public Response> getMyProducts(HttpServletRequest request) { + public Response> getMyProducts(HttpServletRequest request) { String userEmail = tokenProvider.getUserLoginEmail(request); - List list = userProductService.getUserProducts(userEmail); + // 엔티티 대신 DTO를 바로 반환 + List list = userProductService.getUserProductsDto(userEmail); return Response.success(list); } - } + + diff --git a/src/main/java/com/sesac/boheommong/domain/user/dto/response/UserProductResponseDto.java b/src/main/java/com/sesac/boheommong/domain/user/dto/response/UserProductResponseDto.java new file mode 100644 index 0000000..232fa5a --- /dev/null +++ b/src/main/java/com/sesac/boheommong/domain/user/dto/response/UserProductResponseDto.java @@ -0,0 +1,30 @@ +package com.sesac.boheommong.domain.user.dto.response; + +import com.sesac.boheommong.domain.user.entity.UserProduct; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class UserProductResponseDto { + private Long id; + private Long productId; + private Long paidAmount; + + // 필요하다면 유저 정보도 일부 노출 가능 + private String userName; + private String userEmail; + + // 엔티티 -> DTO 변환 + public static UserProductResponseDto fromEntity(UserProduct userProduct) { + return UserProductResponseDto.builder() + .id(userProduct.getId()) + .productId(userProduct.getProductId()) + .paidAmount(userProduct.getPaidAmount()) + // user가 Lazy인 경우, Service 계층에서 이미 초기화되도록 fetch join을 쓰거나, + // 같은 트랜잭션 내에서 user.getName() / user.getLoginEmail()에 접근해야 함 + .userName(userProduct.getUser().getName()) + .userEmail(userProduct.getUser().getLoginEmail()) + .build(); + } +} diff --git a/src/main/java/com/sesac/boheommong/domain/user/service/UserProductService.java b/src/main/java/com/sesac/boheommong/domain/user/service/UserProductService.java index a98998a..3266841 100644 --- a/src/main/java/com/sesac/boheommong/domain/user/service/UserProductService.java +++ b/src/main/java/com/sesac/boheommong/domain/user/service/UserProductService.java @@ -1,11 +1,13 @@ package com.sesac.boheommong.domain.user.service; +import com.sesac.boheommong.domain.user.dto.response.UserProductResponseDto; import com.sesac.boheommong.domain.user.entity.User; import com.sesac.boheommong.domain.user.entity.UserProduct; import com.sesac.boheommong.domain.user.repository.UserProductRepository; import com.sesac.boheommong.domain.user.repository.UserRepository; import com.sesac.boheommong.global.exception.BaseException; import com.sesac.boheommong.global.exception.error.ErrorCode; +import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -35,13 +37,22 @@ public UserProduct createUserProduct(String userEmail, Long productId, Long paid return userProductRepository.save(userProduct); } - // UserProductService.java - public List getUserProducts(String userEmail) { + /** + * 특정 유저가 구매한 상품 목록을 DTO 형태로 반환 + */ + @Transactional // import org.springframework.transaction.annotation.Transactional; + public List getUserProductsDto(String userEmail) { User user = userRepository.findByLoginEmail(userEmail) .orElseThrow(() -> BaseException.from(ErrorCode.USER_NOT_FOUND)); - // 바뀐 메서드명 - return userProductRepository.findAllByUserUserId(user.getUserId()); + // Lazy 로딩 문제를 방지하려면 fetch join을 사용하거나, + // 혹은 같은 트랜잭션 내에서 userProduct.getUser()에 접근해주면 됩니다. + List userProducts = userProductRepository.findAllByUserUserId(user.getUserId()); + + // 엔티티 -> DTO 변환 + return userProducts.stream() + .map(UserProductResponseDto::fromEntity) + .toList(); } public boolean isProductPurchased(String userEmail, Long productId) {