[JPA 활용1] 주문 도메인 개발
23272 단어 TILSpringbootJPAJPA
[ 주문, 주문상품 엔티티 개발 ]
1. Order.java
public class Order {
...
//==생성 메서드==//
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;
}
}
생성 메서드 ( createOrder()
)
- 주문 엔티티를 생성할 때 사용한다.
- 주문 회원, 배송 정보, 주문 상품의 정보를 받아서 실제 주문 엔티티를 생성한다.
주문 취소 ( cancel()
)
- 주문 취소시 사용한다.
- 주문 상태를 취소로 변경하고 주문 상품에 주문 취소를 알린다.
- 만약 이미 배송을 완료한 상품이면 주문을 취소하지 못하도록 예외를 발생시킨다.
전체 주문 가격 조회
- 주문 시 사용한 전체 주문 가격을 조회한다. 전체 주문 가격을 알려면 각각의 주문 상품 가격을 알아야 한다.
- 로직을 보면 연관된 주문상품들의 가격을 조회해서 더한 값을 반환한다. (실무에서는 주로 주문에 전체 주문 가격 필드를 두고 역정규화 한다.)
2. OrderItem.java
public class OrderItem {
...
//==생성 메서드==//
public static OrderItem createOrderItem(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();
}
}
생성 메서드 ( createOrderItem()
)
- 주문 상품, 가격, 수량 정보를 사용해서 주문 상품 엔티티를 생성한다.
item.removeStock(count)
를 호출해서 주문한 수량만큼 상품의 재고를 줄인다.
주문 취소 ( cancel()
)
getItem().addStock(count)
를 호출해서 취소한 주문 수량만큼 상품의 재고를 증가시킨다.
주문 가격 조회 ( getTotalPrice()
)
주문 가격 * 수량
을 반환한다.
[ 주문 리포지토리 개발 ]
OrderRepository.java
@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);
}
// public List<Order> findAll(OrderSearch orderSearch) { ... }
}
- 주문 리포지토리는 주문 엔티티를 저장하고 (
save()
) 검색하는 (findOne()
,findAll()
) 기능이 있다. findAll()
은 뒤에서 자세히 알아볼 예정!
[ 주문 서비스 개발 ]
OrderService.java
@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());
delivery.setStatus(DeliveryStatus.READY);
//주문상품 생성
OrderItem orderItem = OrderItem.createOrderItem(item, item.getPrice(), count);
//주문 생성
Order order = Order.createOrder(member, delivery, orderItem);
//주문 저장
orderRepository.save(order);
return order.getId();
}
/**
* 주문 취소
*/
@Transactional
public void cancelOrder(Long orderId) {
//주문 엔티티 조회
Order order = orderRepository.findOne(orderId);
//주문 취소
order.cancel();
}
/**
* 주문 검색
*/
// public List<Order> findOrders(OrderSearch orderSearch) {
// return orderRepository.findAll(orderSearch);
// }
}
- 주문 서비스는 주문 엔티티와 주문 상품 엔티티의 비즈니스 로직을 활용해서 주문, 주문 취소, 주문 내역 검색 기능을 제공한다.
- 예제를 단순화하기 위해서 한 번에 하나의 상품만 주문할 수 있도록 하였다.
주문 ( order()
)
- 주문하는 회원 식별자, 상품 식별자, 주문 수량 정보를 받아서 실제 주문 엔티티를 생성한다.
주문 취소 ( cancelOrder()
)
- 주문 식별자를 받아서 주문 엔티티를 조회한 후 주문 엔티티에 주문 취소를 요청한다.
주문 검색 ( findOrders()
)
OrderSearch
라는 검색 조건을 가진 객체로 주문 엔티티를 검색한다.- 뒤에서 더 자세히 알아볼 예정!
📌 참고
- 도메인 모델 패턴
: 엔티티가 비즈니스 로직을 가지고 객체 지향의 특성을 적극 활용하는 것을 뜻한다.
- 주문 서비스의 주문(
order()
)과 주문 취소(cancelOrder()
) 메서드를 보면 비즈니스 로직 대부분이 엔티티에 있다.- 서비스 계층은 단순히 엔티티에 필요한 요청을 위임하는 역할을 한다.
- 트랜잭션 스크립트 패턴
: 엔티티에는 비즈니스 로직이 거의 없고 서비스 계층에서 대부분의 비즈니스 로직을 처리하는 것
[ 주문 기능 테스트 ]
테스트 요구사항
- 상품 주문이 성공해야 한다.
- 상품을 주문할 때 재고 수량을 초과하면 안 된다.
- 주문 취소가 성공해야 한다.
실행 결과
[ 주문 검색 기능 개발 ]
💡 JPA로 동적쿼리를 해결하는 방법
1. 문자열 조합: 조건에 따라 문자열을 결합하면서 query문을 만들고 parameter를 세팅해주는 방법
2. JPA Criteria: JPA 표준 스펙에서 제공하는 기능
3. queryDSL: 오픈소스를 통해 제공되는 기능으로 쿼리 구현을 method로 한다.
🔗 코드 확인하기
Author And Source
이 문제에 관하여([JPA 활용1] 주문 도메인 개발), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@mmy789/JPA-활용1-주문-도메인-개발저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)