제육's 휘발성 코딩
반응형

1. 상품 도메인 개발

1.1. 구현 기능

  • 상품 등록
  • 상품 목록 조회
  • 상품 수정

1.2. 순서

  • 상품 엔티티 개발 (비즈니스 로직 추가)
  • 상품 리포지토리, 서비스 개발
  • 상품 기능 테스트

1.3. 비즈니스 로직 추가

<code />
package jpabook.jpashop.domain; import jpabook.jpashop.exception.NotEnoughStockException; import lombok.Getter; import lombok.Setter; import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "dtype") @Getter @Setter public abstract class Item { @Id @GeneratedValue @Column(name = "item_id") private Long id; private String name; private int price; private int stockQuantity; @ManyToMany(mappedBy = "items") private List<Category> categories = new ArrayList<>(); // 비즈니스 로직 추가 public void addStock(int quantity) { this.stockQuantity += quantity; } public void removeStock(int quantity) { int restStock = this.stockQuantity - quantity; if (restStock < 0) { throw new NotEnoughStockException("need more stock"); } this.stockQuantity = restStock; } }
  • Item 엔티티에서 관리하는 stockQuantity를 변경하는 비즈니스로직을 엔티티에서 처리하자. 서비스 단에서 처리할 수 있지만, 엔티티에서 처리하는 것이 응집도가 높은 설계로 볼 수 있다.
  • 현재는 setter를 통해 외부에서 수정할 수 있게 되어있지만, setter 없이 지금처럼 추가적인 비즈니스로직을 만드는 것이 바람직하다.
<code />
package jpabook.jpashop.exception; public class NotEnoughStockException extends RuntimeException{ public NotEnoughStockException() { } public NotEnoughStockException(String message) { super(message); } public NotEnoughStockException(String message, Throwable cause) { super(message, cause); } public NotEnoughStockException(Throwable cause) { super(cause); } public NotEnoughStockException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } }
  • 커스텀 예외를 처리하기 위해 별도의 exception 디렉토리를 만들어서 RuntimeException 을 상속받아 구현체들을 만들자.

1.4. 상품 리포지토리 개발

<code />
package jpabook.jpashop.repository; import jpabook.jpashop.domain.Item; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; import javax.persistence.EntityManager; import java.util.List; @Repository @RequiredArgsConstructor public class ItemRepository { // @PersistContext 대신에 @Autowired로 처리 private final EntityManager em; public void save(Item item) { if (item.getId() == null) { em.persist(item); } else { em.merge(item); //update와 비슷 } } public Item findOne(Long id) { return em.find(Item.class, id); } public List<Item> findAll() { return em.createQuery("select i from Item i", Item.class).getResultList(); } }
  • @PersistenceContext 대신에 @Autowired로 처리가 가능하다.
  • em.merge는 저장된 엔티티를 수정한다고 보고한다고 생각하면 된다.

1.5. 상품 서비스 개발

<code />
package jpabook.jpashop.service; import jpabook.jpashop.domain.Item; import jpabook.jpashop.repository.ItemRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service @Transactional(readOnly = true) @RequiredArgsConstructor public class ItemService { private final ItemRepository itemRepository; @Transactional public void saveItem(Item item) { itemRepository.save(item); } public List<Item> findItems() { return itemRepository.findAll(); } public Item findOne(Long itemId) { return itemRepository.findOne(itemId); } }
  • 상품 서비스는 상품 리포지토리에 단순히 위임만 하는 클래스

본 포스팅은 '인프런 - 김영한님 강의(실전! 스프링 부트와 JPA 활용1)'를 토대로 정리한 내용입니다.

반응형
profile

제육's 휘발성 코딩

@sasca37

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요! 맞구독은 언제나 환영입니다^^