Spring/SpringBoot&JPA

[스프링부트와 JPA 활용 1] Section5. 상품 도메인 개발

y-seo 2023. 11. 1. 14:26

상품 엔티티 개발 (비즈니스 로직 추가)

  • 구현 기능
    • 상품 등록
    • 상품 목록 조회
    • 상품 수정
  • 순서
    1. 상품 엔티티 개발 (비즈니스 로직 추가)
    2. 상품 리포지토리 개발
    3. 상품 서비스 개발, (상품 기능 테스트)
  • item.java 수정
package jpabook.jpashop.domain.item;

import jakarta.annotation.ManagedBean;
import jakarta.persistence.*;
import jpabook.jpashop.domain.Category;
import jpabook.jpashop.exception.NotEnoughStockException;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@Setter
@Inheritance(strategy = InheritanceType.JOINED) //Single Table 전략
@DiscriminatorColumn(name = "dtype")
public 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;
    }
}

위와 같이 엔티티 안에 비즈니스 메소드가 있는 것이 응집력이 있는 코드이다. Setter 대신 핵심 비즈니스 메소드를 가지고 stockQuantity를 변경해야 한다

  • jpashop/src/main/java/jpabook/jpashop/exception/NotEnoughStockException.java 생성
package jpabook.jpashop.exception;

public class NotEnoughStockException extends RuntimeException {
    public NotEnoughStockException() {
        super();
    }

    public NotEnoughStockException(String message) {
        super(message);
    }

    public NotEnoughStockException(String message, Throwable cause) {
        super(message, cause);
    }

    public NotEnoughStockException(Throwable cause) {
        super(cause);
    }

}
  • 재고를 변경해야 할 일이 있으면 핵심 비즈니스 메소드를 가지고 변경하게 해야함 → 가장 객체지향적인 것

 

상품 리포지토리 개발

  • jpashop/src/main/java/jpabook/jpashop/repository/ItemRepository.java 생성
package jpabook.jpashop.repository;

import jakarta.persistence.EntityManager;
import jpabook.jpashop.domain.item.Item;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
@RequiredArgsConstructor
public class ItemRepository {

    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();
    }
}

 

상품 서비스 개발

  • 상품 서비스는 상품 리포지토리에 단순하게 위임만 하는 클래스이다
  • jpashop/src/main/java/jpabook/jpashop/service/ItemService.java 생성
package jpabook.jpashop.service;

import jpabook.jpashop.domain.item.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);
    }
}