[JPA] 상품도메인 개발

이준영·2022년 10월 28일
1

스프링 - JPA

목록 보기
8/11

시험기간 때문에 너무 오랜만에 들어왔다.. 쫌 까먹은것 같은데... 잘 기억하고 있는지 모르겠지만 일단 다시 시작해보자!!

상품도메인 개발

이번시간에서의 두가지 키워드는 기능순서

  • 구현해야하는 기능은 다음과 같다
  1. 상품 등록
  2. 상품 목록 조회
  3. 상품 수정
  • 각각의 기능을 개발하는 순서는 다음과 같다
  1. 상품 엔티티 개발하고 domain
  2. 상품 리포지토리 개발 repository
  3. 상품 서비스 개발 service
  4. 기능 테스트 Test

구현 순서는 어떤 기능 구현에서도 적용되니 꼭 기억하기❗️❗️

구현해야할 각 기능마다 개발 순서를 따라가며 하나씩 코드 작성해보자

  • 상품 엔티티 : Item

@Entity
//상속관계 매핑이기 때문에 상속관계 전략을 지정해야되는데 이 전략을 부모클래스에 잡아야해
//여기선 싱글 테이블 전략
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype")  //ex. book이면 어떻게 할거야.. 뭔소린지 더 알아보자..
@Getter @Setter
public abstract class Item {

    @Id							// PRIMARY KEY 표시 annotation
    @GeneratedValue				// 자동생성 설정 annotation
    @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<>();

    //==비즈니스 로직==//
    // 보통 stock quantity를 가져와서 거기서 지지고 볶고 삶고 마지막에 setQuantity 같은 방식으로 코딩을 했읉텐데
    // BUT, 객체 지향적으로 생각해보면 데이터를 가지고 있는 쪽에 비즈니스 메서드가 있는게 가장 좋음. 응집력 있음
    // quantity를 변경할일 있으면 setter를 쓰는게 아니라 이렇게 핵심 비즈니스 로직으로 변경하도록!!
    /**
     * stock(재고) 증가
     */
    public void addStock(int quantity) {
        this.stockQuantity += quantity;
    }

    /**
     * stock(재고) 감소
     */
    public void removeStock(int quantity) {
        int restStock = this.stockQuantity - quantity;
        if (restStock < 0) {
            throw new NotEnoughStockException("need more stock");
        }
        this.stockQuantity = restStock;
    }
}

자세한 설명은 코드에 주석을 달아놨다.
이해가 잘 안되는건 @DiscriminatorColumn(name = "dtype") 이 annotation인데
구글링해서 쫌 더 찾아보자.

비즈니스 로직 : addStock(), removeStock() 은 나중에 다시 돌아와서 하는데 그냥 한번에 하자.

  • Item 엔티티
    - addStock() : 파라미터로 넘어온 수량만큼 재고를 늘리는 메서드
    - removeStock() : 파라미터로 너머온 수량만큼 재고를 줄이는 메서드. 만약 재고가 부족하면 예외가 발생한다
  • 상품 리포지토리 : ItemRepository

@Repository
@RequiredArgsConstructor // final 변수만 생성자 만들어주는 친구
public class ItemRepository {

    private final EntityManager em;

    public void save(Item item) {

        if (item.getId() == null) {     // item 값이 없다 --> 새거다
            em.persist(item);
        } else {                        // item 값이 있다 --> 있던거다
            em.merge(item);             // merge : 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();
    }
}
  • EntityManger em은 persist, merge, find, createQeury 를 지원해준다
  • save()에서 em.persist(item) / em.merge(item)를 기억하자
  • ItemRepository에서 지원하는 메서드
    -save(item) : 상품을 저장
    -findOne(id) : 상품 id로 해당 상품 조회
    -findAll() : 전체 상품조회
  • 상품 서비스 : ItemService

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class ItemService {

    public final ItemRepository itemRepository;

    // 위에 있는 @Transactional은 전체에 적용 : readOnly니까
    // 가까이 있는 annotation이 우선권을 가짐  : write 해주기 위해 다시 annotation 붙임
    @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);
    }
}

ItemService는 ItemRepository에 있는 기능을 이름만 바꿔서 쓰고있다.
-saveItem(item)
-findItems()
-findOne(itemID)
이게 꼭 필요한가..?

엔티티, 리포지토리, 서비스를 모두 구현 했으면 이제 테스트 하고 마무리~~
하면 되는데 회원 테스트랑 비슷하다고 생략했다...
.
.
.
아싸 강의들을거 줄었다ㅎㅋ

profile
화이팅!

0개의 댓글