기본적인 CRUD는 완성을 했지만 데이터 가공을 안했고 조회시 순환참조로 인해 결과 코드줄이 5000줄을 넘어가고 있었다...
@Getter
@Setter
@AllArgsConstructor
public class CartItemResponseDTO {
private Long productId;
private int quantity;
private int price;
}
장바구니 조회에는 상품id, 수량, 가격만 필요함.
userId와 cartId는 필요하지 않음.

현재 순환참조가 발생하여 장바구니에 2개 들어갔는데 응답 코드가 6000줄이다 ㅋㅋ,,,
@Transactional(readOnly = true)
public List<CartItemResponseDTO> readCartItem(Long userId) {
User user = findUser(userId);
Cart cart = findCartByUser(user).orElseThrow(
() -> new EntityNotFoundException("해당 사용자의 장바구니가 없습니다."));
return cart.getCartItems().stream()
.map(cartItem -> new CartItemResponseDTO(
cartItem.getProduct().getProductId(),
cartItem.getQuantity(),
cartItem.getProduct().getPrice() * cartItem.getQuantity(),
cartItem.getProduct().getSize(),
cartItem.getProduct().getTemperature()))
.collect(Collectors.toList());
}
서비스 로직을 다음과 같이 수정하였음.
stream의 각 요소를 다른 타입이나 형식으로 변환하는map을 사용하여CartItem->cartItemResponseDTO타입으로 변경하였음.
또한 온도와 사이즈여부를 나오게하였고 가격 * 수량으로 총가격을 오게 변화하였음.
문제는 테스트 코드에서 발견되었음..
@Test
@DisplayName("장바구니 상품 조회하기")
void readCartItem() {
when(userRepository.findById(1L)).thenReturn(Optional.of(user));
when(cartRepository.findByUser(user)).thenReturn(Optional.of(cart));
List<CartItemResponseDTO> responseItems = cartService.readCartItem(1L);
CartItemResponseDTO expectedResponse = new CartItemResponseDTO(
cartItem.getProduct().getProductId(),
cartItem.getQuantity(),
cartItem.getProduct_price()
);
assertEquals(1, responseItems.size()); // 장바구니에 1개 상품이 있으니
System.out.println("Expected Response: " + expectedResponse);
System.out.println("Actual Response: " + responseItems.get(0));
// assertTrue(Objects.equals(expectedResponse, responseItems.get(0))); // 내용 비교
}
테스트 코드도 수정하였음!
sout을 찍어본 결과모두 동일하게 나왔는데
assrtTrue구문을 하면 false가 나왔다 뭔가 가격에 대한 자동증가 로직에 대한 문제 같음.. 추후에 다시 자세히 알아보고 추가하겠음!

