배달 주문 시스템에서 고객의 진행 상태를 백엔드에서 관리하는 방법을 구현하려면, 상태 관리를 통해 고객의 진행 상태를 추적하는 것이 필요합니다. 이를 위해 흔히 사용되는 패턴 중 하나는 상태 머신 패턴(State Machine Pattern)입니다. 이 패턴을 사용하면 고객이 주문 프로세스에서 어디에 있는지 쉽게 추적하고, 중간에 다른 작업을 하더라도 원활하게 이전 상태로 돌아올 수 있게 할 수 있습니다.
상태 머신 패턴 개요
상태 머신은 시스템이 특정 상태에서 시작하여, 이벤트에 따라 다른 상태로 전이되는 구조입니다. 예를 들어, "메뉴 선택", "카드 선택", "결제" 등의 상태를 정의하고, 각 상태에서 특정 조건을 충족하면 다음 상태로 전이되도록 설계합니다.
상태 관리 로직
상태 정의
python
코드 복사
from enum import Enum
class OrderState(Enum):
MENU_SELECTION = "MENU_SELECTION"
CARD_SELECTION = "CARD_SELECTION"
PAYMENT = "PAYMENT"
COMPLETED = "COMPLETED"
상태 저장
고객의 상태는 세션 또는 데이터베이스에 저장됩니다.
고객이 어디까지 진행했는지를 저장하기 위해 각 고객에 대해 OrderState를 저장하는 필드를 사용합니다.
상태 전이 로직
python
코드 복사
def get_next_state(current_state):
if current_state == OrderState.MENU_SELECTION:
return OrderState.CARD_SELECTION
elif current_state == OrderState.CARD_SELECTION:
return OrderState.PAYMENT
elif current_state == OrderState.PAYMENT:
return OrderState.COMPLETED
else:
return OrderState.MENU_SELECTION # 기본값은 메뉴 선택
3. 상태 확인 및 재진입 처리
고객이 주문을 시작할 때, 현재 고객의 상태를 확인합니다. 만약 고객이 "메뉴 선택" 상태를 완료한 후 다른 작업을 하다가 다시 돌아온 경우, 고객의 현재 상태를 확인하여 "카드 선택" 단계로 바로 넘어갈 수 있도록 합니다.
python
코드 복사
def handle_order_request(user_id):
current_state = get_user_state(user_id) # DB나 세션에서 현재 상태를 가져옴
if current_state == OrderState.MENU_SELECTION:
return render_menu_selection()
elif current_state == OrderState.CARD_SELECTION:
return render_card_selection()
elif current_state == OrderState.PAYMENT:
return render_payment_page()
else:
return render_menu_selection() # 기본값으로 메뉴 선택 페이지 렌더링
python
코드 복사
def update_user_state(user_id, next_state):
# DB나 세션에 다음 상태를 저장
save_user_state(user_id, next_state)
def menu_selection_completed(user_id):
update_user_state(user_id, OrderState.CARD_SELECTION)
def card_selection_completed(user_id):
update_user_state(user_id, OrderState.PAYMENT)
def payment_completed(user_id):
update_user_state(user_id, OrderState.COMPLETED)
5. 재진입 시 처리
고객이 중간에 다른 작업을 하다가 돌아왔을 때 handle_order_request 함수가 자동으로 현재 상태에 맞는 페이지를 렌더링하도록 보장합니다.
결론
이와 같은 구조로 백엔드에서 상태 관리를 하면 고객이 주문 과정에서 어디까지 진행했는지 쉽게 추적할 수 있고, 중간에 다른 일을 하더라도 자연스럽게 주문을 이어나갈 수 있습니다. 상태 머신 패턴을 사용함으로써 코드의 가독성과 유지보수성도 높일 수 있습니다.
세션에서 주문 상태를 관리하고 각 상태를 2분간 유지하려면 스프링에서 세션 타임아웃을 설정하고, 세션을 사용하여 상태를 저장 및 관리하는 방법을 구현할 수 있습니다. 아래는 스프링을 사용하여 메뉴 선택, 카드 선택, 결제 상태를 세션에서 관리하는 예시입니다.
properties
코드 복사
server.servlet.session.timeout=2m
2. 상태 Enum 정의
주문 상태를 정의하는 OrderState Enum을 작성합니다.
java
코드 복사
public enum OrderState {
MENU_SELECTION,
CARD_SELECTION,
PAYMENT,
COMPLETED
}
3. 서비스 클래스
서비스 클래스에서는 세션에서 상태를 관리하는 메소드를 제공합니다.
java
코드 복사
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpSession;
@Service
public class OrderService {
public void setOrderState(HttpSession session, OrderState state) {
session.setAttribute("orderState", state);
}
public OrderState getOrderState(HttpSession session) {
OrderState state = (OrderState) session.getAttribute("orderState");
return (state != null) ? state : OrderState.MENU_SELECTION;
}
public void advanceState(HttpSession session) {
OrderState currentState = getOrderState(session);
OrderState nextState;
switch (currentState) {
case MENU_SELECTION:
nextState = OrderState.CARD_SELECTION;
break;
case CARD_SELECTION:
nextState = OrderState.PAYMENT;
break;
case PAYMENT:
nextState = OrderState.COMPLETED;
break;
default:
nextState = OrderState.MENU_SELECTION;
}
setOrderState(session, nextState);
}
public void resetOrder(HttpSession session) {
setOrderState(session, OrderState.MENU_SELECTION);
}
}
4. 컨트롤러 클래스
컨트롤러에서는 HTTP 요청을 처리하고 상태를 업데이트합니다.
java
코드 복사
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import javax.servlet.http.HttpSession;
@Controller
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/order")
public String orderProcess(HttpSession session, Model model) {
OrderState currentState = orderService.getOrderState(session);
switch (currentState) {
case MENU_SELECTION:
return "menuSelection"; // 메뉴 선택 페이지
case CARD_SELECTION:
return "cardSelection"; // 카드 선택 페이지
case PAYMENT:
return "payment"; // 결제 페이지
case COMPLETED:
return "orderCompleted"; // 주문 완료 페이지
default:
return "menuSelection"; // 기본적으로 메뉴 선택 페이지로 돌아감
}
}
@PostMapping("/order/menu")
public String menuSelectionCompleted(HttpSession session) {
orderService.advanceState(session);
return "redirect:/order";
}
@PostMapping("/order/card")
public String cardSelectionCompleted(HttpSession session) {
orderService.advanceState(session);
return "redirect:/order";
}
@PostMapping("/order/payment")
public String paymentCompleted(HttpSession session) {
orderService.advanceState(session);
return "redirect:/order";
}
@PostMapping("/order/reset")
public String resetOrder(HttpSession session) {
orderService.resetOrder(session);
return "redirect:/order";
}
}
5. 뷰 템플릿
각 상태에 맞는 뷰 템플릿을 작성합니다. 예를 들어 menuSelection.html, cardSelection.html, payment.html, orderCompleted.html 등을 작성하여 상태에 맞는 UI를 제공합니다.
이 방법은 상태 정보를 서버에서 유지하므로 보안상 안전하며, 세션 타임아웃을 통해 상태를 자동으로 만료시킬 수 있습니다.