Jakarta Persistence API 또는 Java Persistence API
이름은 API지만 Java 애플리케이션에서 관계형 데이터베이스를 사용하기 위해 정해놓은 표준 스펙
부모 엔티티의 기본키를 외래키로 가지고 있는 엔티티가 자식 엔티티
public interface CoffeeRepository extends JpaRepository<Coffee, Long> {
Optional<Coffee> findByCoffeeCode(String coffeeCode);
// @Query(value = "FROM Coffee c WHERE c.coffeeId = :coffeeId") // (1)
// @Query(value = "SELECT * FROM COFFEE WHERE coffee_Id = :coffeeId", nativeQuery =true) // (2)
@Query(value = "SELECT c FROM Coffee c WHERE c.coffeeId = :coffeeId") // (3)
Optional<Coffee> findByCoffee(long coffeeId);
}
@Service
public class OrderService {
private final MemberService memberService;
private final CoffeeService coffeeService;
private final OrderRepository orderRepository;
public OrderService(MemberService memberService,
CoffeeService coffeeService, OrderRepository orderRepository) {
this.memberService = memberService;
this.coffeeService = coffeeService;
this.orderRepository = orderRepository;
}
public Order createOrder(Order order) {
// 회원, 커피가 존재하는지 조회
verifyOrder(order);
// 스템프 개수 업데이트
updateStamp(order);
return orderRepository.save(order);
}
// 주문 업데이트
public Order updateOrder(Order order) {
Order findOrder = findVerifiedOrder(order.getOrderId());
Optional.ofNullable(order.getOrderStatus())
.ifPresent(orderStatus -> findOrder.setOrderStatus(orderStatus));
findOrder.setModifiedAt(LocalDateTime.now());
return orderRepository.save(findOrder);
}
public Order findOrder(long orderId) {
return findVerifiedOrder(orderId);
}
public Page<Order> findOrders(int page, int size) {
return orderRepository.findAll(PageRequest.of(page, size,
Sort.by("orderId").descending()));
}
public void cancelOrder(long orderId) {
Order findOrder = findVerifiedOrder(orderId);
int step = findOrder.getOrderStatus().getStepNumber();
// OrderStatus의 step이 2 이상일 경우(ORDER_CONFIRM)에는 주문 취소가 되지 않도록한다.
if (step >= 2) {
throw new BusinessLogicException(ExceptionCode.CANNOT_CHANGE_ORDER);
}
findOrder.setOrderStatus(Order.OrderStatus.ORDER_CANCEL);
findOrder.setModifiedAt(LocalDateTime.now());
orderRepository.save(findOrder);
}
// 주문이 존재하는지 확인
private Order findVerifiedOrder(long orderId) {
Optional<Order> optionalOrder = orderRepository.findById(orderId);
Order findOrder =
optionalOrder.orElseThrow(() ->
new BusinessLogicException(ExceptionCode.ORDER_NOT_FOUND));
return findOrder;
}
private void verifyOrder(Order order) {
// 회원이 존재하는지 확인
memberService.findVerifiedMember(order.getMember().getMemberId());
// 커피가 존재하는지 확인
order.getOrderCoffees().stream()
.forEach(orderCoffee ->
coffeeService.findVerifiedCoffee(
orderCoffee.getCoffee().getCoffeeId()));
}
private void updateStamp(Order order) {
Member member = order.getMember();
int stampCnt = order.getOrderCoffees().stream()
.map(orderCoffee -> orderCoffee.getQuantity())
.mapToInt(el -> el)
.sum();
member.getStamp().setStampCount(member.getStamp().getStampCount() + stampCnt);
}
}
블로깅 하기에 양이 많아 제일 중요하다 생각된 OrderService 클래스만 블로깅 하려 했는데 제대로 돌아가지 않는다.
post order 요청이 값을 넣어도 NullPointException이 발생한다..
요청값이 잘못되었으면 기존에 작성했던 GlovalControlAdvice에서 예외를 잡아 처리했을텐데 못하는 걸 보니 요청값이 넘어는 오는데 DTO 변환 과정에서 제대로 처리가 되지 않는 것 같다. 해당 부분은 수정해봐야 될 것 같다..
공부하면서 MapStruct와 같이 자동으로 ~ 해준다 라는 부분들이 너무 얼렁뚱땅 넘어가는 느낌이라 가장 이해하기 힘들고 찝찝하다. 시간 날때 상속받는 인터페이스, 클래스들을 파헤쳐 봐야겠다.
기타 구현 코드는 깃허브 참조