구현 기능
순서
- 주문 엔티티, 주문상품 엔티티 개발
- 주문 리포지토리 개발
- 주문 서비스 개발
- 주문 검색 기능 개발
- 주문 기능 테스트
주문 엔티티
@Entity
@Table(name = "orders")
@Getter @Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 외부에서 매개변수가 없는 생성자를 생성할 수 없다.
public class Order {
@Id @GeneratedValue
@Column(name = "order_id")
private Long id;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "member_id")
private Member member;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<>();
@OneToOne(fetch = LAZY, cascade = CasecadeType.ALL)
@Joincolum(name = "delivery_id")
private Delivery delivery;
private LocalDateTime orderDate; // 주문시간
@Enumerated(EnumType.STRING)
private OrderStatus status; // 주문상태 [ORDER, CANCEL]
// 연관 관계 메서드
public void setMember(Member member) {
this.member = member;
member.getOrders().add(this);
}
public void addOrderItem(OrderItem orderItem) {
orderItems.add(orderItem);
orderItem.setOrder(this);
}
// 생성 메서드. Builder패턴으로 대체 가능
public static Order createOrder(Member member, Delivery delivery, OrderItem... orderItems) {
Order order = new Order();
order.setMember(member);
order.setDelivery(delivery);
for (OrderItem orderItem : orderItems) {
order.addOrderItem(orderItem);
}
order.setStatus(OrderStatus.ORDER);
order.setOrderDate(LocalDateTime.now());
return order;
}
// 비즈니스 로직
// 주문 취소
public void cancel() {
if (delivery.getStatus() == DeliveryStatus.COMP) {
throw new IllegalStateException("이미 배송완료된 상품은 취소가 불가능합니다. ");
}
this.setStatus(OrderStatus.CANCEL);
for (OrderItem orderItem : orderItems) {
orderItem.cancel(); // 주문 취소
}
}
// 조회 로직
// 전체 주문 가격 조회
public int getTotalPrice() {
//int totalPrice = 0;
//for (OrderItem orderItem : orderItems) {
// totalPrice += orderItem.getTotalPrice();
//}
//return totalPrice;
// Stream 활용
return orderItems.stream()
.mapToInt(OrderItem::getTotalPrice)
.sum();
}
}
주문 아이템 엔티티
// 생성 메서드
public static OrderItem createdOrderItem(Item item, int orderPrice, int count) {
OrderItem orderItem = new OrderItem();
orderItem.setItem(item);
orderItem.setOrderPrice(orderPrice);
orderItem.setCount(count);
item.removeStock(count);
return orderItem;
}
// 비즈니스 로직
public void cancel() {
getItem().addStock(count); // 주문했던 수량을 더해서 돌려놓는다.
}
// 조회 로직
public int getTotalPrice() {
return getOrderPrice() * getCount();
}
주문 레퍼지토리
@Repository
@RequiredArgsConstructor
public class OrderRepository {
private final EntityManager em;
public void save(Order order) {
em.persist(order);
}
public Order findOne(Long id) {
return em.find(Order.class, id);
}
}
주문 서비스
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class OrderService {
private final OrderRepository orderRepository;
private final MemberRepository memberRepository;
private final ItemRepository itemRepository;
// 주문
@Transactional
public Long order(Long memberId, Long itemId, int count) {
// 엔티티 조회
Member member = memberRepository.findOne(memberId);
Item item = itemRepository.findOne(itemId);
// 배송정보 생성
Delivery delivery = new Delivery();
delivery.setAddress(member.getAddress());
// 주문상품 생성
OrderItem orderItem = OrderItem.createOrderItem(item, item.getPrice(), count);
// 주문 생성
Order order = Order.createOrder(member, delivery, orderItem);
// 주문 저장
orderRepository.save(order);
return order.getId(); // cascadeType.ALL 이므로 연관된 모든 것이 저장된다. (단, 명확하게 종속되는 경우에만 사용해야 한다.)
}
// 주문 취소
@Transactional
public void cancelOrder(Long orderId) {
// 주문 엔티티 조회
Order order = orderRepository.findOne(orderId);
// 주문 취소
order.cancel();
}
// 주문 검색
}