이번 프로젝트는 IKEA 클론 코딩이었다. 일주일이라는 시간동안 해내는거라 스코프는 최대한 작게 했다.
그 중에 나는 장바구니 .. 뭔가 특별하게 어려운가? 싶어서 인터넷에서 레퍼코드를 찾아보겠다고 하루를 할애했다..
실제로 찾기는 했으나 원래 하던 방식이 아니라서 또 멘붕.......
결국에는 그냥 알던대로 하기로 했다 ..^^ㅋㅋㅎ
1. Entity 설정
- 기획 시 ERD를 설계했던대로 엔티티를 설정해준다.
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Cart extends Timestamped{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name ="member_id")
private Member member;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name ="product_id")
private Product product;
@Column(nullable = false)
private int count;//카트에 담긴 상품 개수
//금액은 BigDecimal 사용하기
@Column(nullable = false)
private BigDecimal sum; //상품비용 합계
@Column(nullable = false)
private BigDecimal delivery_fee; //배송비
그리고 나는 @Builder 방식보다는 생성자 방식을 선호해서... (나중에 대참사가 일어남..)
public Cart (CartRequestDto cartRequestDto,Member member, Product product){
this.product = product;
this.member = member;
this.count = cartRequestDto.getCount();
this.sum =product.getPrice().multiply(new BigDecimal(count));
this.delivery_fee = new BigDecimal(count * 15000);
}
2. Repository 설정
- 로직을 짜면서 계속 추가하긴했지만 결론적으론 이렇게 사용하였다
public interface CartRepository extends JpaRepository<Cart, Long> {
List<Cart> findByMember(Member member);
Optional<Cart> findByIdAndMember(Long id, Member member);
void deleteByMember(Member member);
List<Cart> findByMemberAndProduct(Member member, Product product);
}
3. Dto 설정
- 장바구니 상품 수량 변경시 필요한 requestDto 설정
@Getter
public class CartRequestDto {
@NotNull
private Long productId;
private int count;
}
- ResponseDto 설정
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CartResponseDto {
private Product product;
private Long cart_id;
private int count;
private BigDecimal cart_price;// 카트 당 합계 금액
private LocalDateTime createdAt;
}
👉 (나중에) 수정한 내용이지만 생성자 방식에서 빌더 방식으로 리팩토링을 거쳤다.. 그래서 Response에 빌더가 있고 생성자는 따로 안해주었다.
4. Service
- 본격적인 로직짜기 ! PK값과 FK 값에 대해서 많이 헷갈렸다. 이래서 DB를 먼저 공부하라고했나봐..
- Cart_id 가 멤버당 1개씩 지정되는 줄 알았는데 그게 아니고 멤버의 장바구니의 상품 당 cart_id가 하나씩 부여되는 식이었다 (PK값이므로) => 그래서 repository로 찾아오는데 꽤 헷갈렸다..
- 장바구니 상품 추가
👉 단순하게 추가가 아니라 이미 있는 상품인지 아닌지 확인하는 로직을 추가해야 했다!
@Transactional // get빼고는 트랜잭션 꼭 넣어주기!
@Override
public CartResponseDto addCart(CartRequestDto cartRequestDto,Member member, Product product){
List<Cart> cartList = cartRepository.findByMemberAndProduct(member, product);
//사용자와 선택한 상품으로 일단 카트리스트를 만들고
Cart cart;
//장바구니에 상품이 없을 때
if (cartList.isEmpty()) {
cart = new Cart(cartRequestDto,member,product);//카트를 새로 생성해서
cart = cartRepository.save(cart);//저장해준다
} else {//장바구니에 상품이 있을 때
cart = cartList.get(0);//카트리스트의 index 0번째 값 = 처음에 찾은 cart 상품
cart.changeCount(cart.getCount()+1); // 같은 상품이므로 갯수를 하나더 늘려준다.
}
cartRepository.save(cart);
return CartResponseDto.builder()//ResponseDto 빌더써서 저장해주기..
.cart_id(cart.getId())
.product(cart.getProduct())
.count(cartRequestDto.getCount())
.cart_price(cart.getSum())
.createdAt(cart.getCreatedAt())
.build();
}
- 장바구니 조회 [처음]
@Override
public List<CartResponseDto> getCartList(Member member) {
return cartRepository.findByMember(member);
}
👉그냥 단순하게 List형으로 조회만 하면되겠지 ..^^ 하다가 해보니 아니었다..
이상태로 조회를 하게되면 상품이 여러개일때 응답 값이 문제였다
👉이렇게 상품 합계와 배송비가 그냥 따로 나올뿐 총 배송비/ 총 상품금액은 생각을 못했다...... 테스트 데이터를 넣어서 해볼때 상품을 하나씩만 넣어놓고 해서 이 부분을 아예 생각하지 못했다..
🚨data 안에 product를 list로 넣을 순 없을까? => cart_id가 따로 부여되는 부분은 어떡하지?
하면서 고민하면서 CartResponseDto를 수정하려고 하니 .... 여기서 문제가 생겼다
🤦♀️아까 언급했다 싶이 나는 생성자 방식 vs 다른 기능들은 빌더 방식이라 생성자 방식으로 수정하려면 다른 빌더 방식을 모두 생성자 방식으로 리팩토링해야했다.....
✔ 결국 내 코드들을 모두 빌더 방식으로 리팩토링하기로 결정! 하고 전체조회시 전체를 감싸주는 CartGetListReponseDto를 새로 만들어 주어서 전체 총 배송비와 총 금액을 나타낼수있게 만들었다.
- 장바구니 조회 [수정 후]
@Override
public CartGetListResponseDto getCartList(Member member) {
List<Cart> carts = cartRepository.findByMember(member);
List<CartResponseDto> cartProducts = new ArrayList<>();
int totalCnt = 0; //총 상품 갯수 초기화
BigDecimal totalPrice = new BigDecimal(0);
for (Cart cart : carts) {//for문을 돌려서
cartProducts.add(//List에
CartResponseDto.builder()//cartresponseDto를 넣어준다
.cart_id(cart.getId())
.product(cart.getProduct())
.count(cart.getCount())
.cart_price(cart.getProduct().getPrice().multiply(new BigDecimal(cart.getCount())))
.createdAt(cart.getCreatedAt())
.build());
totalCnt += cart.getCount();//총 상품 갯수를 더해주고
totalPrice = totalPrice.add(cart.getProduct().getPrice().multiply(new BigDecimal(cart.getCount())));
}//총금액 공식을 넣어준다
//전체상품조회Dto에도 값을 넣어준다
CartGetListResponseDto cartGetListResponseDto = CartGetListResponseDto.builder()
.cartProducts(cartProducts)//위에 지정했던 List를 넣어주고
.total_delivery_fee(new BigDecimal(15000 * totalCnt))//총 배송비
.total_order_price(totalPrice)//총 금액
.total_order_and_delivery_price(totalPrice.add(new BigDecimal(15000 * totalCnt)))
.build();//총 배송비 + 총 제품비
return cartGetListResponseDto;
}
이렇게 해주고 나니
👉무사히 감싸져서 전체금액이 잘 나왔다......
product부분이 list로 나와야한다는 생각 때문에 그걸 감싸줄 더 큰 부분을 생각하지 못했다...
🚩=> 처음에 만들때부터 정확히 어떤 게 응답값으로 나가야할지 잘 계산해서 만들어야겠다!!
- 상품 수량 변경
@Transactional
@Override
public CartResponseDto changeItemCount(Long id, Member member, CartRequestDto cartRequestDto) {
Cart cart = cartRepository.findByIdAndMember(id,member)//cart_id와 멤버로 찾아서
.orElseThrow(EntityNotFoundException::new);
cart.changeCount(cartRequestDto.getCount());// 리퀘스트로 받은 갯수로 변경해주고
cartRepository.save(cart);// 저장해준다
return CartResponseDto.builder()//리턴해주는 Response는 빌더로.. 아님 message로 success만 넘겨도 됨
.cart_id(cart.getId())
.product(cart.getProduct())
.count(cartRequestDto.getCount())
.cart_price(cart.getSum())
.createdAt(cart.getCreatedAt())
.build();
}
- 상품 삭제 / 장바구니 전체 삭제
@Transactional
@Override
public void deleteOneItem(Long id) { //cart_id
cartRepository.deleteById(id);
}
//장바구니 전체상품 삭제하기
@Transactional
@Override
public void deleteAllItem(Member member) {
cartRepository.deleteByMember(member);
}
5. controller 설정
👉그냥 넣으면되니까 생략...
모든 소스코드는 github에서 확인 가능하다!
- 다 완성하고나서 Security부분과 연결하고 테스트를 해보니 JPA 연관관계 때문에 애를 많이 먹었다...
- 특히 삭제 .. 부분에서 외래키때문에 삭제가 안된다는 에러를 계속봤다..
- 장바구니는 사용자와 상품 모두와 관계가 있기 때문에 많이 헷갈렸다.. 시작 전에 시간을 가지고 그걸 먼저 이해했다면 괜찮았을 것 같다
- 괜히 쫄지말고 레퍼코드 먼저 찾지말고 원래 하던대로 시작해볼걸 그랬다. 원래 알고있던 CRUD에서 살을 붙이면 (로직을 더하면) 될 일이었다.. 쫄지말자~~!
🚨관련 에러 노트
2022.09.13 - [SPRING/🚨에러노트[SPRING]] - [220913] UserDetails = null 에러
2022.09.13 - [SPRING/🚨에러노트[SPRING]] - [220913] The given id must not be null! 에러
2022.09.13 - [SPRING/🚨에러노트[SPRING]] - [220913] JPA delete 관련 에러 (Cascade 영속성 전이 관련 에러)
'🌿SPRING > 🌱연습[SPRING]' 카테고리의 다른 글
[SPRING] 토글 만들기 (Boolean) (0) | 2022.09.22 |
---|---|
[SPRING] 좋아요 토글 만들기 (0,1) (0) | 2022.09.22 |
[SPRING] 회원정보 조회 로직 만들기 (0) | 2022.09.08 |
[SPRING] 입문주차 과제 - 출력 값 + 에러코드 만들어주기 (0) | 2022.08.19 |
[SPRING] 입문주차 과제 - 전체 게시글 목록 조회 / 게시글 조회 (0) | 2022.08.17 |