Skip to content

Commit

Permalink
Merge pull request #50 from kookmin-sw/리뷰_작성하기
Browse files Browse the repository at this point in the history
리뷰 작성하기
  • Loading branch information
moonwonki authored May 10, 2024
2 parents 54bf4db + 7173a4e commit f728d4c
Show file tree
Hide file tree
Showing 10 changed files with 418 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/login", "/register", "/css/**", "/images/**", "/js/**", "/order/**", "/guest/**")
.requestMatchers("/login", "/register", "/css/**", "/images/**", "/js/**", "/order/**", "/guest/**", "/review/**")
.permitAll()
.anyRequest().authenticated()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ public String getWholeMenuByOwner(Model model){
@GetMapping("/admin/item/detail/{itemId}")
public String getMenuByOwner(@PathVariable("itemId") Long itemId, Model model) {
model.addAttribute("itemInfo", itemService.getItemInfoById(itemId));
model.addAttribute("reviewList", reviewService.getReviewsOfItem(itemId));
return "item/itemDetail";
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.example.WebOrder.controller;

import com.example.WebOrder.dto.OrderItemDto;
import com.example.WebOrder.service.CategoryService;
import com.example.WebOrder.service.ItemService;
import com.example.WebOrder.service.OrderService;
import com.example.WebOrder.service.ReviewService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
Expand All @@ -18,11 +19,13 @@ public class OrderController {
private final ItemService itemService;
private final OrderService orderService;
private final CategoryService categoryService;
private final ReviewService reviewService;

public OrderController(ItemService itemService, OrderService orderService, CategoryService categoryService) {
public OrderController(ItemService itemService, OrderService orderService, CategoryService categoryService, ReviewService reviewService) {
this.itemService = itemService;
this.orderService = orderService;
this.categoryService = categoryService;
this.reviewService = reviewService;
}


Expand All @@ -38,9 +41,10 @@ public String getShopPageByGuest(@PathVariable Long userId, @PathVariable Long s
//주문하기
@ResponseBody
@PostMapping("/order/{userId}/{seatId}")
public Boolean order(@PathVariable Long userId, @PathVariable Long seatId, @RequestBody String json) throws JsonProcessingException {
orderService.order(seatId, json);
public Boolean order(@PathVariable Long userId, @PathVariable Long seatId, @RequestBody String json, HttpServletRequest request, HttpServletResponse response) throws JsonProcessingException {
Long orderId = orderService.order(seatId, json);
log.info("주문 성공");
response.addCookie(reviewService.getCookieOfOrderInfo(request, orderId));
return true;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.example.WebOrder.controller;

import com.example.WebOrder.dto.ReviewDto;
import com.example.WebOrder.service.ItemService;
import com.example.WebOrder.service.ReviewService;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Controller
@Slf4j
public class ReviewController {

private final ReviewService reviewService;
private final ItemService itemService;
public ReviewController(ReviewService reviewService, ItemService itemService) {
this.reviewService = reviewService;
this.itemService = itemService;
}


// fetch를 통해 item의 review를 가져오는 컨트롤러
// requestParam으로 page가 있어야 한다.
@ResponseBody
@GetMapping("/review/get/{itemId}")
public List<ReviewDto> getReviewOfItem( @PathVariable("itemId") Long itemId, @RequestParam(name="page", defaultValue = "1") Integer page){
Pageable pageable = PageRequest.of(page - 1, 10, Sort.Direction.DESC, "id");

List<ReviewDto> reviewsOfItem = reviewService.getReviewsOfItem(itemId, pageable);

return reviewsOfItem;
}

// 쿠키를 분석해서 주문한 메뉴의 리스트를 보여주는 페이지
@GetMapping("/review/menu/{userId}")
public String getReviewMenuPage(HttpServletRequest request, Model model, @PathVariable("userId") Long userId){
String orderItemsIdString = new String();

for (Cookie cookie : request.getCookies()){
if (cookie.getName().equals("orderItemIds")){
orderItemsIdString = cookie.getValue();
}
}
log.info("orderItemIds : " + orderItemsIdString);

model.addAttribute("itemList", reviewService.getItemDtoListFromCookieString(userId, orderItemsIdString));
return "review/reviewMenu";
}

// 리뷰 적는 form을 주는 페이지
@GetMapping("/review/write/{userId}/{itemId}")
public String getReviewWriteForm(@PathVariable("userId") Long userId, @PathVariable("itemId") Long itemId,@RequestParam(name="page", defaultValue = "1") Integer page, Model model){
model.addAttribute("item", itemService.getItemInfoById(itemId));
model.addAttribute("totalPage", reviewService.getNumberOfPages(itemId));
model.addAttribute("reviews", reviewService.getReviewsOfItem(itemId, PageRequest.of(page - 1, 10, Sort.Direction.DESC, "id")));
return "review/reviewWrite";
}



// 리뷰 적는 form을 제출
@PostMapping("/review/write/{userId}/{itemId}")
public String writeReview(@PathVariable("userId") Long userId, @PathVariable("itemId") Long itemId, ReviewDto reviewDto){
reviewService.createReview(reviewDto);
return "redirect:/review/write/" + userId + "/" + itemId;
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.example.WebOrder.repository;

import com.example.WebOrder.entity.Item;
import com.example.WebOrder.entity.Review;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface ReviewRepository extends JpaRepository<Review, Long> {
List<Review> findAllByItemId(Long itemId);
Page<Review> findByItemId(Long itemId, Pageable pageable);

}
87 changes: 77 additions & 10 deletions src/main/java/com/example/WebOrder/service/ReviewService.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,36 @@
package com.example.WebOrder.service;

import com.example.WebOrder.dto.ItemDto;
import com.example.WebOrder.dto.OrderItemDto;
import com.example.WebOrder.dto.ReviewDto;
import com.example.WebOrder.entity.Item;
import com.example.WebOrder.entity.Order;
import com.example.WebOrder.entity.OrderItem;
import com.example.WebOrder.entity.Review;
import com.example.WebOrder.repository.ItemRepository;
import com.example.WebOrder.repository.OrderRepository;
import com.example.WebOrder.repository.ReviewRepository;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.Dictionary;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ReviewService {

private final ItemRepository itemRepository;
private final ReviewRepository reviewRepository;
private final OrderRepository orderRepository;

public ReviewService(ItemRepository itemRepository, ReviewRepository reviewRepository) {
public ReviewService(ItemRepository itemRepository, ReviewRepository reviewRepository, OrderRepository orderRepository) {
this.itemRepository = itemRepository;
this.reviewRepository = reviewRepository;
this.orderRepository = orderRepository;
}

public Long createReview(ReviewDto dto){
Expand Down Expand Up @@ -48,14 +59,70 @@ public Long createReview(ReviewDto dto){
return returnValue;
}

public List<ReviewDto> getReviewsOfItem(Long itemId){
Optional<Item> optionalItem = itemRepository.findById(itemId);
if (optionalItem.isEmpty()) throw new RuntimeException("엔티티 없음");
Item item = optionalItem.get();

List<Review> reviews = item.getReviews();
public List<ReviewDto> getReviewsOfItem(Long itemId, Pageable pageable){
List<Review> reviews = reviewRepository.findByItemId(itemId, pageable).getContent();
log.info(reviews.toString());
return reviews.stream().map(ReviewDto::fromEntity).toList();
}


// 주문할 때, 주문 내역에 해당하는 item id를 쿠키로 생성하는 코드.
// 리뷰 서비스에 활용 됨.
public Cookie getCookieOfOrderInfo(HttpServletRequest request, Long orderId){
Optional<Order> optionalOrder = orderRepository.findById(orderId);
if (optionalOrder.isEmpty()) throw new RuntimeException("엔티티없음");
Order order = optionalOrder.get();


// request에 이미 해당하는 cookie가 있다면 (이전에 주문한 내역이 있다면), cookie를 이어서 작성하도록 값을 복사한다.
Cookie cookie = new Cookie("orderItemIds", "");
for (Cookie requestCookie : request.getCookies()){
if (requestCookie.getName().equals("orderItemIds")){
cookie.setValue(requestCookie.getValue());
log.info("현재 가져온 쿠키 value : " + requestCookie.getName() + "/" + requestCookie.getValue());
}
}


StringBuilder sb = new StringBuilder();
for (OrderItemDto itemDto : order.getOrderItems()){
sb.append("-");
sb.append(itemDto.getItemId().toString());
}

cookie.setValue(cookie.getValue() + sb.toString());
cookie.setMaxAge(7200);
cookie.setPath("/");

return cookie;
}

// 리뷰를 작성하고자 리뷰 메뉴 페이지에 접근할 때, 주문 내역에 남아있는 메뉴들을 parsing해서 dto 리스트로 가져오는 메소드
public List<ItemDto> getItemDtoListFromCookieString(Long userId, String cookieString){
String[] splitCookieString = cookieString.split("-");
List<Long> itemIdList = Arrays.stream(splitCookieString)
.map(String::trim) // 각 요소의 앞뒤 공백 제거
.filter(s -> !s.isEmpty()) // 빈 문자열 제거
.map(Long::parseLong) // 문자열을 정수로 변환
.distinct() // 중복 제거
.toList(); // 리스트로 수집

List<ItemDto> itemDtoList = new ArrayList<>();

for (Long itemId : itemIdList){
Optional<Item> optionalItem = itemRepository.findById(itemId);
if (optionalItem.isEmpty()) throw new RuntimeException("엔티티없음");

itemDtoList.add(ItemDto.fromEntity(optionalItem.get()));
}

return itemDtoList;


}


public Integer getNumberOfPages(Long itemId) {
return reviewRepository.findByItemId(itemId, Pageable.ofSize(10)).getTotalPages();
}
}
2 changes: 1 addition & 1 deletion src/main/resources/templates/guest/guestWelcome.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<!-- 주문하기 버튼 -->
<a th:href="@{'/guest/' + ${userId} + '/' + ${seatId} + '/checkEntrance'}" class="btn btn-primary btn-lg btn-custom">주문하기</a>
<!-- 리뷰 작성 버튼 -->
<a href="/writeReview" class="btn btn-success btn-lg btn-custom">리뷰 작성</a>
<a th:href="@{'/review/menu/' + ${userId}}" class="btn btn-success btn-lg btn-custom">리뷰 작성</a>
</div>
</div>
</div>
Expand Down
83 changes: 82 additions & 1 deletion src/main/resources/templates/order/orderForm.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" th:href="@{/css/orderForm.css}">
<style>
.review-card{
display: flex; /* Flexbox 사용 */
flex-direction: row; /* 요소들을 가로로 정렬 (기본값이므로 생략 가능) */
}
.fixed-star {
color: gray;
cursor: pointer;
}

