Spring BootとJPA 1-TIL(4)を使用
46201 ワード
[参考講座]実戦!Spring BootとJPAによる1-Webアプリケーションの開発
商品注文 クエリ受注履歴 注文キャンセル
作成方法(createOrder():受注エンティティを作成します.受注会員、配送情報、受注商品の情報を受け取り、実際の受注エンティティを生成します. キャンセルオーダー(cancel():キャンセルオーダーに使用します.受注ステータスをキャンセルに変更し、受注商品に受注のキャンセルを通知します. 全発注価格の照会:発注時に使用される全発注価格の照会.全受注価格を知るには、各受注商品の価格を知る必要があります.論理的に見ると、関連注文品の価格を調べて、もう一つの価格を返します. 生成方法(createOrderItem():受注商品、価格、数量情報を使用して受注商品エンティティを生成します. キャンセル():getItem()です.addStock(count)を呼び出し、キャンセルされた注文数に応じて商品在庫を増やします. 受注価格照会(getTotalPrice):受注価格に数量を乗じた値を返します.
受注(order()):受注の会員ID、商品ID、受注数量情報を受信し、実際の受注エンティティを生成して保存します. キャンセルオーダー(キャンセルオーダー():受注識別子を受信し、受注エンティティを問合せ、受注エンティティに受注のキャンセルを要求します. 受注検索(FindOrders):OrderSearchという検索条件を使用して受注エンティティを検索します.詳細については、次の受注検索機能を参照してください. 参照)
注文サービスの注文とキャンセルの方法から見ると、ほとんどのビジネスロジックはエンティティにあります.サービス・レイヤは、エンティティの委任に必要なリクエストのみを担当します.このように、エンティティがビジネスロジックを有し、オブジェクト指向の特性を積極的に利用することをドメインモデルモデルモデルと呼ぶ.
逆に、エンティティにはビジネスロジックがほとんどなく、サービス・レイヤでほとんどのビジネスロジックを処理することをトランザクション・スクリプト・モードと呼びます.
テスト要件の商品を正常に注文しなければなりません. 商品の注文は在庫数量を超えてはならない. の注文を正常にキャンセルする必要があります.
Web層を開発してみましょう
💡 受注ドメインの開発
実装機能
▼▼注文、注文商品本体の開発
受注エンティティの開発
@Entity
@Table(name = "orders")
@Getter @Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
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<>();
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(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);
}
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.CANCEL);
for (OrderItem orderItem : orderItems) {
orderItem.cancel();
}
}
//==조회 로직==//
/**
* 전체 주문 가격 조회
*/
public int getTotalPrice() {
int totalPrice = 0;
for (OrderItem orderItem : orderItems) {
totalPrice += orderItem.getTotalPrice();
}
return totalPrice;
}
}
機能の説明
受注エンティティの開発
@Entity
@Table(name = "order_item")
@Getter @Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
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 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();
}
}
機能の説明
▼▼▼受注記録庫の開発
オーダーレコードコード
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();
}
/**
* 주문취소
* */
@Transactional
public void cancelOrder(Long orderId) {
//주문 엔티티 조회
Order order = orderRepository.findOne(orderId);
//주문 취소
order.cancel();
}
//검색
// public List<Order> findOrders(Order)
}
受注サービスは、受注エンティティと受注商品エンティティのビジネスロジックを使用して、受注、受注のキャンセル、受注履歴の取得機能を提供します.注文サービスの注文とキャンセルの方法から見ると、ほとんどのビジネスロジックはエンティティにあります.サービス・レイヤは、エンティティの委任に必要なリクエストのみを担当します.このように、エンティティがビジネスロジックを有し、オブジェクト指向の特性を積極的に利用することをドメインモデルモデルモデルと呼ぶ.
逆に、エンティティにはビジネスロジックがほとんどなく、サービス・レイヤでほとんどのビジネスロジックを処理することをトランザクション・スクリプト・モードと呼びます.
受注機能のテスト
テスト要件
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class OrderServiceTest {
@Autowired EntityManager em;
@Autowired OrderService orderService;
@Autowired OrderRepository orderRepository;
@Test
public void 상품주문() throws Exception {
//given
Member member = createMember();
Item item = createBook("시골 JPA", 10000, 10);
int orderCount = 2;
//when
Long orderId = orderService.order(member.getId(), item.getId(), orderCount);
//then
Order getOrder = orderRepository.findOne(orderId);
assertEquals("상품 주문시 상태는 ORDER", OrderStatus.ORDER, getOrder.getStatus());
assertEquals("주문한 상품 종류 수가 정확해야 한다.", 1, getOrder.getOrderItems().size());
assertEquals("주문 가격은 가격 * 수량이다.", 10000 * orderCount, getOrder.getTotalPrice());
assertEquals("주문 수량만큼 재고가 줄어야 한다.", 8, item.getStockQuantity());
}
private Book createBook(String name, int price, int stockQuantity) {
Book book = new Book();
book.setName(name);
book.setPrice(price);
book.setStockQuantity(stockQuantity);
em.persist(book);
return book;
}
private Member createMember() {
Member member = new Member();
member.setName("회원1");
member.setAddress(new Address("서울", "강가", "123-123"));
em.persist(member);
return member;
}
@Test(expected = NotEnoughStockException.class)
public void 상품주문_재고수량초과() throws Exception {
//given
Member member = createMember();
Item item = createBook("시골 JPA", 10000, 10);
int orderCount = 11;
//when
orderService.order(member.getId(), item.getId(), orderCount);
//then
fail("재고 수량 부족 예외가 발생해야 한다.");
}
@Test
public void 주문취소() throws Exception {
//given
Member member = createMember();
Book item = createBook("시골 JPA", 10000, 10);
int orderCount = 2;
Long orderId = orderService.order(member.getId(), item.getId(), orderCount);
//when
orderService.cancelOrder(orderId);
//then
Order getOrder = orderRepository.findOne(orderId);
assertEquals("주문 취소시 상태는 CANCEL이다.", OrderStatus.CANCEL, getOrder.getStatus());
assertEquals("주문이 취소된 상품은 그만큼 재고가 증가해야 한다.", 10, item.getStockQuantity());
}
}
Web層を開発してみましょう
Reference
この問題について(Spring BootとJPA 1-TIL(4)を使用), 我々は、より多くの情報をここで見つけました https://velog.io/@yulhee741/Spring-Boot와-JPA-활용1-TIL4テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol