Skip to content

Commit ee78cf7

Browse files
committed
[250626] 배송도메인 - JPA 메서드네이밍 오류 수정 / 순환참조오류 수정-이벤트클래스 추가 / 카프카 네이밍설정 변경
1 parent a909dff commit ee78cf7

File tree

7 files changed

+112
-39
lines changed

7 files changed

+112
-39
lines changed

src/main/java/com/ecommerce/config/KafkaConfig.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class KafkaConfig {
2626
private static final String PRODUCT_EVENTS_TOPIC = "product-events";
2727
private static final String ORDER_EVENTS_TOPIC = "order-events";
2828
private static final String PAYMENT_EVENTS_TOPIC = "payment-events";
29-
private static final String DELIVERY_EVENTS_TOPIC = "delivery-events";
29+
private static final String SHIPMENT_EVENTS_TOPIC = "shipment-events";
3030
@Value("${spring.kafka.bootstrap-servers[0]}")
3131
private String bootStrapServers;
3232
@Value("${spring.kafka.consumer.group-id:ecommerce-service}")
@@ -79,8 +79,8 @@ public ConsumerFactory<String, byte[]> paymentConsumerFactory() {
7979
* 배송 서비스용 컨슈머 팩토리
8080
*/
8181
@Bean
82-
public ConsumerFactory<String, byte[]> deliveryConsumerFactory() {
83-
return createConsumerFactory(DELIVERY_EVENTS_TOPIC);
82+
public ConsumerFactory<String, byte[]> shipmentConsumerFactory() {
83+
return createConsumerFactory(SHIPMENT_EVENTS_TOPIC);
8484
}
8585

8686

@@ -114,8 +114,8 @@ public KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<String,
114114
}
115115

116116
@Bean
117-
public KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<String, byte[]>> deliveryKafkaListenerContainerFactory() {
118-
return createListenerContainerFactory(deliveryConsumerFactory());
117+
public KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<String, byte[]>> shipmentKafkaListenerContainerFactory() {
118+
return createListenerContainerFactory(shipmentConsumerFactory());
119119
}
120120

121121
private ConcurrentKafkaListenerContainerFactory<String, byte[]> createListenerContainerFactory(
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.ecommerce.shipment.event.external;
2+
3+
import com.ecommerce.shipment.dto.request.CarrierUpdateRequest;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Getter;
7+
8+
import java.util.UUID;
9+
10+
@Getter
11+
@Builder
12+
@AllArgsConstructor
13+
public class CarrierUpdateEvent {
14+
15+
private final UUID shipUUID;
16+
17+
private final CarrierUpdateRequest request;
18+
19+
public static CarrierUpdateEvent of(UUID shipUUID, CarrierUpdateRequest request) {
20+
return CarrierUpdateEvent.builder()
21+
.shipUUID(shipUUID).request(request)
22+
.build();
23+
}
24+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.ecommerce.shipment.event.external;
2+
3+
import com.ecommerce.shipment.domain.ExternalShippingStatus;
4+
import lombok.Builder;
5+
import lombok.Getter;
6+
7+
import java.util.UUID;
8+
9+
@Getter
10+
@Builder
11+
public class ShipmentStatusUpdateEvent {
12+
13+
private final UUID shipUUID;
14+
15+
private final ExternalShippingStatus status;
16+
17+
public static ShipmentStatusUpdateEvent of(UUID shipUUID, ExternalShippingStatus status) {
18+
return ShipmentStatusUpdateEvent.builder()
19+
.shipUUID(shipUUID).status(status)
20+
.build();
21+
}
22+
}

src/main/java/com/ecommerce/shipment/event/producer/ShipmentEventPublisher.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
@RequiredArgsConstructor
1818
public class ShipmentEventPublisher {
1919

20-
private final KafkaTemplate<String, Object> kafkaTemplate;
20+
private final KafkaTemplate<String, byte[]> kafkaTemplate;
2121

2222
// 배송 생성 이벤트 발행 (택배사)
2323
public void publishShipCreated(Shipment shipment) {
@@ -27,8 +27,8 @@ public void publishShipCreated(Shipment shipment) {
2727
.setStatus(shipment.getStatus().toKafkaString())
2828
.setEstmtDeliverDt(shipment.getEstmtDeliverDt().toInstant(ZoneOffset.UTC).toEpochMilli()).build();
2929

30-
log.info("Publishing shipment created event: {}", shipCreateEvent);
31-
kafkaTemplate.send("shipment", "created", shipCreateEvent.toByteArray());
30+
log.info("Publishing shipment.created event: {}", shipCreateEvent);
31+
kafkaTemplate.send("shipment-events", "shipment.created", shipCreateEvent.toByteArray());
3232
}
3333

3434
// 배송 실패 이벤트 발행 (주문 도메인)
@@ -38,8 +38,8 @@ public void publishShipFailed(Shipment shipment) {
3838
.setShipUuid(shipment.getShipUUID().toString())
3939
.setFailedDt(shipment.getUpdtDt().toInstant(ZoneOffset.UTC).toEpochMilli()).build();
4040

41-
log.info("Publishing shipment failed event: {}", shipmentFailedEvent);
42-
kafkaTemplate.send("shipment", "failed", shipmentFailedEvent.toByteArray());
41+
log.info("Publishing shipment.failed event: {}", shipmentFailedEvent);
42+
kafkaTemplate.send("shipment-events", "shipment.failed", shipmentFailedEvent.toByteArray());
4343
}
4444

4545
// 배송 상태 변경 이벤트 발행 (내부 확인용)
@@ -52,8 +52,8 @@ public void publishShipStatusChanged(Shipment shipment) {
5252
.setTrackingNumber(shipment.getTrackingNumber())
5353
.setChangedAt(shipment.getUpdtDt().toInstant(ZoneOffset.UTC).toEpochMilli()).build();
5454

55-
log.info("Publishing shipment status changed event: {}", changedEvent);
56-
kafkaTemplate.send("shipment", "changed", changedEvent.toByteArray());
55+
log.info("Publishing shipment.changed event: {}", changedEvent);
56+
kafkaTemplate.send("shipment-events", "shipment.changed", changedEvent.toByteArray());
5757
}
5858

5959
// 배송 완료 이벤트 발행 (주문 도메인)
@@ -64,7 +64,7 @@ public void publishShipCompleted(Shipment shipment) {
6464
.setCompletedDt(shipment.getUpdtDt().toInstant(ZoneOffset.UTC).toEpochMilli())
6565
.build();
6666

67-
log.info("Publishing delivery.completed event: {}", shipComplete);
68-
kafkaTemplate.send("shipment", "completed", shipComplete.toByteArray());
67+
log.info("Publishing shipment.completed event: {}", shipComplete);
68+
kafkaTemplate.send("shipment-events", "shipment.completed", shipComplete.toByteArray());
6969
}
7070
}

src/main/java/com/ecommerce/shipment/repository/ShipmentRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ public interface ShipmentRepository extends JpaRepository<Shipment, Long> {
1616
Optional<Shipment> findByShipUUID(UUID shipUUID);
1717

1818
// 여러 주문의 배송 조회 목록 조회 (유저의 전체 배송)
19-
List<Shipment> findByOrderUUIDin(List<UUID> orderUUIDs);
19+
List<Shipment> findByOrderUUIDIn(List<UUID> orderUUIDs);
2020

2121
}

src/main/java/com/ecommerce/shipment/service/ExternalCarrierService.java

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
package com.ecommerce.shipment.service;
22

3-
import com.ecommerce.shipment.domain.Shipment;
43
import com.ecommerce.shipment.domain.ExternalShippingStatus;
4+
import com.ecommerce.shipment.domain.Shipment;
55
import com.ecommerce.shipment.dto.request.CarrierUpdateRequest;
6+
import com.ecommerce.shipment.event.external.CarrierUpdateEvent;
7+
import com.ecommerce.shipment.event.external.ShipmentStatusUpdateEvent;
68
import lombok.RequiredArgsConstructor;
79
import lombok.extern.slf4j.Slf4j;
10+
import org.springframework.context.ApplicationEventPublisher;
811
import org.springframework.scheduling.annotation.Async;
912
import org.springframework.stereotype.Service;
1013

1114
import java.security.SecureRandom;
12-
import java.util.Random;
1315
import java.util.UUID;
1416
import java.util.concurrent.CompletableFuture;
1517
import java.util.concurrent.TimeUnit;
@@ -19,10 +21,14 @@
1921
@RequiredArgsConstructor
2022
public class ExternalCarrierService {
2123

22-
private final ShipmentService shipmentService;
2324
@SuppressWarnings("java:S2245")
2425
private final SecureRandom secureRandom = new SecureRandom();
2526

27+
private final ApplicationEventPublisher eventPublisher;
28+
29+
private static final int DELIVERY_SUCCESS_RATE = 9; // 90% 성공률
30+
private static final int RANDOM_RANGE = 10;
31+
2632
private static final String[] CARRIER_NAMES = {
2733
"Express Delivery", "Fast Shipping", "Quick Carrier", "Safe Transport"
2834
};
@@ -46,18 +52,11 @@ public void requestDelivery(Shipment shipment) {
4652
ExternalShippingStatus.READY_FOR_PICKUP
4753
);
4854

49-
50-
// 한 번의 트랜잭션으로 택배사 정보 + 상태 변경
51-
shipmentService.updateCarrierInfoAndStatus(
52-
shipment.getShipUUID(),
53-
readyRequest
54-
);
55-
5655
log.info("Delivery registered with carrier: {}, tracking: {}", carrierName, trackingNumber);
5756

5857
// 배송 상태 변경 시뮬레이션 시작
5958
simulateDeliveryProcess(shipment.getShipUUID());
60-
59+
eventPublisher.publishEvent(CarrierUpdateEvent.of(shipment.getShipUUID(), readyRequest));
6160
} catch (InterruptedException e) {
6261
Thread.currentThread().interrupt();
6362
log.error("Delivery request interrupted", e);
@@ -72,17 +71,12 @@ private void simulateDeliveryProcess(UUID shipUUID) {
7271
try {
7372
// 배송출발 단계
7473
TimeUnit.SECONDS.sleep(5 + secureRandom.nextInt(10));
75-
shipmentService.updateShipmentStatusByUUID(shipUUID, ExternalShippingStatus.SHIPPING);
74+
eventPublisher.publishEvent(ShipmentStatusUpdateEvent.of(shipUUID, ExternalShippingStatus.SHIPPING));
7675

7776
// 최종 배송 완료/실패 (90% 성공률)
78-
TimeUnit.SECONDS.sleep(5 + secureRandom.nextInt(10));
79-
if (secureRandom.nextInt(10) < 9) {
80-
shipmentService.updateShipmentStatusByUUID(shipUUID, ExternalShippingStatus.DELIVERED);
81-
log.info("Delivery completed successfully: {}", shipUUID);
82-
} else {
83-
shipmentService.updateShipmentStatusByUUID(shipUUID, ExternalShippingStatus.FAILED);
84-
log.info("Delivery failed: {}", shipUUID);
85-
}
77+
ExternalShippingStatus finalStatus = decideShippingStatus();
78+
eventPublisher.publishEvent(ShipmentStatusUpdateEvent.of(shipUUID, finalStatus));
79+
log.info("Delivery completed : {} status : {}", shipUUID, finalStatus.toString());
8680

8781
} catch (InterruptedException e) {
8882
Thread.currentThread().interrupt();
@@ -109,4 +103,10 @@ private String generateTrackingNumber() {
109103

110104
return sb.toString();
111105
}
106+
107+
private ExternalShippingStatus decideShippingStatus() {
108+
return secureRandom.nextInt(RANDOM_RANGE) < DELIVERY_SUCCESS_RATE ?
109+
ExternalShippingStatus.DELIVERED : ExternalShippingStatus.FAILED;
110+
}
111+
112112
}

src/main/java/com/ecommerce/shipment/service/ShipmentService.java

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
import com.ecommerce.shipment.domain.ExternalShippingStatus;
44
import com.ecommerce.shipment.domain.Shipment;
55
import com.ecommerce.shipment.dto.request.CarrierUpdateRequest;
6+
import com.ecommerce.shipment.event.external.CarrierUpdateEvent;
7+
import com.ecommerce.shipment.event.external.ShipmentStatusUpdateEvent;
68
import com.ecommerce.shipment.event.producer.ShipmentEventPublisher;
79
import com.ecommerce.shipment.repository.ShipmentRepository;
810
import jakarta.persistence.EntityNotFoundException;
911
import jakarta.transaction.Transactional;
1012
import lombok.RequiredArgsConstructor;
1113
import lombok.extern.slf4j.Slf4j;
14+
import org.springframework.context.event.EventListener;
1215
import org.springframework.stereotype.Service;
1316

1417
import java.time.LocalDateTime;
@@ -60,10 +63,34 @@ public void createExecuteShipment(Shipment shipment) {
6063
}
6164
}
6265

66+
// 택배사 정보 업데이트 이벤트 처리
67+
@EventListener
68+
@Transactional
69+
public void updateCarrierInfo(CarrierUpdateEvent event) {
70+
try {
71+
log.info("Processing carrier update event : {}", event.getShipUUID());
72+
updateCarrierInfoAndStatus(event.getShipUUID(), event.getRequest());
73+
} catch (Exception e) {
74+
log.error("Failed to handle carrier update event: {}", e.getMessage());
75+
}
76+
}
77+
78+
79+
@EventListener
80+
@Transactional
81+
public void updateShippingStatus(ShipmentStatusUpdateEvent event) {
82+
try {
83+
log.info("Processing status update event for shipment: {} -> {}",
84+
event.getShipUUID(), event.getStatus());
85+
updateShipmentStatusByUUID(event.getShipUUID(), event.getStatus());
86+
} catch (Exception e) {
87+
log.error("Failed to handle shipment status update event: {}", e.getMessage());
88+
}
89+
}
6390

6491
// (엔티티 재사용)
6592
@Transactional
66-
public void updateCarrierInfoAndStatus(UUID shipUUID, CarrierUpdateRequest readyRequest) {
93+
protected void updateCarrierInfoAndStatus(UUID shipUUID, CarrierUpdateRequest readyRequest) {
6794
// 한 번만 DB 조회
6895
Shipment shipment = shipmentRepository.findByShipUUID(shipUUID)
6996
.orElseThrow(() -> new EntityNotFoundException("No shipment found for order: " + shipUUID));
@@ -78,7 +105,7 @@ public void updateCarrierInfoAndStatus(UUID shipUUID, CarrierUpdateRequest ready
78105
}
79106

80107
@Transactional
81-
public void updateShipmentStatusByUUID(UUID shipUUID, ExternalShippingStatus newStatus) {
108+
protected void updateShipmentStatusByUUID(UUID shipUUID, ExternalShippingStatus newStatus) {
82109
Shipment shipment = shipmentRepository.findByShipUUID(shipUUID)
83110
.orElseThrow(() -> new EntityNotFoundException("No shipment found for order: " + shipUUID));
84111
updateShipmentStatus(shipment, newStatus);
@@ -93,7 +120,7 @@ private void updateCarrierInfo(Shipment shipment, String carrierName, String tra
93120
private void updateShipmentStatus(Shipment shipment, ExternalShippingStatus newStatus) {
94121
shipment.updateShippingStatus(newStatus);
95122
shipment.processStatusChange(eventPublisher);
96-
log.info("배송 상태 변경: {} -> {}", shipment.getShipUUID(), newStatus);
123+
log.info("Change shipment status: {} -> {}", shipment.getShipUUID(), newStatus);
97124
}
98125

99126

@@ -127,7 +154,7 @@ public Shipment getShipmentByOrderUUID(UUID orderUUIDs) {
127154
}
128155

129156
public List<Shipment> getShipListByOrderUUID(List<UUID> orderUUIDs) {
130-
return shipmentRepository.findByOrderUUIDin(orderUUIDs);
157+
return shipmentRepository.findByOrderUUIDIn(orderUUIDs);
131158
}
132159

133160

0 commit comments

Comments
 (0)