오늘은 Entity, Repository, Service, Controller로 나누고, 상품의 CRUD 기능을 구현해보겠습니다.
CRUD는 Create, Read, Update, Delete로, 현재 쇼핑몰 프로젝트에 비유하면
라고 할 수 있습니다.
이전 게시글에 포스팅 된 DB 설계를 토대로 Entity를 먼저 만듭니다.
Item, Cart, CartItem의 Entity를 만들어야 합니다.
먼저, 상품의 Entity(VO)가 필요합니다.
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
@Entity
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name; // 상품 이름
private String text; // 상품에 대한 상세설명
private int price; // 상품 가격
private int count; // 판매 개수
private int stock; // 재고
private boolean isSoldout; // 상품 상태 (판매중 / 품절)
@ManyToOne
@JoinColumn(name="user_id")
private User user; // 판매자 아이디
@OneToMany(mappedBy = "item")
private List<CartItem> cart_items = new ArrayList<>();
private String photo; // 상품 사진
}
상품의 Entity를 이름, 설명, 가격, 판매량, 재고, 상태, 사진 으로 구성하였습니다.
판매자 아이디는 User Entity로써, 회원가입할 때 사용자 정보를 담는 Entity 입니다.
로그인/회원가입 부분은 Spring Security에 따로 다루었습니다.
상품을 판매하고 있는 판매자가 누구인지 알아야 하기 때문에 @ManyToOne으로 판매자 아이디를 넣습니다. @ManyToOne인 이유는 쉽게 말해서 판매자 한 명이 여러 개의 상품을 팔 수 있기 때문입니다.
또한 CartItem Entity도 필요한데 이것은 유저의 장바구니 안에 들어있는 상품들을 의미하는 Entity 입니다.
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Entity
public class Cart {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name="user_id")
User user; // 해당 유저의 장바구니
@OneToMany(mappedBy = "cart")
private List<CartItem> cart_items = new ArrayList<>();
}
Cart Entity를 보면 CartItem Entity가 @OneToMany로 들어가 있습니다.
장바구니 안에는 장바구니 상품들이 담겨있기 때문에 둘의 연관 관계를 @OneToMany로 지정한 것입니다.
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Entity
public class CartItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="cart_id")
private Cart cart;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="item_id")
private Item item;
private int cartCount; // 카트에 담긴 상품 개수
}
Cart Entity 에서는 CartItem Entity가 @OneToMany 였지만,
여기서(CartItem Entity)는 Cart Entity가 @ManyToOne 입니다.
Item Entity도 마찬가지 입니다.
이제 각 Entity의 Repository를 만들어야 합니다.
Repository에서는 JPA를 상속받습니다.
public interface Item extends JpaRepository<Cart, Integer> {}
public interface Cart extends JpaRepository<Cart, Integer> {}
public interface CartItem extends JpaRepository<Cart, Integer> {}
다음은 Service를 만들어야 합니다.
이 게시물에서는 상품의 CRUD 기능을 다룰 것이기 때문에 ItemService만 보도록 하겠습니다. 추후에 기능을 추가하기 위해서는 CartService 와 같은 Service를 더 구현해야 합니다.
Service에는 CRUD의 기능이 구현되어 있으므로 기능 하나씩 살펴보겠습니다.
Create - 상품 등록
public void saveItem(Item item) { itemRepository.save(item); }
JPA를 상속받는 Repository의 save 함수를 사용하여 DB에 입력한 상품 정보를 저장 합니다.
Read - 상품 불러오기 (읽기)
public Item itemView(Integer id) { return itemRepository.findById(id).get(); }
여기서는 findById 함수를 사용하는데, 개별 상품을 읽어들일 때 사용합니다.
public List<Item> allItemView() { return itemRepository.findAll(); }
findAll 함수는 함수명에서 예측할 수 있듯이 전체 상품 List를 받아올 때 사용합니다.
html에서 전체 상품 리스트를 보여줘야 할 때 사용하는 함수입니다!
Update - 상품 수정
public void itemModify(Item item, Integer id) {
Item update = itemRepository.findItemById(id);
update.setName(item.getName());
update.setText(item.getText());
update.setPrice(item.getPrice());
update.setStock(item.getStock());
itemRepository.save(update);
}
상품 수정 기능에서는 update라는 새로운 Item 변수를 만듭니다.
이유는 이전에 입력되어있던 정보를 update라는 변수에 넣어두고, 새로운 정보를 set 을 통해 바꿔주는 것입니다.
따라서 최종적으로 Repository에 save 되는 것은 새로운 정보가 저장된 update 변수입니다.
Delete - 상품 삭제
public void itemDelete(Integer id) { itemRepository.deleteById(id); }
deleteById는 DB에서 id에 해당하는 데이터를 삭제시킵니다.
Service에서 구현한 기능들을 Controller에서 사용합니다.
@Controller
@RequiredArgsConstructor
public class ItemController {
private final ItemService itemService;
// 상품 등록 페이지 (GET)
@GetMapping("/item/new")
public String itemSaveForm() {
return "/seller/itemForm";
}
// 상품 등록 (POST)
@PostMapping("/item/new/pro")
public String itemSave(Item item) {
itemService.saveItem(item); return "/main";
}
// 상품 수정 페이지 (GET)
@GetMapping("/item/modify/{id}")
public String itemModifyForm(@PathVariable("id") Integer id, Model model) {
model.addAttribute("item", itemService.itemView(id));
return "/seller/itemModify";
}
// 상품 수정 (POST)
@PostMapping("/item/modify/pro/{id}")
public String itemModify(Item item, @PathVariable("id") Integer id) {
itemService.itemModify(item, id);
return "redirect:/main";
}
// 상품 상세 페이지
@GetMapping("/item/view/{id}")
public String itemView(Model model, @PathVariable("id") Integer id) {
model.addAttribute("item", itemService.itemView(id));
return "/seller/itemView";
}
// 상품 삭제
@GetMapping("/item/delete/{id}")
public String itemDelete(@PathVariable("id") Integer id) {
itemService.itemDelete(id);
return "/main";
}
이렇게 Controller에서는 @GetMapping과 @PostMapping을 이용하여 url을 설정하고, Service에서 구현한 기능들을 사용합니다.
여기서 주의할 점은 상품의 CRUD 기능은 관리자 혹은 판매자만 접근해야 하는 기능입니다. 쇼핑몰 회원들은 구매, 장바구니 등 이외에 상품을 등록하거나 삭제하는 등의 기능에는 접근을 할 수 없기 때문입니다.
즉, 위에 구현한 기능들은 모두 역할이 관리자/판매자 일 때만 가능해야 합니다.
관리자/판매자와 구매자 간의 권한 설정은 다음 게시물에서 다뤄보겠습니다!