-
쇼핑몰 프로젝트 -- 카테고리, 리뷰(화면구현)쇼핑몰 프로젝트 2024. 6. 20. 04:51
어제 아이템 전체 조회를 해서 오늘은 카테고리별 아이템 조회를 했다.
categoryRepository
//categoryId 단건조회 public Category findOneCategory(Long categoryId) { if (categoryId == null) { throw new IllegalArgumentException("Category ID must not be null"); } Category category = em.find(Category.class, categoryId); if (category == null) { throw new IllegalArgumentException("Category not found for ID: " + categoryId); } return category; }
//카테고리 당 아이템 조회(검색, 정렬, 페이징) public List<Item> findAllItemPagingSortByAndKeyword(Long categoryId, String keyword, Pageable pageable, String sortBy) { String queryString = "select distinct i from Item i" + " join fetch i.category c" + " where i.category.categoryId = :categoryId"; // 검색 조건 추가 boolean hasKeyword = (keyword != null && !keyword.isEmpty()); if (hasKeyword) { queryString += " and i.itemName like :keyword"; } // 기본 정렬 조건 queryString += " order by i.itemId desc"; // 최신순으로 정렬 (itemId가 클수록 최신 데이터) // 추가 정렬 조건 if ("itemRatings".equals(sortBy)) { queryString += ", i.itemRatings desc"; } else if ("likeCount".equals(sortBy)) { queryString += ", i.likeCount desc"; } TypedQuery<Item> query = em.createQuery(queryString, Item.class) .setParameter("categoryId", categoryId) .setFirstResult((int) pageable.getOffset()) .setMaxResults(pageable.getPageSize()); // 검색 키워드 파라미터 설정 if (hasKeyword) { query.setParameter("keyword", "%" + keyword + "%"); } return query.getResultList(); }
itemService
//categoryId단건조회 public Category findOneCategory(Long categoryId) { return categoryRepository.findOneCategory(categoryId); }
//카테고리당 아이템 조회(정렬,검색,페이징) public List<ItemListDto> finaAllItemPagingSortBy(Long categoryId, String keyword, Pageable pageable, String sortBy) { List<Item> items = itemRepository.findAllItemPagingSortByAndKeyword(categoryId, keyword, pageable, sortBy); List<ItemListDto> result = items.stream() .map(ItemListDto::new) .collect(Collectors.toList()); return result; }
itemController
//카테고리당 아이템 조회(정렬,검색,페이징(페이징받아서 페이징)) @GetMapping("/ypjs/categoryItem/get/{categoryId}") public String getAllCategoryItem(@PathVariable("categoryId") Long categoryId, @RequestParam(value = "page",defaultValue = "0") int page, @RequestParam(value = "size",defaultValue = "6") int size, @RequestParam(value = "sortBy", defaultValue = "itemId") String sortBy, @RequestParam(value = "keyword", required = false) String keyword, Model model) { Pageable pageable = PageRequest.of(page, size); categoryService.findOneCategory(categoryId); List<ItemListDto> items = itemService.finaAllItemPagingSortBy(categoryId, keyword, pageable, sortBy); // CategoryOneDto category = new CategoryOneDto(findCategory, items); model.addAttribute("items",items); return "item/itemCategoryList"; }
item/itemCategoryList
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" lang="en"> <head th:replace="frame/header :: head"> <title>Zay Shop - Product Listing Page</title> </head> <style> .fixed-size-img { width: 300px; /* 원하는 너비로 설정 */ height: 300px; /* 원하는 높이로 설정 */ object-fit: cover; /* 이미지를 크기에 맞게 조정 */ } </style> <body> <!--header--> <header th:replace="frame/header :: header"></header> <!-- Start Content --> <div class="container py-5"> <div class="row"> <div class="col-lg-3"> <h1 class="h2 pb-4">Categories</h1> <ul class="list-unstyled templatemo-accordion"> <li class="pb-3"> <a class="collapsed d-flex justify-content-between h3 text-decoration-none" href="#"> Women <i class="fa fa-fw fa-chevron-circle-down mt-1"></i> </a> <ul class="collapse show list-unstyled pl-3"> <li><a class="text-decoration-none" th:href="@{/ypjs/categoryItem/get/{categoryId}(categoryId=3)}">Outer</a></li> <li><a class="text-decoration-none" th:href="@{/ypjs/categoryItem/get/{categoryId}(categoryId=4)}">Top</a></li> <li><a class="text-decoration-none" th:href="@{/ypjs/categoryItem/get/{categoryId}(categoryId=5)}">Bottom</a></li> </ul> </li> <li class="pb-3"> <a class="collapsed d-flex justify-content-between h3 text-decoration-none" href="#"> Man <i class="pull-right fa fa-fw fa-chevron-circle-down mt-1"></i> </a> <ul id="collapseTwo" class="collapse list-unstyled pl-3"> <li><a class="text-decoration-none" th:href="@{/ypjs/categoryItem/get/{categoryId}(categoryId=6)}">Outer</a></li> <li><a class="text-decoration-none" th:href="@{/ypjs/categoryItem/get/{categoryId}(categoryId=7)}">Top</a></li> <li><a class="text-decoration-none" th:href="@{/ypjs/categoryItem/get/{categoryId}(categoryId=8)}">Bottom</a></li> </ul> </li> </ul> </div> <div class="col-lg-9"> <div class="row"> <div class="col-md-6"> <ul class="list-inline shop-top-menu pb-3 pt-1"> <li class="list-inline-item"> <a class="h3 text-dark text-decoration-none mr-3" th:href="@{/ypjs/item/get}">All Items</a> </li> </ul> </div> <div class="col-md-6 pb-4"> <div class="d-flex"> <select class="form-control"> <option>최신순</option> <option>별점높은순</option> <option>찜많은순</option> </select> </div> </div> </div> <div class="container-fluid mt-3"> <div class="row"> <!-- items 리스트의 각 항목을 반복 --> <div th:each="item : ${items}" class="col-md-4"> <div class="card mb-4 product-wap rounded-0"> <!-- 제품 이미지 --> <div class="card rounded-0"> <a th:href="@{/ypjs/item/get/{itemId}(itemId=${item.itemId})}"> <img class="card-img rounded-0 img-fluid fixed-size-img" th:src="${item.itemFilePath}" alt="product-item"> <!-- 필요한 경우 오버레이나 추가 요소를 여기에 추가할 수 있습니다 --> <div class="card-img-overlay rounded-0 product-overlay d-flex align-items-center justify-content-center"> <!-- 추가적인 콘텐츠가 필요하다면 여기에 추가할 수 있습니다 --> <ul class="list-unstyled"> <!-- 리스트의 다른 요소들 --> </ul> </div> </a> </div> <!-- 제품 정보 --> <div class="card-body"> <!-- 제품 링크 --> <a th:href="@{/ypjs/item/get/{itemId}(itemId=${item.itemId})}" id="itemName" class="font-weight-bold" th:text="${item.itemName}"></a> <!-- 별점 표시 --> <ul class="list-unstyled d-flex justify-content-center mb-1"> <li> <i class="text-warning fa fa-star"></i> <i class="text-warning fa fa-star"></i> <i class="text-warning fa fa-star"></i> <i class="text-muted fa fa-star"></i> <i class="text-muted fa fa-star"></i> </li> </ul> <!-- 가격 표시 --> <span id="itemPrice" class="font-weight-bold" th:text="${item.itemPrice}"></span> <span class="font-weight-bold">원</span> </div> </div> </div> </div> </div> </div> </div> </div> </div> <!-- End Content --> <!-- Start Brands --> <section class="bg-light py-5"> <div class="container my-4"> <div class="row text-center py-3"> <div class="col-lg-6 m-auto"> <h1 class="h1">Our Brands</h1> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod Lorem ipsum dolor sit amet. </p> </div> <div class="col-lg-9 m-auto tempaltemo-carousel"> <div class="row d-flex flex-row"> <!--Controls--> <div class="col-1 align-self-center"> <a class="h1" href="#multi-item-example" role="button" data-bs-slide="prev"> <i class="text-light fas fa-chevron-left"></i> </a> </div> <!--End Controls--> <!--Carousel Wrapper--> <div class="col"> <div class="carousel slide carousel-multi-item pt-2 pt-md-0" id="multi-item-example" data-bs-ride="carousel"> <!--Slides--> <div class="carousel-inner product-links-wap" role="listbox"> <!--First slide--> <div class="carousel-item active"> <div class="row"> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_01.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_02.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_03.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_04.png" alt="Brand Logo"></a> </div> </div> </div> <!--End First slide--> <!--Second slide--> <div class="carousel-item"> <div class="row"> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_01.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_02.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_03.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_04.png" alt="Brand Logo"></a> </div> </div> </div> <!--End Second slide--> <!--Third slide--> <div class="carousel-item"> <div class="row"> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_01.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_02.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_03.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_04.png" alt="Brand Logo"></a> </div> </div> </div> <!--End Third slide--> </div> <!--End Slides--> </div> </div> <!--End Carousel Wrapper--> <!--Controls--> <div class="col-1 align-self-center"> <a class="h1" href="#multi-item-example" role="button" data-bs-slide="next"> <i class="text-light fas fa-chevron-right"></i> </a> </div> <!--End Controls--> </div> </div> </div> </div> </section> <!--End Brands--> <footer th:replace="frame/footer :: footer"></footer> </body> </html>
카테고리 3번에 해당하는 화면
카테고리 리스트 전체 조회
categoryRepository
// category 전체 조회 public List<Category> findAll(Long categoryId, String keyword, Pageable pageable) { String queryString = "select c from Category c where 1=1"; // 카테고리 아이디로 검색 조건 추가 if (categoryId != null) { queryString += " and c.categoryId = :categoryId"; } // 키워드로 카테고리 이름 검색 조건 추가 if (keyword != null && !keyword.isEmpty()) { queryString += " and c.categoryName like :keyword"; } // 카테고리 아이디와 키워드가 모두 비어 있는 경우 if (categoryId == null && (keyword == null || keyword.isEmpty())) { // 이 경우, 전체 카테고리를 조회하도록 queryString에 추가 조건 없음 queryString = "select c from Category c"; } TypedQuery<Category> query = em.createQuery(queryString, Category.class) .setFirstResult((int) pageable.getOffset()) .setMaxResults(pageable.getPageSize()); // 매개변수 바인딩 if (categoryId != null) { query.setParameter("categoryId", categoryId); } if (keyword != null && !keyword.isEmpty()) { query.setParameter("keyword", "%" + keyword + "%"); } return query.getResultList(); }
categoryService
//category전체 조회 public List<CategoryListDto> findAllCategory(Long categoryId, String keyword, Pageable pageable) { //List<Category> categories = categoryRepository.findAllWithItem(); List<Category> categories = categoryRepository.findAll(categoryId, keyword, pageable); List<CategoryListDto> result = categories.stream() .map(c -> new CategoryListDto(c)) .collect(Collectors.toList()); return result; }
categoryController
//categoryList보기 @GetMapping("/ypjs/category/get") public String getCategoryList(Model model, @RequestParam(value = "categoryId", required = false) Long categoryId, @RequestParam(value = "page", defaultValue = "0") int page, @RequestParam(value = "size", defaultValue = "8") int size, @RequestParam(value = "keyword", required = false) String keyword) { Pageable pageable = PageRequest.of(page, size); List<CategoryListDto> categories = categoryService.findAllCategory(categoryId, keyword, pageable); model.addAttribute("categories", categories); return "category/categoryList"; }
category/categoryList
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" lang="en"> <head th:replace="frame/header :: head"> <title>Zay Shop - Product Listing Page</title> </head> <body> <!--header--> <header th:replace="frame/header :: header"></header> <!-- Start Content --> <div class="container py-5"> 카테고리 리스트 </div> <!-- End Content --> <!-- jQuery --> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- JS 파일 포함 --> <script src="/js/jquery-1.11.0.min.js"></script> <script src="/js/summernote-lite.js"></script> <script src="/js/summernote-ko-KR.js"></script> <script src="/js/item/category.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote.min.js"></script> <!-- Start Contact --> <div class="container py-5"> <div class="row py-5"> <form class="col-md-9 m-auto" method="post" > <!-- 폼 요소들 --> <div class="row"> <style> .category-box { border: 1px solid #ccc; padding: 10px; margin-bottom: 10px; } .category-label { font-weight: bold; } </style> <div th:each="category : ${categories}" class="category-box"> <div> <span class="category-label">카테고리 번호 </span> <span>:</span> <a th:href="@{/ypjs/category/get/{categoryId}(categoryId=${category.categoryId})}" th:text="${category.categoryId}"></a> </div> <div> <span class="category-label">카테고리 부모 번호 </span> <span>:</span> <span th:text="${category.categoryParent}"></span> </div> <div> <span class="category-label">카테고리 이름 </span> <span>:</span> <span th:text="${category.categoryName}"></span> </div> </div> <!-- End Contact --> </div> </form> </div> </div> <footer th:replace="frame/footer :: footer"></footer> </body> </html>
여기서 카테고리 보기를 누르면
이렇게 쭉 카테고리 리스트가 나온다.
이제 카테고리를 등록할 거다
categoryRepository//categoryId 단건조회 public Category findOneCategory(Long categoryId) { if (categoryId == null) { throw new IllegalArgumentException("Category ID must not be null"); } Category category = em.find(Category.class, categoryId); if (category == null) { throw new IllegalArgumentException("Category not found for ID: " + categoryId); } return category; }
//카테고리 저장 public void saveCategory(Category category) { em.persist(category); }
categoryService
//category등록 @Transactional public Category saveCategory(CategoryRequestDto categoryRequestDto) { Category parentCategory = categoryRepository.findOneCategory(categoryRequestDto.getCategoryParent()); Category category = new Category( parentCategory, categoryRequestDto.getCategoryName() ); categoryRepository.saveCategory(category); return category; }
categoryContoller
//카테고리 등록 화면 @GetMapping("/ypjs/category/post") public String insert() {return "category/categoryPost";} //category등록 @PostMapping("/ypjs/category/post") public CategoryRespnseDto saveCategory(@RequestBody @Valid CategoryRequestDto categoryRequestDtorequest, HttpSession session){ //멤버정보 찾기 LoginDto.ResponseLogin responseLogin = (LoginDto.ResponseLogin) session.getAttribute("member"); Category category = categoryService.saveCategory(categoryRequestDtorequest); return new CategoryRespnseDto(category.getCategoryId(), category.getCategoryParent(), category.getCategoryName()); }
category/categoryPost
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" lang="en"> <head th:replace="frame/header :: head"> <title>Zay Shop - Product Listing Page</title> </head> <body> <!--header--> <header th:replace="frame/header :: header"></header> <!-- Start Content --> <div class="container py-5"> 카테고리 등록 </div> <!-- End Content --> <!-- jQuery --> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- JS 파일 포함 --> <script src="/js/jquery-1.11.0.min.js"></script> <script src="/js/summernote-lite.js"></script> <script src="/js/summernote-ko-KR.js"></script> <script src="/js/item/category.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote.min.js"></script> <!-- Start Contact --> <div class="container py-5"> <div class="row py-5"> <form class="col-md-9 m-auto" method="post"> <!-- 폼 요소들 --> <div class="row"> <div class="form-group mb-3"> <label for="categoryParent">카테고리 부모 번호</label> <input type="text" class="form-control mt-1" id="categoryParent" name="categoryParent" placeholder="카테고리 부모 번호"> </div> <div class="form-group mb-3"> <label for="categoryName">카테고리 이름</label> <input type="text" class="form-control mt-1" id="categoryName" name="categoryName" placeholder="카테고리 이름"> </div> <!-- 글 등록 버튼 --> <div class="row"> <div class="col text-end mt-2"> <!-- 버튼 id가 btn-categoryPost로 변경되었습니다. --> <button type="button" id="btn-categoryPost" class="btn btn-success btn-lg px-3">카테고리 등록</button> </div> </div> </div> </form> </div> </div> <!-- End Contact --> <footer th:replace="frame/footer :: footer"></footer> </body> </html>
category.js
let categoryBoardObject = { init: function() { let _this = this; $("#btn-categoryPost").on("click", function() { alert("카테고리 저장 버튼 클릭됨"); _this.insert(); }), $("#btn-categoryUpdate").on("click", function() { alert("수정이 요청되었습니다."); _this.update(); }), $("#btn-categoryDelete").on("click", () => { alert("삭제가 요청되었습니다."); _this.delete(); }); }, insert: function() { alert("카테고리 등록이 요청되었습니다."); let data = { categoryParent: $("#categoryParent").val(), categoryName: $("#categoryName").val(), }; $.ajax({ type: "POST", url: "/ypjs/category/post", data: JSON.stringify(data), contentType: "application/json; charset=utf-8", success: function(response) { window.location.href = "/ypjs/item/get"; }, error: function(error) { window.location.href = "/ypjs/item/get"; } }); }, update: function() { let categoryId = $("#categoryId").val(); let updateData = { categoryId: $("#categoryId").val(), categoryParent: $("#categoryParent").val(), categoryName: $("#categoryName").val(), }; $.ajax({ type: "PUT", // URL 경로 조합 시, 경로와 id 값을 올바르게 분리하고 '/'를 추가합니다. url: "/ypjs/category/update/" + categoryId, data: JSON.stringify(updateData), contentType: "application/json; charset=utf-8", success: function(response) { window.location.href = "/ypjs/item/get"; }, error: function(error) { alert("에러 발생: " + JSON.stringify(error)); // 에러 발생 시 적절히 처리하도록 수정이 필요할 수 있습니다. } }); }, delete: function() { // itemId 가져오기 let categoryId = $("#categoryId").val(); $.ajax({ type: "DELETE", url: "/ypjs/category/delete/" + categoryId, success: function(response) { alert(response.data); // 성공 메시지 처리 window.location.href = "/test"; // 삭제 후 페이지 이동 }, error: function(xhr, status, error) { alert("에러 발생: " + error); } }); } }; $(document).ready(function() { categoryBoardObject.init(); });
js는 같이 수정, 등록까지
이 화면이 나온다.
카테고리 단건 조회
categoryRespository//categoryId 단건조회 public Category findOneCategory(Long categoryId) { if (categoryId == null) { throw new IllegalArgumentException("Category ID must not be null"); } Category category = em.find(Category.class, categoryId); if (category == null) { throw new IllegalArgumentException("Category not found for ID: " + categoryId); } return category; }
//(카테고리당 아이템 조회) public List<Item> findAllItems(Long categoryId, Pageable pageable) { String queryString = "select i from Item i where i.category.categoryId = :categoryId order by i.itemId desc"; TypedQuery<Item> query = em.createQuery(queryString, Item.class) .setParameter("categoryId", categoryId) .setFirstResult((int) pageable.getOffset()) .setMaxResults(pageable.getPageSize()); return query.getResultList(); }
categoryService
//categoryId단건조회 public Category findOneCategory(Long categoryId) { return categoryRepository.findOneCategory(categoryId); }
//카테고리 당 아이템 조회 public List<ItemListDto> findAllCategoryItem(Long categoryId, Pageable pageable) { List<Item> items = itemRepository.findAllItems(categoryId,pageable); List<ItemListDto> result = items.stream() .map(ItemListDto::new) .collect(Collectors.toList()); return result; }
categoryController
//category 1개 조회 @GetMapping("/ypjs/category/get/{categoryId}") public String getOneCategory (@PathVariable("categoryId") Long categoryId, Model model, @RequestParam(value = "page", defaultValue = "0") int page, @RequestParam(value = "size", defaultValue = "5") int size) { Pageable pageable = PageRequest.of(page, size); Category findCategory = categoryService.findOneCategory(categoryId); List<ItemListDto> items = itemService.findAllCategoryItem(categoryId, pageable); // CategoryOneDto category = new CategoryOneDto( findCategory, items); model.addAttribute("category", findCategory); model.addAttribute("items",items); return "category/categoryGet"; }
category/categoryGet
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" lang="en"> <head th:replace="frame/header :: head"> <title>Zay Shop - Product Listing Page</title> </head> <body> <!--header--> <header th:replace="frame/header :: header"></header> <!-- Start Content --> <div class="container py-5"> 카테고리 번호 당 아이템 리스트 </div> <!-- End Content --> <!-- jQuery --> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- JS 파일 포함 --> <script src="/js/jquery-1.11.0.min.js"></script> <script src="/js/summernote-lite.js"></script> <script src="/js/summernote-ko-KR.js"></script> <script src="/js/item/category.js"></script> <script src="/js/item/item.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote.min.js"></script> <!-- Start Contact --> <div class="container py-5"> <div class="row py-5"> <form class="col-md-9 m-auto" method="post" > <!-- 폼 요소들 --> <div class="row"> <style> .category-box { border: 1px solid #ccc; padding: 10px; margin-bottom: 10px; } .category-label { font-weight: bold; } .item-box { border: 1px solid #ccc; padding: 10px; margin-bottom: 10px; } .item-info { /* Optional: Add additional styles for item information */ } .category-label { font-weight: bold; } </style> <div class="category-box"> <div> <span class="category-label">카테고리 번호:</span> <span>:</span> <span th:text="${category.categoryId}"></span> </div> <div> <span class="category-label">카테고리 부모 번호:</span> <span>:</span> <span th:text="${category.categoryParent.categoryId}"></span> </div> <div> <span class="category-label">카테고리 이름:</span> <span>:</span> <span th:text="${category.categoryName}"></span> </div> <br> <div class="container"> <div class="row justify-content-end"> <div class="col-auto"> <input type="hidden" id="categoryId" th:value="${category.categoryId}"> <a th:href="@{/ypjs/category/update/{categoryId}(categoryId=${category.categoryId})}" class="btn btn-warning">수정하기</a> </div> <div class="col-auto"> <button type="button" id="btn-categoryDelete" class="btn btn-danger">삭제하기</button> </div> </div> </div> </div> <div th:if="${not #lists.isEmpty(items)}"> <br><br><br> <h3>아이템 목록</h3> <br> <div th:each="item : ${items}" class="item-box"> <div class="item-info"> <div> <span class="category-label">아이템 이름:</span> <span>:</span> <span th:text="${item.itemName}"></span> </div> <div> <span class="category-label">아이템 내용:</span> <span>:</span> <span th:utext="${item.itemContent}"></span> </div> <div> <span class="category-label">아이템 가격:</span> <span>:</span> <span th:text="${item.itemPrice}"></span> </div> <div> <span class="category-label">아이템 수량:</span> <span>:</span> <span th:text="${item.itemStock}"></span> </div> <!-- 필요한 다른 아이템 정보들을 추가 --> <div class="container"> <div class="row justify-content-end"> <div class="col-auto"> <a th:href="@{/ypjs/item/update/{itemId}(itemId=${item.itemId})}" class="btn btn-warning" style="padding: 2px 10px; font-size: 12px; width: 90px; height: 40px; text-align: center; display: inline-block; line-height: 40px;"> 수정하기 </a> </div> <button type="button" class="btn btn-danger btn-sm btn-delete-item" th:attr="data-itemId=${item.itemId}" style="padding: 2px 10px; font-size: 16px; width: 90px; height: 40px;"> 삭제하기 </button> </div> </div> </div> </div> </div> <!-- End Contact --> </div> </form> </div> </div> <footer th:replace="frame/footer :: footer"></footer> </body> </html>
카테고리 번호에 해당하는 모든 아이템이 나온다.
카테고리 수정
categoryRespository
//categoryId 단건조회 public Category findOneCategory(Long categoryId) { if (categoryId == null) { throw new IllegalArgumentException("Category ID must not be null"); } Category category = em.find(Category.class, categoryId); if (category == null) { throw new IllegalArgumentException("Category not found for ID: " + categoryId); } return category; }
categoryService
//categoryId단건조회 public Category findOneCategory(Long categoryId) { return categoryRepository.findOneCategory(categoryId); }
categoryController
//카테고리수정보기 @GetMapping("/ypjs/category/update/{categoryId}") public String updateCategory(@PathVariable("categoryId") Long categoryId, Model model) { Category findCategory = categoryService.findOneCategory(categoryId); CategoryUpdateDto category = new CategoryUpdateDto(findCategory.getCategoryId(), findCategory.getCategoryParent().getCategoryId(), findCategory.getCategoryName()); model.addAttribute("category", category); return "category/categoryUpdate"; } //category수정 @ResponseBody @PutMapping("ypjs/category/update/{categoryId}") public CategoryUpdateDto updateCategory(@PathVariable("categoryId") Long categoryId, @RequestBody @Valid CategoryUpdateDto categoryUpdateDto) { categoryService.updateCategory(categoryId, categoryUpdateDto); Category findCategory = categoryService.findOneCategory(categoryId); return new CategoryUpdateDto(findCategory.getCategoryId(), findCategory.getCategoryParent().getCategoryId(), findCategory.getCategoryName()); }
category/categoryUpdate
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" lang="en"> <head th:replace="frame/header :: head"> <title>Zay Shop - Product Listing Page</title> </head> <body> <!--header--> <header th:replace="frame/header :: header"></header> <!-- Start Content --> <div class="container py-5"> 카테고리 수정 </div> <!-- End Content --> <!-- jQuery --> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- JS 파일 포함 --> <script src="/js/jquery-1.11.0.min.js"></script> <script src="/js/summernote-lite.js"></script> <script src="/js/summernote-ko-KR.js"></script> <script src="/js/item/category.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote.min.js"></script> <!-- Start Contact --> <div class="container py-5"> <div class="row py-5"> <form class="col-md-9 m-auto" method="post" > <!-- 폼 요소들 --> <div class="row"> <div class="form-group mb-3"> <label for="categoryId">카테고리 번호</label> <input type="text" class="form-control mt-1" id="categoryId" name="categoryId" th:value="${category.categoryId}" placeholder="카테고리 번호"> </div> <div class="form-group mb-3"> <label for="categoryParent">카테고리 부모 번호</label> <input type="text" class="form-control mt-1" id="categoryParent" name="categoryParent" th:value="${category.categoryParent}" placeholder="카테고리 부모 번호"> </div> <div class="form-group mb-3"> <label for="categoryName">카테고리 이름</label> <input type="text" class="form-control mt-1" id="categoryName" name="categoryName" th:value="${category.categoryName}" placeholder="카테고리 이름"> </div> <!-- 글 등록 버튼 --> <div class="row"> <div class="col text-end mt-2"> <button type="button" id="btn-categoryUpdate" class="btn btn-success btn-lg px-3">수정하기</button> </div> </div> </div> </form> </div> </div> <!-- End Contact --> </div> </div> <footer th:replace="frame/footer :: footer"></footer> </body> </html>
카테고리 삭제는 컨트롤러만 보면 될 듯
//category삭제 @DeleteMapping("ypjs/category/delete/{categoryId}") public @ResponseBody ResponseDto<?> deleteCategory(@PathVariable("categoryId") Long categoryId) { categoryService.deleteCategory(categoryId); return new ResponseDto<>(HttpStatus.OK.value(), "카테고리가 삭제되었습니다."); }
리뷰 등록
reviewRepository
//상품 하나 조회 public Item findOne(Long ItemId) { return em.find(Item.class, ItemId); }
//상품 하나 조회 public Item findOne(Long ItemId) { return em.find(Item.class, ItemId); }
public Member findOne(Long memberId) { return em.find(Member.class, memberId); }
reviewService
//단건상품 조회 public Item findOneItem(Long ItemId) { return itemRepository.findOne(ItemId); }
//리뷰등록 @Transactional public ItemReview saveItemReview(ItemReviewDto itemReviewDto, Long memberId) { Item item = itemRepository.findOne(itemReviewDto.getItemId()); Member member = memberRepository.findOne(memberId); ItemReview itemReview = new ItemReview( item, member, itemReviewDto.getItemScore(), itemReviewDto.getItemReviewName(), itemReviewDto.getItemReviewContent() ); //리뷰 저장 itemReviewRepository.saveReview(itemReview); // 새로운 리뷰가 추가된 후 아이템의 리뷰 리스트를 업데이트 item.getItemReviews().add(itemReview); //평점 업데이트 item.updateItemRatings(); itemRepository.saveItem(item); return itemReview; }
reviewController
//리뷰등록 화면 @GetMapping("/ypjs/itemReview/post/{itemId}") public String insert(@PathVariable("itemId") Long itemId, Model model) { Item findItem = itemService.findOneItem(itemId); model.addAttribute("item", findItem); return "itemreview/itemReviewPost";} //리뷰등록 @ResponseBody @PostMapping("/ypjs/itemReview/post/{itemId}") public ItemReviewDto saveItemReview(@PathVariable("itemId") Long itemId, HttpSession session, Model model, @RequestBody @Valid ItemReviewDto requestDto) { //멤버정보 찾기 LoginDto.ResponseLogin responseLogin = (LoginDto.ResponseLogin) session.getAttribute("member"); System.out.println("@@@@@@@@@@@@@@@@@@@@@@@"+itemId); Item findItem = itemService.findOneItem(itemId); //ItemReview itemReview = itemReviewService.saveItemReview(requestDto, responseLogin.getMemberId()); ItemReview itemReview = itemReviewService.saveItemReview(requestDto, 1L); model.addAttribute("item", findItem); return new ItemReviewDto(itemReview.getItem().getItemId(), itemReview.getItemScore(), itemReview.getItemReviewName(), itemReview.getItemReviewContent()); }
itemreview/itemReviewPost
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" lang="en"> <head th:replace="frame/header :: head"> <title>Zay Shop - Product Listing Page</title> </head> <body> <!--header--> <header th:replace="frame/header :: header"></header> <!-- Start Content --> <div class="container py-5"> 리뷰등록 </div> <!-- End Content --> <!-- jQuery --> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Summernote 스타일 및 스크립트 --> <link href="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote-bs4.min.css" rel="stylesheet"> <script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote-bs4.min.js"></script> <!-- JS 파일 포함 --> <script src="/js/jquery-1.11.0.min.js"></script> <script src="/js/summernote-lite.js"></script> <script src="/js/summernote-ko-KR.js"></script> <script src="/js/item/itemReview.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote.min.js"></script> <!-- Start Contact --> <div class="container py-5"> <div class="row py-5"> <form class="col-md-9 m-auto" method="post"> <!-- 폼 요소들 --> <div class="row"> <input type="hidden" id="itemId" th:value="${item.itemId}" > <!-- Thymeleaf의 value 속성 사용 --> <input type="hidden" id="memberId" value="1"> <!-- memberId 값 받아와야 됨 --> <div class="form-group mb-3"> <label for="itemReviewName">제목</label> <input type="text" class="form-control mt-1" id="itemReviewName" name="itemReviewName" placeholder="제목"> </div> <div class="form-group mb-3"> <label for="itemScore">점수</label> <input type="text" class="form-control mt-1" id="itemScore" name="itemScore" placeholder="점수"> </div> <div class="mb-3"> <label for="itemReviewContent">내용</label> <textarea class="form-control" id="itemReviewContent" name="itemReviewContent" rows="10"></textarea> </div> <!-- Summernote 초기화 스크립트 --> <script th:inline="javascript"> $(document).ready(function() { $("#itemReviewContent").summernote({ height: 600, // 높이 설정 placeholder: '내용을 입력하세요...', // 플레이스홀더 설정 callbacks: { onChange: function(contents, $editable) { // 내용이 변경될 때 처리할 로직 추가 가능 } } }); }); </script> <!-- 글 등록 버튼 --> <div class="row"> <div class="col text-end mt-2"> <button type="button" id="btn-itemReviewPost" class="btn btn-success btn-lg px-3">리뷰등록</button> </div> </div> </div> </form> </div> </div> <!-- End Contact --> <footer th:replace="frame/footer :: footer"></footer> </body> </html>
화면은 있는데 링크연결 아직 안해놓음
리뷰 보기
reviewRepository
//페치조인 (아이템 당 리뷰 조회) public List<ItemReview> findAllItemReview(Long itemId) { return em.createQuery( "select ir from ItemReview ir" + " join fetch ir.item i WHERE i.itemId = :itemId", ItemReview.class) .setParameter("itemId", itemId) .getResultList(); }
reviewService
//아이템 당 리뷰조회 public List<ItemReviewListDto> findAllItemReview(Long itemId) { //List<ItemReview> reviews = itemReviewRepository.findAllItemReview(itemId); List<ItemReview> reviews = itemReviewRepository.findAllItemReview(itemId); List<ItemReviewListDto> result = reviews.stream() .map(ItemReviewListDto::new) .collect(Collectors.toList()); return result; }
reviewController
//아이템 당 리뷰조회 @GetMapping("/ypjs/itemReview/get/{itemId}") public String getAllItemReview(@PathVariable("itemId") Long itemId, Model model) { itemService.findOneItem(itemId); List<ItemReviewListDto> itemReviews = itemReviewService.findAllItemReview(itemId); model.addAttribute("itemReviews", itemReviews); return "itemreview/itemReviewGet"; }
itemrevirew/itemReviewGet
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" lang="en"> <head th:replace="frame/header :: head"> <title>Zay Shop - Product Listing Page</title> </head> <body> <!--header--> <header th:replace="frame/header :: header"></header> <!-- Start Content --> <div class="container py-5"> 아이템 리뷰 </div> <!-- End Content --> <!-- jQuery --> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- JS 파일 포함 --> <script src="/js/jquery-1.11.0.min.js"></script> <script src="/js/summernote-lite.js"></script> <script src="/js/summernote-ko-KR.js"></script> <script src="/js/item/category.js"></script> <script src="/js/item/item.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote.min.js"></script> <!-- Start Contact --> <div class="container py-5"> <div class="row py-5"> <form class="col-md-9 m-auto" method="post" > <!-- 폼 요소들 --> <div class="row"> <style> .category-box { border: 1px solid #ccc; padding: 10px; margin-bottom: 10px; } .category-label { font-weight: bold; } .item-box { border: 1px solid #ccc; padding: 10px; margin-bottom: 10px; } .item-info { /* Optional: Add additional styles for item information */ } .category-label { font-weight: bold; } </style> <div th:if="${not #lists.isEmpty(itemReviews)}"> <br><br><br> <h3>리뷰 목록</h3> <br> <div th:each="itemReview : ${itemReviews}" class="item-box"> <div class="item-info"> <div> <span class="category-label">아이템 이름:</span> <span>:</span> <span th:text="${itemReview.itemReviewName}"></span> </div> <div> <span class="category-label">별점:</span> <span>:</span> <span th:text="${itemReview.itemScore}"></span> </div> <div> <span class="category-label">아이템 내용:</span> <span>:</span> <span th:utext="${itemReview.itemReviewContent}"></span> </div> <!-- 수정 및 삭제 버튼 --> <!-- <div class="container">--> <!-- <div class="row justify-content-end">--> <!-- <div class="col-auto">--> <!-- <a th:href="@{/ypjs/itemReview/update/{itemId}(itemId=${item.itemId})}" class="btn btn-warning">수정하기</a>--> <!-- </div>--> <!-- <div class="col-auto">--> <!-- <button type="button"--> <!-- class="btn btn-danger btn-sm btn-delete-item"--> <!-- th:attr="data-itemReviewId=${itemReview.itemReview}"--> <!-- style="padding: 2px 10px; font-size: 16px; width: 90px; height: 40px;">--> <!-- 삭제하기--> <!-- </button>--> </div> </div> </div> </div> </div> </div> </div> </form> </div> </div> <!-- End Contact --> </div> </form> </div> </div> <footer th:replace="frame/footer :: footer"></footer> </body> </html>
수정, 삭제 버튼도 안먹고 리뷰보기는 아직 미완성
베트남 여행 일정으로 나머지는 여행갔다와서 할 예정
'쇼핑몰 프로젝트' 카테고리의 다른 글
쇼핑몰 프로젝트 --별 기능(화면구현) (0) 2024.06.26 쇼핑몰 프로젝트 --리뷰 수정, 삭제, 아이템 검색, 정렬(화면구현) (0) 2024.06.26 쇼핑몰 프로젝트 --아이템조회, 삭제, 아이템전체리스트조회 (화면구현) (0) 2024.06.19 쇼핑몰 프로젝트 --아이템 등록, 수정 (화면구현) (0) 2024.06.17 쇼핑몰 프로젝트 --아이템 리뷰 등록, 조회, 수정, 삭제(api) (0) 2024.06.15