항해99/개발일지

20220219 #주문하기 구현하기 + fetchType??

paran21 2022. 2. 21. 21:23

스프링 시큐리티는 지난번에 사용한 코드를 거의 그대로 가져와서 금방끝났다.

프론트에서 로그인하시는 분이 지난주에는 노드랑 하셔서 방식이 조금 달랐던 것 같은데, 다행히 다른 프론트 분이 도와주셔서 크게 어려움없이 금방 끝낼 수 있었다.

 

#주문하기

주문하기 부분을 하고 있어서 구현을 했는데, 아직 장바구니 부분이 완료되지 않아서 TestData를 넣고 했다.

이 부분을 하다보니 생성자 메소드를 새로 만들어야 했다.

그리고 ProductInCart를 주문하기로 넘기면서 기존에 있던 Cart와의 연결관계를 끊는 메소드도 추가하였다.

public class ProductInCart {
...

//연관관계 편의 메소드
    public void setCart(Cart cart) {
        this.cart = cart;
        cart.getProductInCartList().add(this);
    }

    public void setOrder(Order order) {
        this.order = order;
        order.getProductInCartList().add(this);
    }

    public void setProductInCart(Product product, Long count, String state) {
        this.product = product;
        this.count = count;
        this.state = state;
    }

    //생성 메소드
    public static ProductInCart addProductInCart(Product product, Long count,
                                                 String state, Cart cart) {
        ProductInCart productInCart = new ProductInCart();
        productInCart.setProductInCart(product, count, state);
        productInCart.setCart(cart);
        return productInCart;
    }

    // cart 연결 제거
    public void removeCart() {
        this.cart.getProductInCartList().remove(this);
        this.cart = null;
    }
}

주문하기는 다음과 같이 구현했다.

먼저 새로운 Order를 만들어주고 나서,

ProductInCart의 State를 order로 변경하고 연관관계 편의 메소드인 setOrder를 사용해서 연관관계를 만들어주었다.

그리고 기존의 Cart와의 관계는 제거하고 저장하였다. 

// 주문하기
@Transactional
public void getOrder(OrderRequestDto orderRequestDto, UserDetailsImpl userDetails) {
    //productInCart 찾기
    List<Long> productInCartIdList = orderRequestDto.getProductInCartIdList();
    List<ProductInCart> productInCartList = new ArrayList<>();
    for (Long productInCartId :productInCartIdList ) {
        ProductInCart productInCart = productInCartRepository.findById(productInCartId)
                .orElseThrow(() -> new IllegalArgumentException("productInCart를 찾을 수 없습니다."));
        productInCartList.add(productInCart);
    }

    // user찾기
    User user = userRepository.findById(userDetails.getUser().getId())
            .orElseThrow(() -> new IllegalArgumentException("user를 찾을 수 없습니다."));

    Long sumPrice = 0L;
    Long totalPrice = 0L;
    Long deliveryFee = 3000L;

    // 새로운 order 생성
    for (ProductInCart productInCart : productInCartList ) {
        sumPrice += productInCart.getCount() * productInCart.getProduct().getPrice();
    }
    if(sumPrice >= 50000) {
        deliveryFee = 0L;
    }
    totalPrice = sumPrice + deliveryFee;

    Order order = Order.addOrder(totalPrice, deliveryFee, user);
    orderRepository.save(order);

    // productInCart 상태 변경, order 추가, cart 연결제거
    for (ProductInCart productInCart : productInCartList ) {
        productInCart.setState("order");
        productInCart.setOrder(order);
        productInCart.removeCart();
        productInCartRepository.save(productInCart);
    }
}

 

#Fetch 타입?(해결은 이 글 작성하는 21일에 했다!)

장바구니 담는 메소드를 팀원들이랑 같이 구현하다가 중간에 처음보는 LazyInitializationException이 발생했다.

여기서 오류가 발생했다.

Cart cart = userDetails.getUser().getCart();

그리고 다음과 같은 방법으로 바꿔서 해결했다.

//        Long cartId = userDetails.getUser().getCart().getId();
//        Cart cart = cartRepository.findById(cartId)
//                .orElseThrow(() -> new IllegalArgumentException("카트없다!!!!"));

 

오류가 발생한 부분이 User-Cart 관계라고 생각했는데, 다시 오류를 보니 Cart.ProductInCartList에서 오류가 발생했다.

LazyInitializationException는 지연로딩을 하면서 프록시 객체를 생성할 때 오류가 발생한 것 같다.

Cart와 ProductInCart는 OneToMany이기 때문에 fetch의 기본값이 LAZY인데 EAGER로 바꿔서 즉시로딩이 되게 하였더니 해결되었다.

// fetch 기본값 LAZY
@OneToMany(mappedBy = "cart", fetch = FetchType.EAGER)
private List<ProductInCart> productInCartList = new ArrayList<>();