암튼 이제 결과 값이 깔끔하게 리턴되도록 변경하였음!
이제 장바구니 수정, 삭제 부분인데...
장바구니는 기본적으로.. 수량을 하나씩 늘리거나 뺀다
또한 전체 장바구니 삭제와, 장바구니에서 물건의 수량이 0이 되면 장바구니에서 사라지게 됨!
@Transactional
public void deleteCartItem(Long userId, Long cartItemId) {
User user = findUser(userId);
Cart cart = findCartByUser(user).orElseThrow(
() -> new EntityNotFoundException("해당 사용자의 장바구니가 없습니다."));
CartItem cartItem = findCartItemByItem(cartItemId);
if (cart.getCartItems().contains(cartItem)) {
cart.getCartItems().remove(cartItem);
cartItemRepository.delete(cartItem);
}
}
현재는 카트에 카트 아이템이 포함되어 있으면 지우는... 아주 이상한 코드로 짜여져 있다...
@Getter
@Setter
public class CartDeleteDTO {
private Long userId;
private Long itemId;
private int quantity;
}
일단 새롭게 삭제를 위한 DTO를 생성하였음
1차적으로 구현하였으나 장바구니 삭제 로직에서 에러 발생
정상적으로 삭제되었다고 나오지만 수량은 줄지 않고
else문으로 빠지고 있음
즉 cart에 cartItem이 contains 되고 있지 않다는 것!
@Transactional
public void deleteCartItem(long userId, CartDeleteDTO cartDeleteDTO) {
User user = findUser(userId); // 유저 찾아
Cart cart = findCartByUser(user).orElseThrow(
() -> new EntityNotFoundException("해당 사용자의 장바구니가 없습니다.")); // 유저에 맞는 카트 찾아
CartItem cartItem = findCartItemByItem(cartDeleteDTO.getCartId());
if (cart.getCartItems().contains(cartItem)) {
if (cartItem.getQuantity() > cartDeleteDTO.getQuantity()) {
cartItem.setQuantity(cartItem.getQuantity() - cartDeleteDTO.getQuantity());
cartItemRepository.save(cartItem);
entityManager.flush(); // 수동으로 플러시
System.out.println("CartItem after update: " + cartItem.getQuantity());
} else {
cart.getCartItems().remove(cartItem);
cartItemRepository.delete(cartItem);
entityManager.flush(); // 수동으로 플러시
System.out.println("CartItem deleted");
}
} else {
System.out.println("CartItem not found in cart");
}
}
private CartItem findCartItemByItem(Long cartItemId) {
return cartItemRepository.findById(cartItemId)
.orElseThrow(() -> new EntityNotFoundException("장바구니 항목을 찾을 수 없습니다."));
한참 삽질한결과 메소드 이름의 중요성을 알았음,,,
cartItem 레포에서 카트의 아이디가 아닌 cartItem의 아이디를 가져오고 있었기에 당연히 카트에 포함이 안되고 있었음
private List<CartItem> findCartItemByCartId(Long cartId) {
return cartItemRepository.findByCartId(cartId);
}
cart의 아이디를 가져오도록 변경!
@Transactional
public void deleteCartItem(long userId, CartDeleteDTO cartDeleteDTO) {
User user = findUser(userId);
Cart cart = findCartByUser(user).orElseThrow(
() -> new EntityNotFoundException("해당 사용자의 장바구니가 없습니다."));
List<CartItem> cartItem = findCartItemByCartId(cartDeleteDTO.getCartId());
CartItem cartItemToDelete = cartItem.stream()
.filter(item -> item.getProduct().getProductId().equals(cartDeleteDTO.getProductId()))
.findFirst()
.orElseThrow(() -> new EntityNotFoundException("해당 카트에 상품이 존재하지 않습니다."));
// 수량 감소 또는 삭제 처리 로직
if (cartItemToDelete.getQuantity() > cartDeleteDTO.getQuantity()) {
cartItemToDelete.setQuantity(cartItemToDelete.getQuantity() - cartDeleteDTO.getQuantity());
cartItemRepository.save(cartItemToDelete); // 수정된 CartItem 저장
} else {
// 수량보다 많이 지울경우
cart.getCartItems().remove(cartItemToDelete);
cartItemRepository.delete(cartItemToDelete); // CartItem 삭제
}
cartRepository.save(cart);
}
후에
리스트로 변환하고 필터를 돌려 상품(조인)했기에 상품의 아이디와 DTO의 상품의 아이디와 같은 것을 확인하였음.
후에 동일하게 수량을 비교하여 적으면 삭제 같거나 많을시에는 전체 삭제로 처리하였음
@Transactional
public void deleteAllCartItems(Long userId) {
User user = findUser(userId);
Cart cart = findCartByUser(user).orElseGet(() -> createCartForUser(user)); // cart 가 없으면 사용자에게 생성
List<CartItem> cartItems = new ArrayList<>(cart.getCartItems());
cart.getCartItems().clear();
for (CartItem cartItem : cartItems) {
cartItemRepository.delete(cartItem);
}
cartRepository.save(cart);
}
또한 장바구니를 다 쓰면 전체로 비워야 하기 떄문에
order 쪽에서 주문이 접수되면 전체 장바구니 비우기를 생성!
생각해보니 장바구니 -> 주문하기 버튼을 눌렀을 떄
장바구니가 비어있는 지 안 비어있는지 체크하는 로직이 있어야 할 것 같다!!
@Transactional(readOnly = true)
public boolean isCartEmpty(Long userId) {
User user = findUser(userId);
Cart cart = findCartByUser(user).orElseThrow(
() -> new EntityNotFoundException("해당 사용자의 장바구니가 없습니다."));
List<CartItem> cartItem = findCartItemByCartId(cart.getId());
return cartItem.isEmpty();
}
간단하게 하나 boolean으로 만들어줬다!

!