구조
Member → Cart → CartItem
↑
Item
Item 엔티티 추가
@Entity
@Table(name = "items")
@Getter @Setter
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "item_id")
private Long id;
private String itemName;
private int price;
private int stock;
}
CartItem 엔티티 추가
@Entity // 이 클래스가 DB테이블과 매핑되는 JPA 엔티티임 선언
@Table(name = "cart_items") // DB에 생성될 실제 테이블 이름을 cart_items로 지정
@Getter @Setter // Lombok을 사용해 모든 필드의 Getter(조회)와 Setter(수정) 메서드를 자동 생성
public class CartItem {
@Id // 테이블 기본키로 지정
@GeneratedValue(strategy = GenerationType.IDENTITY) // 기본키 생성 DB에 위임
@Column(name = "cart_item_id") // DB테이블의 실제 컬럼 이름을 cart_item_id로 매핑
private Long id;
// 어떤 장바구니에 들어갔는지
@ManyToOne // 여러 아이템이 하나의 장바구니에 속함
@JoinColumn(name = "cart_id") // 외래키(FK) 컬럼 이름을 cart_id로 지정하여 Cart 테이블과 연결
private Cart cart;
// 어떤 상품인지
@ManyToOne // 여러 장바구니 아이템이 하나의 상품을 가리킬 수 있음
@JoinColumn(name = "item_id") // 외래키(FK) 컬럼 이름을 item_id로 지정하여 Item 테이블과 연결
private Item item;
private int quantity; // 수량
}
Repository 추가
public interface CartRepository extends JpaRepository<Cart, Long> {
} CartRepository가 관리하는 Cart엔티티의 PK타입은 Long
public interface CartItemRepository extends JpaRepository<CartItem, Long> {
}
public interface ItemRepository extends JpaRepository<Item, Long> {
}
CartService
@Service // 이 클래스가 비즈니스 로직(핵심 기능)을 처리하는 곳임을 스프링에 등록
@RequiredArgsConstructor //Lombok을 이용해 final이 붙은 필드(Repository)를 자동으로 주입하는 생성자를 만듦
public class CartService {
private final CartRepository cartRepository; // 장바구니 데이터를 DB에 저장하고 조회하기 위한 레포지토리
private final MemberRepository memberRepository; // 회원정보를 DB에서 조회하기 위한 레포지토리
// 장바구니 생성
public Cart createCart(Long memberId) { // 회원 ID를 받아와서 해당 회원의 장바구니를 생성하는 메서드
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new IllegalArgumentException("회원 없음"));
// 전달받은 memberId로 DB에서 회원조회. 회원 없으면 예외 처리
Cart cart = new Cart();
cart.setMember(member); // 생성한 장바구니의 주인(member)를 위에서 조회한 회원으로 지정
cart.setCreatedBy(LocalDateTime.now());
return cartRepository.save(cart); // 설정끝난 장바구니 객체를 DB에 저장하고 저장된 결과 반환
}
}
+) Required(필수적인)+ Args(인자) + Constructor(생성자) : 필수적인 필드만 가지고 생성자를 만들어라
스프링이 말하는 필수 필드: final이 붙은 필드. (자바에서 final이 붙은 변수는 값이 한번 초기화 되어야 컴파일 됨)
ItemService
package com.example.demo.service;
import com.example.demo.entity.Item;
import com.example.demo.repository.ItemRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service // 이 클래스가 핵심 비즈니스 로직을 처리하는 '서비스' 컴포넌트임을 스프링에 등록
@RequiredArgsConstructor // final이 붙은 itemRepository를 자동으로 주입해주는 생성자를 만듦
public class ItemService {
private final ItemRepository itemRepository; // 상품 데이터를 DB에 접근해 처리할 레포지토리
// 상품 생성
public Item save(Item item) {
// 전달받은 상품 객체(item)을 DB에 저장하고, 저장된 결과 반환
return itemRepository.save(item);
}
// 전체 조회
public List<Item> findAll() {
// DB에 저장된 모든 상품 리스트를 가져와서 반환
return itemRepository.findAll();
}
// 단건 조회
public Item findById(Long id) {
// 상품 ID로 특정 상품 하나를 찾음. 없으면 상품 없음 예외 발생시킴
return itemRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("상품 없음"));
}
// 수정
public Item update(Long id, Item updatedItem) {
Item item = findById(id); // 수정할 상품이 DB에 있는지 조회
// 조회해온 기존 상품 정보를 새로운 정보로 수정
item.setItemName(updatedItem.getItemName()); // 이름 변경
item.setPrice(updatedItem.getPrice()); // 가격 변경
item.setStock(updatedItem.getStock()); // 재고 변경
return itemRepository.save(item);
} // 정보가 수정된 상품 객체를 DB에 다시 저장하고 결과 반환
// 삭제
public void delete(Long id) {
// 전달받은 상품 ID에 해당하는 데이터를 DB에서 삭제
itemRepository.deleteById(id);
}
}
CartItemService
@Service
@RequiredArgsConstructor //final이 붙은 Repository들을 자동으로 주입해주는 생성자를 만듦
public class CartItemService {
private final CartRepository cartRepository; //장바구니 데이터를 조회하기 위한 레포지토리
private final ItemRepository itemRepository; //상품 데이터를 조회하기 위한 레포지토리
private final CartItemRepository cartItemRepository; //장바구니 상품 데이터를 DB에 저장하고 조회하는 레포지토리
// 장바구니에 상품 추가
public CartItem addItem(Long cartId, Long itemId, int quantity) {
Cart cart = cartRepository.findById(cartId)
.orElseThrow(() -> new IllegalArgumentException("장바구니 없음"));
Item item = itemRepository.findById(itemId)
.orElseThrow(() -> new IllegalArgumentException("상품 없음"));
CartItem cartItem = new CartItem();
cartItem.setCart(cart); // 이 장바구니 상품이 속할 장바구니 지정
cartItem.setItem(item); // 이 장바구니 상품이 가리킬 실제 상품 지정
cartItem.setQuantity(quantity); // 화면에서 넘어온 수량 설정
// 설정이 완료된 장바구니 상품(CartItem)을 DB에 저장하고 그 결과 반환
return cartItemRepository.save(cartItem);
}
// 전체 조회
public List<CartItem> getAll() {
return cartItemRepository.findAll();
}
}
CartController
@RestController // 이 클래스가 REST API의 요청을 받아 처리하고 결과를 JSON 형태로 반환하는 컨트롤러임을 스프링에 등록
@RequiredArgsConstructor // final이 붙은 cartService를 자동으로 주입해주는 생성자를 만듦
@RequestMapping("/carts") // 이 컨트롤러 내부의 모든 메서드는 URL경로가 "/carts"로 시작하도록 기본 주소 설정
public class CartController {
private final CartService cartService; // 장바구니 관련 비즈니스 로직을 호출하기 위한 서비스
@PostMapping("/{memberId}") // HTTP POST 요청을 처리하며, 전체 주소는 "/carts/{memberId}"가 됨
public Cart create(@PathVariable Long memberId) {
// @PathVariable은 URL 경로에 들어있는 값 {memberId}을 파라미터 변수(memberId)에 그대로 매핑해주는 역할
// 서비스 레이어의 createCart 메서드를 호출하여 해당 회워의 장바구니를 생성하고 결과 반환
return cartService.createCart(memberId);
}
}
ItemController
package com.example.demo.controller;
import com.example.demo.entity.Item;
import com.example.demo.service.ItemService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequiredArgsConstructor
@RequestMapping("/items") // 이 컨트롤러 내부의 모든 메서드는 URL 경로가 "/items"로 시작하도록 기본 주소 설정
public class ItemController {
private final ItemService itemService; // 상품 비즈니스 로직을 호출하기 위한 서비스 객체
// CREATE
@PostMapping // HTTP POST요청을 처리하며, 주소는 "/items"가 됨. 주로 데이터를 생성(등록)할 때 사용
public Item create(@RequestBody Item item) {
// @RequestBody는 웹 브라우저나 클라이언트가 보낸 JSON 형태의 데이터를 자바 객체(Item)로 변환하여 받아옴
return itemService.save(item);
}
// READ ALL
@GetMapping // HTTP GET요청을 처리하며, 주소는 "/items"가 됨. 주로 데이터를 조회할 때 사용
public List<Item> getAll() {
return itemService.findAll();
}
// READ ONE
@GetMapping("/{id}") // HTTP GET요청을 처리하며, 주소는 "/items/{id}"
public Item getOne(@PathVariable Long id) {
// @PathVariable은 URL 경로에 포함된 {id} 값을 파라미터 변수(id)에 그대로 매핑
return itemService.findById(id);
}
// UPDATE
@PutMapping("/{id}") // HTTP PUT요청을 처리하며, 주소는 "/items/{id}". 기존 데이터 전체 수정시 사용
public Item update(@PathVariable Long id,
@RequestBody Item item) {
// URL에서 가져온 id와 Request Body로 넘어온 수정할 JSON데이터('item 객체')를 동시에 받음
return itemService.update(id, item);
}
// DELETE
@DeleteMapping("/{id}") // HTTP DELETE 요청을 처리하며, 주소는 "/items/{id}". 데이터 삭제시 사용
public String delete(@PathVariable Long id) { // URL에서 삭제할 상품의 고유 id 가져옴
itemService.delete(id);
return "삭제 완료";
}
}
CartItemController
@RestController // 이 클래스가 REST API의 요청을 받아 처리하고 결과를 JSON 형태로 반환하는 컨트롤러임을 스프링에 등록
@RequiredArgsConstructor
@RequestMapping("/cart-items") // 이 컨트롤러 내부의 모든 메서드는 URL 경로가 /cart-items로 시작
public class CartItemController {
private final CartItemService cartItemService;
// 상품 추가
@PostMapping //HTTP POST요청 처리. 주소는 "/cart-items"가 됨. 주로 데이터를 생성(등록)할 때 사용
public CartItem addItem(
@RequestParam Long cartId, // URL 쿼리 파라미터나 폼 데이터에서 "cartId"라는 이름의 값 받아옴
@RequestParam Long itemId, // URL 쿼리 파라미터나 폼 데이터에서 "itemId"라는 이름의 값 받아옴
@RequestParam int quantity // URL 쿼리 파라미터나 폼 데이터에서 "quantity"라는 이름의 값 받아옴
) {
return cartItemService.addItem(cartId, itemId, quantity);
}
// 조회
@GetMapping //HTTP GET요청 처리. 주소는 "/cart-items"가 됨. 주로 데이터를 조회할 때 사용
public List<CartItem> getAll() {
return cartItemService.getAll();
}
}
포스트맨 실습
Cart
- 장바구니 생성
: 5번회원의 장바구니 id는 3번으로 매핑
생성이므로 POST타입
서버에 넘겨줄 내용이 없으므로 Body태그 필요 없음
CartController의 @PostMapping과 매핑

