ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • #Spring boot-9 상품 도메인 개발
    SPRING-BOOT 2021. 3. 4. 14:19

    [출처] 인프런 김영한 강사님 -실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

     

    상품 도메인 개발

     

    구현 기능

    · 상품 등록

    · 상품 목록 조회

    · 상품 수정

     

    순서

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

    · 상품 리포지토리 개발

    · 상품 서비스 개발 상품

    · 기능 테스트

     

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

    상품 엔티티 코드

    item class

    package jpabook.jpashop.domain.item;
    
    import jpabook.jpashop.domain.Category;
    import jpabook.jpashop.exception.NotEnoughStockException;
    import lombok.Getter;
    import lombok.Setter;
    
    import javax.persistence.*;
    import java.util.ArrayList;
    import java.util.List;
    
    /*
    *
    * 
    1. 추상클래스는 뭐? 실체클래스의 공통적인 부분(변수,메서드)를 추출해서 선언한 클래스
    
    2. 추상클래스는 객체를 생성할 수 없다! 아직은 실체성이 없고 구체적이지 않기 때문에!
    
    3. 추상클래스와 실체클래스는 어떤관계? 상속관계!
    * */
    @Entity
    @Getter @Setter
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE) //한테이블에 다때려박는것
    @DiscriminatorColumn(name ="dtype")
    public abstract class Item {
    
        @Id @GeneratedValue
        @Column(name ="item_id")
        private Long id;
        private String name;
    
        private int price;
    
        private int stockQuantity;
        //변경할 일이 있으면 setter로 변경하는 것이 아니라 아래와같이 핵심 비지니스 로직으로 변경해야 한다.
        // ->이게 가장 객체지향적인 것이다.
    
        @ManyToMany(mappedBy = "items")
        private List<Category> categories = new ArrayList<>();
    
        //===비지니스 로즥===//
        //재고를 줄이고 늘리는 로직
        // 엔티티 자체가 해결할 수 있는 것은 주로 엔티티 안에 비지니스 로직을 넣는게 좋다 -> 이게 객체지향적
        //즉 데이터를 가지고 있는 쪽에 핵심 비지니스 로직이 있는 것이 좋다.
    
        /*
        * stock 증가
        * */
        public void addStock(int quantity){
            this.stockQuantity += quantity;
        }
    
        /*
         * stock 감소
         * */
        public void remvoeStoc(int quantity){
            int restStock = this.stockQuantity - quantity;
            if(restStock < 0){
                throw new NotEnoughStockException("need more stock");
            }
            this.stockQuantity = restStock;
        }
    
    }
    

     

    stockQuantity를 변경할 일이 있으면 setter로 변경하는 것이 아니라 핵심 비지니스 로직을 따로 만들어서 변경해야 한다.

    ->이게 가장 객체지향적인 것이다.

     

    참고 : 엔티티 자체가 해결할 수 있는 것은 주로 엔티티 안에 비지니스 로직을 넣는게 좋다 -> 이게 객체지향적
             즉 데이터를 가지고 있는 쪽에 핵심 비지니스 로직이 있는 것이 좋다.

     

    예외추가

    NotEnoughStockException class

    package jpabook.jpashop.exception;
    
    public class NotEnoughStockException extends RuntimeException{
        //여기서 overide를 했는데 왜해야 하냐면 메세지 같은것을 다넘겨 주고
        // 메세지와 예외가 발생한 근원적 이셉션을 넣어 처리가 되게 하기 위해서
        public NotEnoughStockException() {
            super();
        }
    
        public NotEnoughStockException(String message) {
            super(message);
        }
    
        public NotEnoughStockException(String message, Throwable cause) {
            super(message, cause);
        }
    
        public NotEnoughStockException(Throwable cause) {
            super(cause);
        }
    
    }
    

    여기서 overide를 했는데 왜해야 하냐면 메세지 같은것을 다넘겨 주고
    메세지와 예외가 발생한 근원적 이셉션을 넣어 처리가 되게 하기 위해서 이다.

     

    비즈니스 로직 분석

    · addStock() 메서드는 파라미터로 넘어온 수만큼 재고를 늘린다. 이 메서드는 재고가 증가하거나

      상품 주문을 취소해서 재고를 다시 늘려야 할 때 사용한다.

    · removeStock() 메서드는 파라미터로 넘어온 수만큼 재고를 줄인다. 만약 재고가 부족하면 예외가 발생한다.

      주로 상품을 주문할 때 사용한다.

     

     

    상품 리포지토리 개발

    상품 리포지토리 코드

    ItemRepository  class

    package jpabook.jpashop.Repository;
    
    import jpabook.jpashop.domain.item.Item;
    import lombok.RequiredArgsConstructor;
    import org.springframework.stereotype.Repository;
    
    import javax.persistence.EntityManager;
    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();
        }
    }
    

     

    기능 설명

    · save()

        · id 가 없으면 신규로 보고 persist() 실행

        · id 가 있으면 이미 데이터베이스에 저장된 엔티티를 수정한다고 보고, merge() 를 실행,

          자세한 내용 은 뒤에 웹에서 설명(그냥 지금은 저장한다 정도로 생각하자)

     

    상품 서비스 개발

    상품 서비즈 코드

    ItemService class

    package jpabook.jpashop.service;
    
    import jpabook.jpashop.Repository.ItemRepository;
    import jpabook.jpashop.domain.item.Item;
    import lombok.RequiredArgsConstructor;
    import org.springframework.beans.factory.annotation.Autowired;
    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);
        }
    
    }
    

    상품 서비스는 상품 리포지토리에 단순히 위임만 하는 클래스

     

     

    상품 기능 테스트

     

    상품 테스트는 회원 테스트와 비슷하므로 생략

    ItemServiceTest class

    package jpabook.jpashop.service;
    
    import jpabook.jpashop.Repository.ItemRepository;
    import jpabook.jpashop.domain.item.Book;
    import jpabook.jpashop.domain.item.Item;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.transaction.annotation.Transactional;
    
    import static org.junit.Assert.*;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    @Transactional
    public class ItemServiceTest {
    
        @Autowired private ItemService itemService;
        @Autowired private ItemRepository itemRepository;
    
        @Test
        public void 상품등록() throws Exception{
            //given
            Book book = new Book();
            book.setName("박");
            book.setAuthor("작가1");
    
            //when
            itemService.saveItem(book);
    
            //then
            assertEquals(book,itemRepository.findOne(book.getId()));
        }
    }

    댓글

Designed by Tistory.