쇼핑몰 프로젝트
쇼핑몰 프로젝트 --리뷰 수정, 삭제, 아이템 검색, 정렬(화면구현)
개발공부중인지니
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 별점 높은 순