- 상품 상세 페이지에서 장바구니에 담을 수량을 선택하고 장바구니 담기 버튼을 클릭할 때 상품이 장바구니에 담기는 기능을 구현해야 한다.
- 상품 상세 페이지에서 장바구니에 담을 상품의 아이디와 수량을 전달 받을 CartItemDto 클래스를 생성한다. (장바구니에 담을 상품의 최소 수량은 1개 이상으로 제한한다.)
- CartItemDto.java
@Getter
@Setter
public class CartItemDto {
@NotNull(message = "상품 아이디는 필수 입력 값 입니다.")
private Long itemId;
@Min(value = 1, message = "최소 1개 이상 담아주세요")
private int count;
}
- 회원 한 명당 1개의 장바구니를 갖어야 한다. 처음 장바구니에 상품을 담을 때는 해당 회원의 장바구니를 최초로 생성해줘야 한다.
- Cart 클래스에 회원 엔티티를 파라미터로 받아서 장바구니 엔티티를 생성하는 로직을 작성한다.
- Cart.java
...
public static Cart createCart(Member member) {
Cart cart = new Cart();
cart.setMember(member);
return cart;
}
- cart 객체를 생성하고 파라미터로 넘어온 member를 cart 필드의 member로 지정하게 되면서 회원이 입력된 장바구니 객체를 생성하게 된다.
- 장바구니에 담을 상품 엔티티를 생성하는 메소드와 장바구니에 담을 수량을 증가시켜 주는 메소드를 CartItem 클래스에 추가한다.
- CartItem.java
...
// 장바구니에 담을 상품 엔티티를 생성하는 메소드와 장바구니에 담을 수량을 증가시켜 주는 메소드를 작성
public static CartItem createCartItem(Cart cart, Item item, int count) {
CartItem cartItem = new CartItem();
cartItem.setCart(cart);
cartItem.setItem(item);
cartItem.setCount(count);
return cartItem;
}
public void addCount(int count) {
// 장바구니에 기존에 담겨 있는 상품인데, 해당 상품을 추가로 장바구니에 담을 때
// 기존 수량에 현재 담을 수량을 더해줄 때 사용할 메소드이다.
this.count += count;
}
- createCartItem 메서드의 파라미터로 cart, item, count를 넘김으로서 특정 cart에 담을 item과 해당 item의 갯수를 입력하고 cartItem을 반환한다.
- addCount 메서드는 최초 cart에 item을 담는 것이 아닌 기존에 있던 item을 추가할 때 사용할 메서드다.
- 현재 로그인한 회원의 Cart 엔티티를 찾기 위해서 CartRepository에 쿼리 메소드를 추가한다.
- CartRepository.java
public interface CartRepository extends JpaRepository<Cart, Long> {
// 현재 로그인한 회원의 Cart 엔티티를 찾기 위해서 CartRepository에 쿼리 메소드를 추가한다.
Cart findByMemberId(Long memberId);
}
- 파라미터로 넘어온 memberId를 기반으로 cart 엔티티의 데이터들을 조회한다.
- 장바구니에 들어갈 상품을 저장하거나 조회하기 위해서 CartItemRepository 인터페이스를 생성한다.
- CartItemRepository.java
//장바구니에 들어갈 상품을 저장하거나 조회하기 위해서 CartItemRepository 인터페이스를 생성한다.
public interface CartItemRepository extends JpaRepository<CartItem, Long> {
CartItem findByCartIdAndItemId(Long cartId, Long itemId);
// 카트 아이디와 상품 아이디를 이용해서 상품이 장바구니에 들어있는지 조회한다.
}
- JPA의 메서드명을 통한 쿼리로 데이터를 조회하고 있다.
- 상품 상세 페이지에서 장바구니에 담기 버튼이 눌리게 되면 itemId, count 값이 /cart url로 body에 담겨 post 방식으로 전달된다.
- cartItemDto는 JSON으로 넘어온 데이터를 자신의 필드에 담아 저장한다.
- 전달받은 데이터를 기반으로 controller에서 Service. addCart 메서드를 호출한다.
- 장바구니에 상품을 담는 로직을 작성하기 위한 CartService 클래스를 생성한다.
- CartService.java
//장바구니에 상품을 담는 로직을 작성하기 위한 CartService 클래스
@Service
@RequiredArgsConstructor
@Transactional
public class CartService {
private final ItemRepository itemRepository;
private final MemberRepository memberRepository;
private final CartRepository cartRepository;
private final CartItemRepository cartItemRepository;
public Long addCart(CartItemDto cartItemDto, String email) {
Item item = itemRepository.findById(cartItemDto.getItemId()).orElseThrow(EntityNotFoundException::new);
// 1. 장바구니에 담을 상품 엔티티를 조회한다.
Member member = memberRepository.findByEmail(email);
// 2. 현재 로그인한 회원 엔티티를 조회한다
Cart cart = cartRepository.findByMemberId(member.getId());
// 3. 현재 로그인한 회원의 장바구니 엔티티를 조회한다.
if (cart == null) {
cart = Cart.createCart(member);
cartRepository.save(cart);
// 4. 상품을 처음으로 장바구니에 담을 경우 해당 회원의 장바구니 엔티티를 생성한다.
}
CartItem savedCartItem = cartItemRepository.findByCartIdAndItemId(cart.getId(), item.getId());
// 5. 현재 상품이 장바구니에 이미 들어가 있는지 조회한다.
if (savedCartItem != null) {
savedCartItem.addCount(cartItemDto.getCount());
// 6. 장바구니에 이미 있던 상품일 경우 기존 수량에 현재 장바구니에 담을 수량 만큼 더해준다.
return savedCartItem.getId();
} else {
CartItem cartItem = CartItem.createCartItem(cart, item, cartItemDto.getCount());
// 7. 장바구니 엔티티, 상품 엔티티, 장바구니에 담을 수량을 이용하여 CartItem 엔티티를 생성한다.
cartItemRepository.save(cartItem);
// 8. 장바구니에 들어갈 상품을 저장한다.
return cartItem.getId();
}
}
}
public Long addCart(CartItemDto cartItemDto, String email) {
Item item = itemRepository.findById(cartItemDto.getItemId()).orElseThrow(EntityNotFoundException::new);
// 1. 장바구니에 담을 상품 엔티티를 조회한다.
Member member = memberRepository.findByEmail(email);
// 2. 현재 로그인한 회원 엔티티를 조회한다
- addCart메서드는 클라이언트로부터 받은 cartItemDto로부터 해당 상품과 갯수를 받아온다. 또 Principal에 담긴 정보를 토대로 email정보를 받아온다.
Cart cart = cartRepository.findByMemberId(member.getId());
// 3. 현재 로그인한 회원의 장바구니 엔티티를 조회한다.
if (cart == null) {
cart = Cart.createCart(member);
cartRepository.save(cart);
// 4. 상품을 처음으로 장바구니에 담을 경우 해당 회원의 장바구니 엔티티를 생성한다.
}
- cart엔티티를 memberId로부터 조회해서 해당 카트가 존재하는지 확인한다. 한 번도 장바구니에 상품을 담은적이 없으면 cart를 생성하고 cart 엔티티를 저장한다.
CartItem savedCartItem = cartItemRepository.findByCartIdAndItemId(cart.getId(), item.getId());
- cartId와 itemId를 조회하여 장바구니에 해당 상품이 있는지 조회해본다.
if (savedCartItem != null) {
savedCartItem.addCount(cartItemDto.getCount());
// 6. 장바구니에 이미 있던 상품일 경우 기존 수량에 현재 장바구니에 담을 수량 만큼 더해준다.
return savedCartItem.getId();
} else {
CartItem cartItem = CartItem.createCartItem(cart, item, cartItemDto.getCount());
// 7. 장바구니 엔티티, 상품 엔티티, 장바구니에 담을 수량을 이용하여 CartItem 엔티티를 생성한다.
cartItemRepository.save(cartItem);
// 8. 장바구니에 들어갈 상품을 저장한다.
return cartItem.getId();
}
}
- 만약 기존에 존재하는 상품일 경우, addCount메서드를 통해 추가로 갯수를 늘린다.
- 기존에 존재하는 상품이 아닐경우, createCartItem 메서드를 통해 새롭게 장바구니에 담길 상품 및 수량을 생성해준 다음, 해당 엔티티를 DB에 저장한다.
- 모든 반환값으로는 cartItem의 Id 값을 반환 받는다.
- 장바구니와 관련된 요청들을 처리하기 위해 CartController를 생성해준다.
- CartController.java
@Controller
@RequiredArgsConstructor
public class CartController {
private final CartService cartService;
@PostMapping(value = "/cart")
public @ResponseBody ResponseEntity order(@RequestBody @Valid CartItemDto cartItemDto,
BindingResult bindingResult, Principal principal) {
if (bindingResult.hasErrors()) {
// 1. 장바구니에 담을 상품 정보를 받는 cartItemDto 객체에 데이터 바인딩 시 에러가 있는지 검사한다.
StringBuilder sb = new StringBuilder();
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
sb.append(fieldError.getDefaultMessage());
}
return new ResponseEntity<String>(sb.toString(), HttpStatus.BAD_REQUEST);
}
String email = principal.getName();
// 2. 현재 로그인한 회원의 이메일 정보를 변수에 저장한다.
Long cartItemId;
try {
cartItemId = cartService.addCart(cartItemDto, email);
// 3. 화면으로부터 넘어온 장바구니에 담을 상품 정보와 현재 로그인한 회원의 이메일 정보를 이용하여
// 장바구니에 상품을 담는 로직을 호출한다.
} catch (Exception e) {
return new ResponseEntity<String>(e.getMessage(),
HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<Long>(cartItemId, HttpStatus.OK);
// 4. 결과값으로 생성된 장바구니 상품 아이디와 요청이 성공하였다는 HTTP 응답 상태 코드를 반환한다.
}
- 추후에 View로 작성될 코드의 Javascript 부분에 의해 Controller의 /cart로의 POST 요청이 호출된다.
- bindingResult를 통해 바인딩 시 에러가 있는 지 검사한다.
try {
cartItemId = cartService.addCart(cartItemDto, email);
- 이상이 없다면 addCart 메서드를 호출하여 장바구니에 상품을 추가해준다. (addCart 메서드에 대해서는 위에서 설명하였다.)
return new ResponseEntity<Long>(cartItemId, HttpStatus.OK);
- 반환값으로 ResponseEntity의 객체를 반환하고 해당 body에는 cartItemId를, HTTP 응답코드는 OK를 담아서 응답한다.
- ItemDtl.html
function addCart(){
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
var url = "/cart";
var paramData = {
itemId : $("#itemId").val(),
count : $("#count").val()
};
var param = JSON.stringify(paramData);
$.ajax({
url : url,
type : "POST",
contentType : "application/json",
data : param,
beforeSend : function(xhr){
/* 데이터를 전송하기 전에 헤더에 csrf값을 설정 */
xhr.setRequestHeader(header, token);
},
dataType : "json",
cache : false,
success : function(result, status){
alert("상품을 장바구니에 담았습니다.");
location.href='/';
},
error : function(jqXHR, status, error){
if(jqXHR.status == '401'){
alert('로그인 후 이용해주세요');
location.href='/members/login';
} else{
alert(jqXHR.responseText);
}
}
});
}
- ItemDtl.html의 페이지에서 입력된 데이터들이 Javascript에 의해 Post방식으로 /cart Url에 요청을 보내게 되면 위에 Controller에서 /cart로 Post 요청을 받아 아래 코드들을 수행하게 된다.
'Portfolio, Project > Project(Programming)' 카테고리의 다른 글
Project (7-3) 장바구니 상품 주문하기 (0) | 2023.08.18 |
---|---|
Project (7-2) 장바구니 조회, 수정, 삭제 (0) | 2023.08.17 |
Project (6-3) 주문 취소하기 (0) | 2023.08.16 |
Project (6-2) 주문 이력 조회하기 (0) | 2023.08.15 |
Project (6-1) 주문 기능 구현 (0) | 2023.08.14 |