1. 주문, 주문상품 엔티티 개발
구현 기능
상품 주문
주문 내역 조회
주문 취소
순서
주문 엔티티, 주문상품 엔티티 개발
주문 리포지토리 개발
주문 서비스 개발
주문 검색 기능 개발
주문 기능 테스트
Order - 주문 엔티티 개발
package jpabook.jpashop.domain;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name="orders")
@Getter @Setter
public class Order {
@Id @GeneratedValue
@Column(name = "order_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="member_id")
private Member member;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<>();
//cascade = CascadeType.ALL : order를 persist하면 컬렉션의 제네릭 타입 OrderItem도 강제로 persist
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "delivery_id")
private Delivery delivery;
//cascade = CascadeType.ALL : order를 persist하면 Delivery도 강제로 persist
private LocalDateTime orderDate; //주문시간
//LocalDateTime: 자바 8부터 지원, Date를 쓰면 날짜 관련 어노테이션을 매핑해야된다는 불편함 존재
@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);
}
public void setDelivery(Delivery delivery) {
this.delivery = delivery;
delivery.setOrder(this);
}
//==생성 메서드==//
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.CANCLE);
for (OrderItem orderItem : orderItems) {
orderItem.cancel(); //orderItem도 취소를 해줘야 함
}
}
//==조회 로직==//
/**
* 전체 주문 가격 조회
*/
public int getTotalPrice() {
return orderItems.stream()
.mapToInt(OrderItem::getTotalPrcie)
.sum(); //for문을 스트림으로 변경
}
//int totalPrice = 0;
// for (OrderItem orderItem : orderItems) {
// totalPrice += orderItem.getTotalPrice();
// }
// return totalPrice;
}
OrderItem item1 = new OrderItem(/* OrderItem 생성자에 필요한 매개변수 */);
OrderItem item2 = new OrderItem(/* OrderItem 생성자에 필요한 매개변수 */);
Order order = createOrder(member, delivery, item1, item2);
"..."은 자바에서 **가변 인수**를 나타내는 기호, 이는 메서드가 동일한 타입의 여러 매개변수를 가질 수 있으며 메서드 호출시 몇 개의 인수가 전달되든 상관없이 처리 가능
자바 스트림(Stream)
기능 설명
**생성 메서드( createOrder() )**: 주문 엔티티를 생성할 때 사용한다.
주문 회원, 배송정보, 주문상품의 정보를 받아서 실제 주문 엔티티를 생성한다.
**주문 취소( cancel() )**: 주문 취소시 사용한다. 주문 상태를 취소로 변경하고 주문상품에 주문 취소를 알린다.
만약 이미 배송을 완료한 상품이면 주문을 취소하지 못하도록 예외를 발생시킨다.
**전체 주문 가격 조회**: 주문 시 사용한 전체 주문 가격을 조회한다.
전체 주문 가격을 알려면 각각의 주문상품 가격을 알아야 한다.
로직을 보면 연관된 주문상품들의 가격을 조회해서 더한 값을 반환한다.
(실무에서는 주로 주문에 전체 주문 가격 필드를 두고 역정규화 한다.)
OrderItem - 주문상품 엔티티 코드
package jpabook.jpashop.domain;
import jpabook.jpashop.domain.Item.Item;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
@Entity
@Getter
@Setter
public class OrderItem {
@Id
@GeneratedValue
@Column(name = "order_item_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "item_id")
private Item item;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="order_id")
private Order order;
private int orderPrice; //주문 가격
private int count; //주문 수량
//==생성 메서드==//
public static OrderItem createOrederItem(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 getTotalPrcie() {
return getOrderPrice() * getCount(); //전체 토탈
}
}
기능 설명
**생성 메서드( createOrderItem() ):** 주문 상품, 가격, 수량 정보를 사용해서 주문상품 엔티티를 생성한다.
그리고 item.removeStock(count) 를 호출해서 주문한 수량만큼 상품의 재고를 줄인다.
**주문 취소( cancel() ):** getItem().addStock(count) 를 호출해서 취소한 주문 수량만큼 상품의 재고를 증가시킨다.
**주문 가격 조회( getTotalPrice() )**: 주문 가격에 수량을 곱한 값을 반환한다.
2. 주문 리포지토리 개발