- 장바구니 담기
: 새 장바구니 내역을 만드는 것이므로 POST
ex) 3번 장바구니에 2번 아이템을 1개 담기
Cart id위에 새로운 id는 CartItem의 PK (여기서는 2)
내부에 포함된 cart id 3과 item id 2는 각각 장바구니 테이블과 상품 테이블을 연결해주는 외래 키(FK)
URL은 CartController의 @RequestParam으로 주입

- 장바구니 조회
: 조회이므로 GET
모든 회원의 장바구니 내역이 전부 조회
ex) 김바덕의 장바구니에는 키보드가 1개, 추바덕의 장바구니에는 마우스가 1개 담겨있음
내부에 포함된 cart id 3과 item id 2는 각각 장바구니 테이블과 상품 테이블을 연결해주는 외래 키(FK)

item
- 아이템 생성
: 생성이므로 POST
Body태그에 생성할 아이템의 정보 적음
상품 이름, 가격, 재고 등을 적어 보내면 @RequestBody가 이를 객체로 받아들임

- 수정
: 데이터 수정이므로 PUT(이전데이터 덮어쓰기)
Body태그에 덮어쓸 내용 적음
ItemController의 @PutMapping("/{itemId}") 메서드와 매핑

- 전체 조회
: 현재 모든 아이템 조회됨
조회이므로 GET
Body태그 필요없음
ItemController의 @GetMapping 메서드와 매핑

