데브코스 : 1차 프로젝트 (3일차-오후)

슬키·2025년 12월 18일

🔧 오후 리팩토링 진행 내용

✨ 구현 기능 명세


1️⃣ 한 고객이 하루에 여러 번 주문하더라도 하나의 주문으로 합배송 처리

  • 동일한 고객이 같은 날 여러 번 주문하더라도
    하나의 배송으로 처리하기 위해 shipmentId 컬럼을 추가하였다.
  • shipmentId는 같은 날, 같은 유저의 READY 상태 주문을 기준으로 동일하게 부여된다.

Order 엔티티 수정 (Order.java)

@Column(nullable = false)
private Long shipmentId;

shipmentId 결정 로직 (OrderService.java)

// 오늘 READY 주문 기준 shipmentId 결정
LocalDateTime startOfToday = LocalDate.now().atStartOfDay();
LocalDateTime endOfToday = LocalDate.now().atTime(23, 59, 59);

Long shipmentId = orderRepository
        .findFirstByUserAndStatusAndOrderDateBetween(
                user,
                OrderStatus.READY,
                startOfToday,
                endOfToday
        )
        .map(Order::getShipmentId)
        .orElseGet(() -> System.currentTimeMillis());
  • 이미 오늘 생성된 READY 상태 주문이 있다면
    해당 주문의 shipmentId를 그대로 사용한다.
  • 오늘 생성된 READY 상태 주문이 없다면
    새로운 배송 단위를 구분하기 위해 System.currentTimeMillis() 값을 사용해
    shipmentId를 생성한다.

2️⃣ 배송 처리 완료 시 status를 COMPLETED로 변경

  • 주문 상태 변경을 위해 OrderScheduler를 작성하였다.
  • 스케줄러를 통해 주문 상태가 시간 흐름에 따라 자동으로 변경된다.

주문 상태 흐름

  • 주문 생성 직후 → READY
  • 전날 14시 ~ 당일 14시 주문 묶음
  • 당일 14시 이후 → DELIVERING
  • DELIVERING 상태에서 하루 경과 → COMPLETED

OrderScheduler.java

@Component
@RequiredArgsConstructor
public class OrderScheduler {

    private final OrderRepository orderRepository;

    @Scheduled(cron = "0 0 14 * * *")
    @Transactional
    public void startDelivery() {
        List<Order> readyOrders =
                orderRepository.findAllByStatus(OrderStatus.READY);

        readyOrders.forEach(order ->
                order.changeStatus(OrderStatus.DELIVERING)
        );
    }

    @Scheduled(cron = "0 0 2 * * *")
    @Transactional
    public void completeDelivery() {
        List<Order> deliveringOrders =
                orderRepository.findAllByStatus(OrderStatus.DELIVERING);

        deliveringOrders.forEach(order ->
                order.changeStatus(OrderStatus.COMPLETED)
        );
    }
}

3️⃣ status = COMPLETED 이고 주문일자가 2일 지난 경우 스케줄러로 삭제

  • OrderCleanupScheduler를 통해 오래된 주문 데이터를 정리한다.
  • COMPLETED 상태이면서 주문일자가 2일이 지난 주문만 삭제되도록 조건을 추가하였다.

OrderCleanupScheduler.java

@Transactional
@Scheduled(cron = "0 0 3 * * *")
public void deleteOldOrders() {
    LocalDateTime twoDaysAgo = LocalDateTime.now().minusDays(2);

    List<Order> oldOrders =
            orderRepository.findAllByStatusAndOrderDateBefore(
                    OrderStatus.COMPLETED,
                    twoDaysAgo
            );

    for (Order order : oldOrders) {
        User user = order.getUser();

        orderRepository.delete(order);

        if (!orderRepository.existsByUser(user)) {
            userRepository.delete(user);
        }
    }
}

4️⃣ MySQL DB 연결 후 전체 기능 테스트

  • 로컬 MySQL DB 연결 완료
  • 기존 H2 환경에서 MySQL 환경으로 전환하여 전체 기능 테스트 진행

📦 shipmentId 추가 후 응답 구조 변경

  • 전체 주문 조회 응답에 shipmentId 필드를 추가하였다.
  • 합배송 단위를 기준으로 주문을 확인할 수 있도록 개선하였다.
image

📝 오늘의 소감

  • 이전에도 백엔드 수업이나 자바 공부를 하면서 스케줄링 개념을 배운 적은 있었지만 대부분 이론 위주였다.
  • 이번 프로젝트를 통해 실제 서비스 로직에 스케줄러를 직접 적용해보니 이해도가 훨씬 높아졌고 재미있었다.
  • 단순한 개념 학습이 아니라 언제, 어떤 데이터를, 어떤 조건으로 처리해야 하는지를 직접 고민해볼 수 있었던 점이 특히 인상 깊었다.
profile
풀스택 개발자 성장일기

0개의 댓글