.fixed-star.active {
color: orange;
}
</style>
<title>Title</title>
</head>
<body class="">
Expand Down Expand Up @@ -133,14 +147,72 @@ <h1 class="heading">장바구니</h1>
<script th:inline="javascript">
let items = [[${items}]];
const details = document.querySelector(".item-details");
function showItemDetail(element) {
async function showItemDetail(element) {
let itemId = parseInt(element.getAttribute("itemId"));
let item = findItemById(itemId);
wrapper.classList.toggle('show-item');
details.querySelector(".image").src = item.itemImageUrl;
details.querySelector(".itemName").innerHTML = item.name;
details.querySelector(".description").innerHTML = item.description;
details.querySelector(".price").innerHTML = item.price + '원';
await getReview(itemId);
}

async function getReview(itemId){
const details = document.querySelector(".reviews");
details.innerHTML = '';
await fetch('/review/get/'+ itemId.toString(), {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include'
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json(); // JSON 형식으로 파싱된 응답 반환
})
.then(reviewList => {
// 받아온 ReviewDto 목록(reviewList)을 순회하면서 각 객체의 rate와 comment 출력
reviewList.forEach(reviewDto => {
let reviewCard = document.createElement('div');
reviewCard.classList.add('review-card');
const rate = reviewDto.rate;
const comment = reviewDto.comment;
// 꽉찬 별 채우기
let activeStarSpan = document.createElement('span');
activeStarSpan.classList.add('fixed-star', 'active');

// rate 값에 따라 별(★) 추가
for (let i = 1; i <= rate; i++) {
const star = document.createElement('span');
star.textContent = '★'; // 별(★) 텍스트 설정
activeStarSpan.appendChild(star); // 생성된 별(★) 요소를 span 요소에 추가
}
// reviewCard 요소에 생성된 span 요소 추가
reviewCard.appendChild(activeStarSpan);
// 빈 별 채우기
let starSpan = document.createElement('span');
starSpan.classList.add('fixed-star');

// rate 값에 따라 별(★) 추가
for (let i = 1; i <= 5-rate; i++) {
const star = document.createElement('span');
star.textContent = '★'; // 별(★) 텍스트 설정
starSpan.appendChild(star); // 생성된 별(★) 요소를 span 요소에 추가
}
// reviewCard 요소에 생성된 span 요소 추가
reviewCard.appendChild(starSpan);

// comment
reviewCard.innerHTML = reviewCard.innerHTML + '<p class="review-comment"> ' + comment + '</p>';
details.appendChild(reviewCard);
})


});
}

function findItemById(id) {
Expand All @@ -159,12 +231,21 @@ <h1 class="heading">장바구니</h1>
});
alert(response.status);
if (await response.text() === 'true') {
const cookies = response.headers.get('Set-Cookie');

if (cookies){
document.cookie = cookies;
alert('브라우저에 쿠키 적용 완료' + document.cookie);
}

window.location.replace("/order/success");
}
else {
alert('주문 오류');
}
}


</script>
</body>
</html>
Loading

0 comments on commit f728d4c

Please sign in to comment.