상품 엔티티 개발
domain/ item/Item.java
package jpabook2.jpashop2.domain.item;
import jpabook2.jpashop2.domain.Category;
import jpabook2.jpashop2.exception.NotEnoughStockException;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@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<>();
// 핵심 비지니스 로직
/**
* stock 증가
*/
public void addStock(int quantity) {
this.stockQuantity += quantity;
}
/**
* stock 감소
*/
public void removeStock(int orderQuantity) {
int restStock = this.stockQuantity - orderQuantity;
if(restStock < 0) {
throw new NotEnoughStockException("need more stock");
}
this.stockQuantity = restStock;
}
}
Item 엔티티 파일에 핵심 비지니스 로직 addStock() 과 removeStock() 을 넣어주었다.
데이터를 가지고 있는 엔티티 파일에 핵심 비지니스 로직을 넣어주게 되면 응집력이 좋고 관리하기 좋다.
removeStock() 메서드에서 계산된 남은 재고 restStock이 0보다 작을 경우 Exception이 발생되게 했다. 만들어준 NotEnoughStockException 은 exception/NotEnoughStockException.java 파일로 만들어서 관리한다.
Setter의 경우에도 @Setter 애노테이션을 사용하기보단 핵심 비지니스 로직을 통해서 setter를 설정해주는 편이 좋다.
exception/NotEnoughStockException.java
package jpabook2.jpashop2.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);
}
}
RuntimeException 을 상속받아서 해당하는 메서드들을 override 해주었다.
상품 리포지토리 개발
repository/ItemRepository.java
@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);
}
}
public void findOne(Long id) {
em.find(Item.class, id);
}
public List<Item> findAll() {
em.createQuery("select i from Item i", Item.class)
.getResultList();
}
}
- save()
- id가 null일 때
- item은 JPA에 저장되기 전까지 id 값이 없으므로, id 값이 없다는 것은 완전히 새로 생성하는 객체라는 뜻이다.
- id가 존재할 때
- 이미 db에 등록되어있고 어디선가 가져온다는 뜻이다.
- 여기서 save는 update는 아니지만 이미 데이터베이스에 저장된 엔티티를 수정한다고 보고 merge()를 실행한다.
상품 서비스 개발
service/ItemService.java
@Service
@Tracsactional(readOnly = true)
public class ItemService {
private final ItemRepository itemRepository;
@Transactional
public void saveItem(Item item) {
itemRepository.save(item);
}
public List<Item> findItem() {
return itemRepository.findAll();
}
public Item findOne(Long itemId) {
return itemRepository.findOne(itemId);
}
}
ItemService는 ItemRepository에 위임만 하는 클래스로, 개발이 단순하게 끝나버린다.
그러나 경우에 따라서는 위임만 하는 클래스를 만들어야 할 필요가 있는지 생각해 볼 필요가 있다.
controller에서 바로 repository에 직접 접근해서 사용할 수 있게 만들 수도 있기 때문이다.
ItemService 전체에 Transactional을 readOnly true로 설정해주었고, saveItem() 메서드는 데이터 변동이 일어나기 때문에 새롭게 @Transactionl을 적용해주었다.
repository에서 EntityManager에 접근하는 메서드들을 만들어주었고, Service에서는 repository의 메서드를 사용해서 Entitymanager에 접근하게끔 작성하였다.
'Server' 카테고리의 다른 글
[Spring] Spring boot와 JPA 활용 - 웹 계층 개발 (0) | 2022.07.05 |
---|---|
[Spring] Spring boot와 JPA 활용 - 주문 도메인 개발 (0) | 2022.06.24 |
[Spring] Spring boot와 JPA 활용 - 애플리케이션 구현 준비, 회원 도메인 개발 (0) | 2022.06.19 |
[Spring] Spring boot와 JPA 활용 - 도메인 분석 설계 (0) | 2022.06.05 |
[Spring] Spring boot와 JPA 활용 - 프로젝트 환경설정 (0) | 2022.06.05 |