
사용자가 구매하고 싶은 상품을 임시로 담아두는 기능
주요 기능

src/main/java/com/onandhome/
├── cart/
│ ├── entity/
│ │ └── CartItem.java # 장바구니 아이템 엔티티
│ ├── CartItemRepository.java # JPA Repository
│ ├── CartService.java # 비즈니스 로직
│ └── CartRestController.java # REST API
├── admin/adminProduct/
│ └── entity/Product.java # 상품 엔티티
└── user/
└── entity/User.java # 사용자 엔티티
@Entity
@Getter
@Setter
@Table(name = "cart_item")
public class CartItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 사용자 (N:1)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "user_id", nullable = false)
private User user;
// 상품 (N:1)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "product_id", nullable = false)
private Product product;
// 수량
@Column(nullable = false)
private int quantity;
}
핵심 포인트
FetchType.EAGER: 장바구니 조회 시 상품 정보 즉시 로딩
public interface CartItemRepository extends JpaRepository<CartItem, Long> {
// 사용자의 장바구니 조회
List<CartItem> findByUser(User user);
// 중복 체크 (사용자 + 상품)
Optional<CartItem> findByUserAndProduct(User user, Product product);
// 사용자의 장바구니 전체 삭제
void deleteByUser(User user);
}
@Service
@RequiredArgsConstructor
@Transactional
public class CartService {
private final CartItemRepository cartRepo;
private final ProductRepository productRepo;
private final UserRepository userRepo;
/**
* 장바구니 목록 조회
*/
public List<CartItem> getCartItems(Long userId) {
User user = userRepo.findById(userId).orElse(null);
if (user == null) return List.of();
return cartRepo.findByUser(user);
}
/**
* 장바구니 담기
* - 중복 상품: 수량 증가
* - 새 상품: CartItem 생성
*/
@Transactional
public CartItem addToCart(Long userId, Long productId, int qty) {
// User, Product 조회
User user = userRepo.findById(userId)
.orElseThrow(() -> new IllegalArgumentException(
"사용자를 찾을 수 없습니다."));
Product product = productRepo.findById(productId)
.orElseThrow(() -> new IllegalArgumentException(
"상품을 찾을 수 없습니다."));
// 중복 체크
Optional<CartItem> existing =
cartRepo.findByUserAndProduct(user, product);
if (existing.isPresent()) {
// 기존 아이템: 수량 증가
CartItem item = existing.get();
item.setQuantity(item.getQuantity() + Math.max(qty, 1));
return cartRepo.save(item);
}
// 새 아이템: 생성
CartItem item = new CartItem();
item.setUser(user);
item.setProduct(product);
item.setQuantity(Math.max(qty, 1));
return cartRepo.save(item);
}
/**
* 수량 변경
*/
@Transactional
public CartItem updateQuantity(Long cartItemId, int quantity) {
CartItem item = cartRepo.findById(cartItemId).orElseThrow();
item.setQuantity(Math.max(quantity, 1));
return cartRepo.save(item);
}
/**
* 아이템 삭제
*/
@Transactional
public void removeItem(Long cartItemId) {
cartRepo.deleteById(cartItemId);
}
/**
* 장바구니 비우기
*/
@Transactional
public void clearCart(Long userId) {
User user = userRepo.findById(userId).orElseThrow();
cartRepo.deleteByUser(user);
}
}
@RestController
@RequestMapping("/api/cart")
@RequiredArgsConstructor
public class CartRestController {
private final CartService cartService;
private final JWTUtil jwtUtil;
private final UserRepository userRepository;
/**
* 장바구니 담기
* POST /api/cart/add
*/
@PostMapping("/add")
public ResponseEntity<Map<String, Object>> addToCart(
@RequestBody AddToCartRequest request,
@RequestHeader("Authorization") String authHeader) {
Map<String, Object> response = new HashMap<>();
try {
// JWT 토큰 검증
String token = authHeader.substring(7);
Map<String, Object> claims = jwtUtil.validateToken(token);
String userId = (String) claims.get("userId");
User user = userRepository.findByUserId(userId)
.orElseThrow(() -> new IllegalArgumentException(
"사용자를 찾을 수 없습니다."));
// 장바구니 담기
CartItem cartItem = cartService.addToCart(
user.getId(),
request.getProductId(),
request.getQuantity()
);
response.put("success", true);
response.put("message", "장바구니에 상품이 추가되었습니다.");
response.put("data", cartItem);
return ResponseEntity.ok(response);
} catch (Exception e) {
response.put("success", false);
response.put("message", e.getMessage());
return ResponseEntity.status(500).body(response);
}
}
/**
* 장바구니 조회
* GET /api/cart
*/
@GetMapping
public ResponseEntity<Map<String, Object>> getCart(
@RequestHeader("Authorization") String authHeader) {
Map<String, Object> response = new HashMap<>();
try {
String token = authHeader.substring(7);
Map<String, Object> claims = jwtUtil.validateToken(token);
String userId = (String) claims.get("userId");
User user = userRepository.findByUserId(userId)
.orElseThrow(() -> new IllegalArgumentException(
"사용자를 찾을 수 없습니다."));
List<CartItem> cartItems =
cartService.getCartItems(user.getId());
response.put("success", true);
response.put("data", cartItems);
response.put("count", cartItems.size());
return ResponseEntity.ok(response);
} catch (Exception e) {
response.put("success", false);
response.put("message", e.getMessage());
return ResponseEntity.status(500).body(response);
}
}
/**
* 수량 변경
* PUT /api/cart/{cartItemId}
*/
@PutMapping("/{cartItemId}")
public ResponseEntity<Map<String, Object>> updateQuantity(
@PathVariable Long cartItemId,
@RequestBody UpdateQuantityRequest request,
@RequestHeader("Authorization") String authHeader) {
Map<String, Object> response = new HashMap<>();
try {
CartItem updatedItem = cartService.updateQuantity(
cartItemId, request.getQuantity());
response.put("success", true);
response.put("data", updatedItem);
return ResponseEntity.ok(response);
} catch (Exception e) {
response.put("success", false);
response.put("message", e.getMessage());
return ResponseEntity.status(500).body(response);
}
}
/**
* 아이템 삭제
* DELETE /api/cart/{cartItemId}
*/
@DeleteMapping("/{cartItemId}")
public ResponseEntity<Map<String, Object>> removeItem(
@PathVariable Long cartItemId,
@RequestHeader("Authorization") String authHeader) {
Map<String, Object> response = new HashMap<>();
try {
cartService.removeItem(cartItemId);
response.put("success", true);
response.put("message", "장바구니에서 상품이 제거되었습니다.");
return ResponseEntity.ok(response);
} catch (Exception e) {
response.put("success", false);
response.put("message", e.getMessage());
return ResponseEntity.status(500).body(response);
}
}
// DTO 클래스
public static class AddToCartRequest {
private Long productId;
private int quantity;
// getter, setter
}
public static class UpdateQuantityRequest {
private int quantity;
// getter, setter
}
}
POST http://localhost:8080/api/user/login
Content-Type: application/json
{
"userId": "user123",
"password": "Password1!"
}
응답에서 accessToken 복사
{
"success": true,
"accessToken": "eyJhbGciOiJIUzI1NiJ9...",
"user": { ... }
}
POST http://localhost:8080/api/cart/add
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
Content-Type: application/json
{
"productId": 1,
"quantity": 2
}
GET http://localhost:8080/api/cart
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
PUT http://localhost:8080/api/cart/1
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
Content-Type: application/json
{
"quantity": 10
}
DELETE http://localhost:8080/api/cart/1
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...



표시 정보