- 삭제
: URL 끝에 /3 등을 붙여 아이템 지움
삭제이므로 DELETE
Body태그 필요없음
ItemController의 @DeleteMapping("/{itemId}") 메서드가 요청을 받음

member
- 단건 조회
: URL 맨 끝에 /1 등을 붙여 한명의 회원을 조회할 수 있음
데이터 조회는 GET
Body태그 필요없음
@GetMapping 메서드와 매핑

- 삭제
: 4번 회원 삭제
삭제이므로 DELETE
Body태그 필요없음
MemberController 내부의 삭제 메서드가 이를 수신

- 회원 생성
: 삭제를 통해 2,3,4번 회원이 사라졌어도 새 회원이 생성될 때 id는 5부터 시작(id는 PK이고, DB의 자동 증가 규칙에 따름)
생성이므로 POST
Body 태그에 생성할 새 회원 정보를 적음
이름, 이메일, 비밀번호, 주소 등을 적어 보내면 @RequestBody가 이를 회원 객체로 변환하여 받아들임

- 수정
: 6번 회원의 정보 수정
데이터 수정이므로 PUT(기존 데이터 덮어쓰기)
Body태그에 덮어쓸 내용 적음
@PutMapping , @RequestBody가 처리

- 전체 조회
: 현재 전체 회원 조회
조회이므로 GET
Body태그 필요 없음
@GetMapping 메서드와 매핑

'SWLUG(2026) > 유지보수' 카테고리의 다른 글
| [SV 2주차] 이미지 로드 실패 (0) | 2026.07.08 |
|---|---|
| [SV 1주차] 회원가입 시 이메일 인증오류 (0) | 2026.07.01 |
| [4주차] member entity, order entity, cart entity 설계 / 포스트맨 실습 (0) | 2026.05.10 |
| [3주차] DB 설명 및 설계 & 프로젝트 실습 1차 (0) | 2026.05.06 |
| [2주차] Git & Github, 스프링부트 (0) | 2026.04.29 |