-
쇼핑몰 프로젝트 --리뷰 수정, 삭제, 아이템 검색, 정렬(화면구현)쇼핑몰 프로젝트 2024. 6. 26. 02:42
먼저 리뷰를 수정, 삭제 할거다
레파지토리
public ItemReview findOneReview(Long itemReviewId) { return em.find(ItemReview.class, itemReviewId); }
서비스
public ItemReview findOneItemReview(Long itemReviewId) { return itemReviewRepository.findOneReview(itemReviewId); }
@Transactional public void updateItemReview(Long itemReviewId, ItemReviewDto itemReviewDto) { ItemReview itemReview = itemReviewRepository.findOneReview(itemReviewId); if (itemReview == null) { throw new IllegalArgumentException("ItemReview not found with id: " + itemReviewId); } Long iRId = itemReview.changeItemReview( itemReviewDto.getItemScore(), itemReviewDto.getItemReviewName(), itemReviewDto.getItemReviewContent() ); //평점 업데이트 itemReview.getItem().updateItemRatings(); }
디티오
package ypjs.project.dto.itemdto; import lombok.Data; import lombok.Getter; import java.time.LocalDateTime; @Data public class ItemReviewDto { private Long itemId; private Long itemReviewId; private int itemScore; private String itemReviewName; private String itemReviewContent; public ItemReviewDto() {} public ItemReviewDto(Long itemId, Long itemReviewId, int itemScore, String itemReviewName, String itemReviewContent) { this.itemId = itemId; this.itemReviewId = itemReviewId; this.itemScore = itemScore; this.itemReviewName = itemReviewName; this.itemReviewContent = itemReviewContent; } }
컨트롤러
// 수정보기 @GetMapping("/ypjs/itemReview/update/{itemReviewId}") public String updateItemReview(@PathVariable("itemReviewId") Long itemReviewId, Model model) { ItemReview findItemReview = itemReviewService.findOneItemReview(itemReviewId); ItemReviewDto itemReview = new ItemReviewDto( findItemReview.getItem().getItemId(), findItemReview.getItemReviewId(), findItemReview.getItemScore(), findItemReview.getItemReviewName(), findItemReview.getItemReviewContent() ); model.addAttribute("itemReview", itemReview); // 반환할 뷰 이름 (템플릿 파일 경로, 예: templates/itemReview/update.html) return "itemReview/itemReviewUpdate"; } //수정등록 @ResponseBody @PutMapping("/ypjs/itemReview/update/{itemReviewId}") public ResponseEntity updateItemReview(@PathVariable(name ="itemReviewId") Long itemReviewId, @RequestBody @Valid ItemReviewDto itemReviewDto, HttpSession session) { //멤버정보 찾기 LoginDto.ResponseLogin responseLogin = (LoginDto.ResponseLogin) session.getAttribute("member"); itemReviewService.updateItemReview(itemReviewId, itemReviewDto); ItemReview findItemReview = itemReviewService.findOneItemReview(itemReviewId); return ResponseEntity.ok().body(findItemReview.getItem().getItemId()); }
응답 방식은 나머지 컨트롤러도 다 저렇게 바꿨다.
타임리프에 버튼 추가
itemReview/itemReviewGet
<input type="hidden" id="itemId" th:value="${itemReview.itemId}"> <!-- 수정 및 삭제 버튼 --> <div class="container"> <div class="row justify-content-end"> <div class="col-auto"> <a th:href="@{/ypjs/itemReview/update/{itemReviewId}(itemReviewId=${itemReview.itemReviewId})}" class="btn btn-warning">수정하기</a> </div> <div class="col-auto"> <button type="button" class="btn btn-danger btn-sm btn-delete-itemReview" th:data-itemReviewId="${itemReview.itemReviewId}" style="padding: 2px 10px; font-size: 16px; width: 90px; height: 40px;"> 삭제하기 </button> </div> </div> </div> </div> </div> </div>
히든으로 아이템아이디 값 받아와야 삭제 후 원하는 화면(아이템 리뷰 리스트)으로 이동 가능
수정 화면
<!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="put"> <!-- 폼 요소들 --> <div class="row"> <input type="hidden" id="itemReviewId" th:value="${itemReview.itemReviewId}"> <div class="form-group mb-3"> <label for="itemReviewName">제목</label> <input type="text" class="form-control mt-1" id="itemReviewName" name="itemReviewName" th:value="${itemReview.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" th:value="${itemReview.itemScore}" placeholder="점수"> </div> <div class="mb-3"> <label for="itemReviewContent">내용</label> <textarea class="form-control" id="itemReviewContent" name="itemReviewContent" th:text="${itemReview.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-itemReviewUpdate" 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>
js
let itemBoardObject = { init: function() { let _this = this; $("#btn-itemReviewPost").on("click", function() { alert("리뷰등록 버튼이 클릭 됨"); _this.insert(); }), $("#btn-itemReviewUpdate").on("click", function() { alert("수정이 요청되었습니다."); _this.update(); }), $(document).on("click", ".btn-delete-itemReview", function() { // 클릭된 버튼의 데이터 속성에서 itemReviewId를 가져옴 let itemReviewId = $(this).data("itemreviewid"); alert("삭제가 요청되었습니다."); // 아이템 리뷰 삭제 함수 호출 _this.deleteItemReview(itemReviewId); }); }, insert: function() { alert("리뷰 등록이 요청되었습니다."); let itemId = $("#itemId").val(); // URL에 사용할 itemId를 가져옴 let data = { itemId: itemId, // itemId를 데이터에 포함 memberId: $("#memberId").val(), // 멤버 ID 추가 itemReviewName: $("#itemReviewName").val(), itemScore: $("#itemScore").val(), itemReviewContent: $("#itemReviewContent").val(), }; $.ajax({ type: "POST", url: "/ypjs/itemReview/post/" + itemId, // URL에 itemId를 추가 data: JSON.stringify(data), contentType: "application/json; charset=utf-8", success: function(response) { alert("리뷰가 성공적으로 등록되었습니다."); window.location.href = "/ypjs/item/get/" + itemId; // 성공 후 리디렉션 }, error: function(error) { alert("에러 발생: " + JSON.stringify(error)); } }); }, update: function() { let itemReviewId = $("#itemReviewId").val(); let updateData = { itemReviewName: $("#itemReviewName").val(), itemScore: $("#itemScore").val(), itemReviewContent: $("#itemReviewContent").val(), }; $.ajax({ type: "PUT", url: "/ypjs/itemReview/update/" + itemReviewId, data: JSON.stringify(updateData), contentType: "application/json; charset=utf-8", success: function(response) { window.location.href = "/ypjs/itemReview/get/" + response ; }, error: function(error) { alert("에러 발생: " + JSON.stringify(error)); // 에러 발생 시 적절히 처리하도록 수정이 필요할 수 있습니다. } }); }, deleteItemReview: function(itemReviewId) { let itemId = $("#itemId").val(); $.ajax({ type: "DELETE", url: "/ypjs/itemReview/delete/" + itemReviewId, success: function(response) { alert("리뷰가 성공적으로 삭제되었습니다."); window.location.href = "/ypjs/itemReview/get/" + itemId; }, error: function(xhr, status, error) { alert("에러 발생: " + error); } }); } }; $(document).ready(function() { itemBoardObject.init(); });
등록 ,수정, 삭제 같이
삭제
레파지토리
//리뷰 삭제 public void deleteItemReview(Long itemReviewId) { ItemReview findItemReivew = em.find(ItemReview.class, itemReviewId); em.remove(findItemReivew); }
서비스
// 리뷰 삭제 @Transactional public void deleteItemReview(Long itemReviewId) { ItemReview itemReview = findOneItemReview(itemReviewId); Item item = itemReview.getItem(); itemReviewRepository.deleteItemReview(itemReviewId); item.removeItemReview(itemReview); item.updateItemRatings(); }
컨트롤러
//삭제 @DeleteMapping("/ypjs/itemReview/delete/{itemReviewId}") public ResponseEntity deleteItemReview(@PathVariable("itemReviewId") Long itemReviewId){ itemReviewService.deleteItemReview(itemReviewId); return ResponseEntity.ok().build(); }
검색, 정렬
레파지토리
//카테고리당 아이템리스트 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 "; // 기본 order by 절을 먼저 추가 switch (sortBy) { case "itemRatings": queryString += "i.itemRatings desc, i.itemId desc"; // itemRatings로 정렬, 동일한 rating이면 itemId로 정렬 break; case "likeCount": queryString += "i.likeCount desc, i.itemId desc"; // likeCount로 정렬, 동일한 likeCount이면 itemId로 정렬 break; case "itemId": default: queryString += "i.itemId desc"; // 기본적으로 itemId로 정렬 break; } 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(); } //아이템 전체리스트 public List<Item> findAllItem(String keyword, Pageable pageable, String sortBy) { // 기본 쿼리 String queryString = "select i from Item i"; // 검색 조건 추가 boolean hasKeyword = (keyword != null && !keyword.isEmpty()); if (hasKeyword) { queryString += " where i.itemName like :keyword"; } // 정렬 조건 queryString += " order by "; switch (sortBy) { case "itemRatings": queryString += "i.itemRatings desc, i.itemId desc"; break; case "likeCount": queryString += "i.likeCount desc, i.itemId desc"; break; case "itemId": default: queryString += "i.itemId desc"; break; } TypedQuery<Item> query = em.createQuery(queryString, Item.class) .setFirstResult((int) pageable.getOffset()) .setMaxResults(pageable.getPageSize()); // 검색 키워드 파라미터 설정 if (hasKeyword) { query.setParameter("keyword", "%" + keyword + "%"); } return query.getResultList(); }
if문으로 했을 때는 정렬이 안됐는데 switch로 바꾸니까 정렬 됨
서비스
//카테고리당 아이템 조회(정렬,검색,페이징) 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; } //아이템 아이디 전체 조회 public List<ItemListDto> findAllItem(String keyword, Pageable pageable, String sortBy) { List<Item> items = itemRepository.findAllItem(keyword, pageable, sortBy); List<ItemListDto> result = items.stream() .map(ItemListDto::new) .collect(Collectors.toList()); return result; }
컨트롤러
//카테고리당 아이템 조회(정렬,검색,페이징(페이징받아서 페이징)) @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); Category category = categoryService.findOneCategory(categoryId); List<ItemListDto> items = itemService.finaAllItemPagingSortBy(categoryId, keyword, pageable, sortBy); model.addAttribute("items",items); model.addAttribute("category", category); model.addAttribute("sortBy", sortBy); // 정렬 옵션을 다시 모델에 추가 model.addAttribute("keyword", keyword); //검색조건 유지 return "item/itemCategoryList"; } //아이템 전체 조회 @GetMapping("/ypjs/item/get") public String getAllItem( @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); List<ItemListDto> items = itemService.findAllItem(keyword, pageable, sortBy); model.addAttribute("items", items); model.addAttribute("sortBy", sortBy); // 정렬 옵션을 다시 모델에 추가 model.addAttribute("keyword", keyword); //검색조건 유지 return "item/itemList"; }
타임리프
item/itemList
<div class="col-lg-6"> <!-- 검색 폼 및 정렬 폼 통합 --> <form th:action="@{/ypjs/item/get}" method="get" class="input-group"> <input type="text" id="keyword" name="keyword" class="form-control" placeholder="제목으로 검색하기" th:value="${keyword}"> <div class="input-group-append"> <button type="submit" class="btn btn-link text-dark"> <i class="fa fa-search"></i> </button> </div> <div class="col-auto"> <select class="form-control" name="sortBy" id="sortBy" onchange="this.form.submit()"> <option value="itemId" th:selected="${sortBy == 'itemId'}">최신순</option> <option value="itemRatings" th:selected="${sortBy == 'itemRatings'}">별점 높은 순</option> <option value="likeCount" th:selected="${sortBy == 'likeCount'}">찜많은순</option> </select> </div> </form> </div>
item/itemCategoryList
<div class="col-lg-6"> <!-- 검색 폼 및 정렬 폼 통합 --> <form th:action="@{/ypjs/categoryItem/get/{categoryId}(categoryId=${category.categoryId})}" method="get" class="input-group"> <input type="text" id="keyword" name="keyword" class="form-control" placeholder="제목으로 검색하기" th:value="${keyword}"> <div class="input-group-append"> <button type="submit" class="btn btn-link text-dark"> <i class="fa fa-search"></i> </button> </div> <div class="col-auto"> <select class="form-control" name="sortBy" id="sortBy" onchange="this.form.submit()"> <option value="itemId" th:selected="${sortBy == 'itemId'}">최신순</option> <option value="itemRatings" th:selected="${sortBy == 'itemRatings'}">별점 높은 순</option> <option value="likeCount" th:selected="${sortBy == 'likeCount'}">찜많은순</option> </select> </div> </form> </div>
추가
모든 아이템 별점 높은 순
카테고리 4번에 제목 2 별점 높은 순
'쇼핑몰 프로젝트' 카테고리의 다른 글
쇼핑몰 프로젝트 --페이지네이션, 유효성검사, 리뷰 정렬(화면구현) (0) 2024.06.28 쇼핑몰 프로젝트 --별 기능(화면구현) (0) 2024.06.26 쇼핑몰 프로젝트 -- 카테고리, 리뷰(화면구현) (0) 2024.06.20 쇼핑몰 프로젝트 --아이템조회, 삭제, 아이템전체리스트조회 (화면구현) (0) 2024.06.19 쇼핑몰 프로젝트 --아이템 등록, 수정 (화면구현) (0) 2024.06.17