Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<JSONObject> confirmPayment(@RequestBody String jsonBody) throws Exception {

Expand Down Expand Up @@ -80,28 +75,6 @@ public ResponseEntity<JSONObject> 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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public class AutoPaymentScheduler {
* 매일 오전 0시(혹은 원하는 시각)에 실행
* - “내일 자동결제 예정”인 AutoPayment 찾아서, 알림 발행
*/

// @Scheduled(cron = "0 */1 * * * *")
@Scheduled(cron = "0 0 0 * * *")
public void notifyBeforeAutoPayment() {
log.info("자동결제 전날 알림 스케줄러 실행...");
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -175,10 +176,12 @@ public Response<UserProduct> purchaseProduct(
),
})
@GetMapping("/products")
public Response<List<UserProduct>> getMyProducts(HttpServletRequest request) {
public Response<List<UserProductResponseDto>> getMyProducts(HttpServletRequest request) {
String userEmail = tokenProvider.getUserLoginEmail(request);
List<UserProduct> list = userProductService.getUserProducts(userEmail);
// 엔티티 대신 DTO를 바로 반환
List<UserProductResponseDto> list = userProductService.getUserProductsDto(userEmail);
return Response.success(list);
}

}


Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -35,13 +37,22 @@ public UserProduct createUserProduct(String userEmail, Long productId, Long paid

return userProductRepository.save(userProduct);
}
// UserProductService.java
public List<UserProduct> getUserProducts(String userEmail) {
/**
* 특정 유저가 구매한 상품 목록을 DTO 형태로 반환
*/
@Transactional // import org.springframework.transaction.annotation.Transactional;
public List<UserProductResponseDto> 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<UserProduct> userProducts = userProductRepository.findAllByUserUserId(user.getUserId());

// 엔티티 -> DTO 변환
return userProducts.stream()
.map(UserProductResponseDto::fromEntity)
.toList();
}

public boolean isProductPurchased(String userEmail, Long productId) {
Expand Down