1. Product 관리 - 등록, 수정, 삭제
ProductDto (상품 리스트 반환할 때 쓰인다.)
엔티티인 Product를 직접 사용해서 어떤 코드를 작성하면 참조형 데이터의 특성상 데이터베이스의 내용이 바로 변경될 우려가 있다.
그래서 Dto라는 클래스를 이용한다.
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProductDto {
private Long id;
private String productName;
private Integer price;
private Boolean soldOutYn;
private String productImg;
@Enumerated(EnumType.STRING)
private Category category;
private Integer productQuantity;
private LocalDateTime stockedDt;
private Integer cumulativeSales;
long totalCount;
long seq;
public static List<ProductDto> of (List<Product> productList) {
if (productList != null ) {
List<ProductDto> productDtoList = new ArrayList<>();
for (Product product : productList) {
productDtoList.add(of(product));
}
return productDtoList;
}
return null ;
}
static ProductDto of (Product parameter) {
return ProductDto.builder()
.category(parameter.getCategory())
.cumulativeSales(parameter.getCumulativeSales())
.price(parameter.getPrice())
.productImg(parameter.getProductImg())
.productName(parameter.getProductName())
.productQuantity(parameter.getProductQuantity())
.soldOutYn(parameter.getSoldOutYn())
.stockedDt(parameter.getStockedDt())
.build();
}
}
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class ProductInput {
private Long id;
private String productName;
private Integer price;
private String productImg;
@Enumerated(EnumType.STRING)
private Category category;
private Integer productQuantity;
private LocalDateTime stockedDt;
}
ProductParam - id만 가지고 상품을 찾을 때 쓸 수 있다.
@Data
public class ProductParam extends CommonParam {
long id;
}
package com.example.mall.admin.controller;
import com.example.mall.admin.model.ProductDto;
import com.example.mall.admin.model.ProductInput;
import com.example.mall.admin.model.ProductParam;
import com.example.mall.admin.service.ProductService;
import com.example.mall.controller.BaseController;
import com.example.mall.member.service.MemberService;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
@RequiredArgsConstructor
public class AdminProductController extends BaseController {
private final ProductService productService;
private final MemberService memberService;
@GetMapping("/admin/product/list.do")
public String list (Model model,
ProductParam param) {
param.init();
List<ProductDto> list = productService.list();
long totalCount = 0 ;
if (list != null && list.size() > 0 ) {
totalCount = productService.list().size();
}
String queryString = param.getQueryString();
String pagerHtml = getPaperHtml(totalCount,
param.getPageSize(),
param.getPageIndex(),
queryString);
model.addAttribute("list" , list);
model.addAttribute("totalCount" , totalCount);
model.addAttribute("pager" , pagerHtml);
model.addAttribute("list" , list);
return "admin/product/list" ;
}
@PostMapping("/admin/product/add.do")
public String add (Model model, ProductInput parameter) {
boolean result = productService.add(parameter);
return "redirect:/admin/product/list.do" ;
}
@PostMapping("/admin/product/delete.do")
public String del (Model model, ProductInput parameter) {
boolean result = productService.delete(parameter.getId());
return "redirect:/admin/product/list.do" ;
}
@PostMapping("/admin/product/update.do")
public String update (Model model, ProductInput parameter) {
boolean result = productService.update(parameter);
return "redirect:/admin/product/list.do" ;
}
}
public interface ProductService {
boolean add (ProductInput product) ;
boolean update (ProductInput parameter) ;
boolean delete (long id) ;
List<ProductDto> list () ;
}
========================오류 - update() 가 작동하지 않는다. ========================
오류: update()를 실행해도 데이터베이스에 들어가지 않는다.
원인: product를 save()하지 않았다.
package com.example.mall.admin.service.impl;
import com.example.mall.admin.model.ProductDto;
import com.example.mall.admin.model.ProductInput;
import com.example.mall.admin.repository.ProductRepository;
import com.example.mall.admin.service.ProductService;
import com.example.mall.entity.Product;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class ProductServiceImpl implements ProductService {
private final ProductRepository productRepository;
@Override
public boolean add (ProductInput parameter) {
Product product = Product.builder().productName(parameter.getProductName())
.productImg(parameter.getProductImg()).productQuantity(parameter.getProductQuantity())
.price(parameter.getPrice()).category(parameter.getCategory())
.stockedDt(parameter.getStockedDt()).build();
productRepository.save(product);
return true ;
}
@Override
public boolean delete (long id) {
Optional<Product> OptionalProduct = productRepository.findById(id);
productRepository.delete(OptionalProduct.get());
return true ;
}
@Override
public List<ProductDto> list () {
return ProductDto.of(productRepository.findAll());
}
}
<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org" >
<head>
<meta charset="UTF-8" >
<title>관리자</title>
<style>
.list table {
width: 100 %;
border-collapse: collapse;
}
.list table th, .list table td {
border: solid 1px #000 ;
}
.search-form {
position: relative;
padding: 5px 0 5px 0 ;
text-align: right;
}
.search-form .total-count {
position-position: absolute;
left: 0 ;
top: 0 ;
height: 20px;
float : left;
}
.pager {
margin-top: 10px;
text-align: center;
}
.pager a.on {
font-weight: bold;
color: red;
}
</style>
</head>
<body>
<h1>관리자 상품 리스트</h1>
<div th:replace="/fragments/layout.html :: fragment-admin-body-menu" ></div>
<div class ="list" >
<div class ="search-form" >
<p class ="total-count" >전체 <span th:text="${totalCount}" ></span>개 </p>
<form method="get" >
<select name="searchType" >
<option value="all" >전체</option>
<!-- 상품을 검색하기 위한 수단 상품 이름 / 카테고리 / -->
<!-- 문자열이 아닌 형태는 어떻게 처리하지???-->
<option th:selected="${#strings.equals(param.searchType, 'productId')}" value="productId" >상품
No
</option>
<option th:selected="${#strings.equals(param.searchType, 'productName')}"
value="productName" >이름
</option>
<option th:selected="${#strings.equals(param.searchType, 'price')}" value="price" >가격
</option>
</select>
<input th:value="${param.searchValue}" type="search" name="searchValue" placeholder="검색어 입력" />
<button type="submit" >검색</button>
</form>
</div>
<table>
<thead>
<tr>
<th>No</th>
<th>카테고리</th>
<th>상품 Id</th>
<th>상품명</th>
<th>가격</th>
<th>품절 여부</th>
<th>상품 사진</th>
<th>재고 수량</th>
<th>입고 예정일</th>
<th>누적 판매량</th>
</tr>
</thead>
<tbody>
<tr th:each="x : ${list}" >
<td th:th:text="${x.seq}" ></td>
<td th:th:text="${x.category}" ></td>
<td th:text="${x.id}" ></td>
<td th:text="${x.productName}" ></td>
<td th:text="${x.price}" ></td>
<td th:text="${x.soldOutYn}" ></td>
<td th:text="${x.productImg}" ></td>
<td th:text="${x.productQuantity}" ></td>
<td th:text="${x.stockedDt}" ></td>
<td th:text="${x.cumulativeSales}" ></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
Note) 실행 결과
Ex) delete 테스트
productService .delete(1 L);
Ex) update 테스트
ProductInput productInput = ProductInput.builder()
.id(3L )
.productName("목걸이" )
.productQuantity(0 )
.price(542 )
.category(Category.CATEGORY_ACCESSORY)
.build();
productService.update(productInput);
@Override
public boolean update (ProductInput parameter) {
Optional<Product> OptionalProduct = productRepository.findById(parameter.getId());
if (OptionalProduct.isPresent()) {
Product product = OptionalProduct.get();
product.setProductImg(parameter.getProductImg());
product.setProductName(parameter.getProductName());
product.setProductQuantity(parameter.getProductQuantity());
product.setCategory(parameter.getCategory());
product.setPrice(parameter.getPrice());
product.setStockedDt(parameter.getStockedDt());
productRepository.save(product);
return true ;
}
return false ;
}
점검 사항
add(), delete() 는 확인 완료
update() 구현부 마지막에 save()를 해줘야한다!
상품 추가, delete는 html에 내용 추가하기
cart : product 는 일대다 연관 관계
그러면 cart하나에 여러 개의 product를 매핑 가능하다
장바구니는 곧 멤버를 의미한다.