Back-End/Spring

[Spring] AJAX를 이용한 쇼핑몰 좋아요 구현 소스코드

09009 2023. 6. 15. 10:14

RestCustomerController

package com.yyi.shop.customer.controller;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpSession;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.yyi.shop.dto.CustomerDto;

@RestController
@RequestMapping("/customer/*")
public class RestCustomerController {
	
	// 로그인이 되어있는지 확인
	@RequestMapping("getCustomerId")
	public Map<String, Object> getCustomerId(HttpSession session) {
		
		Map<String, Object> map = new HashMap<>();
		
		CustomerDto sessionUser = (CustomerDto) session.getAttribute("sessionUser");
		
		if (sessionUser == null) {
			map.put("result", "fail");	
			map.put("reason", "로그인이 되어있지 않습니다.");
		} else {
			map.put("result", "success");
			map.put("id", sessionUser.getId());		
		}
		
		return map;
	}

}

 

ProductSqlMapper.xml

	<!-- 상품 좋아요 클릭 -->
	<insert id="likeProduct">
		INSERT INTO product_likes VALUES(
			likes_seq.nextval,
			#{product_id},
			#{customer_id},
			SYSDATE
		)	
	</insert>
	
	<!-- 상품 좋아요 취소 -->
	<delete id="unlikeProduct">
		DELETE FROM product_likes
			WHERE product_id = #{product_id} AND
				  customer_id = #{customer_id}
	</delete>
	
	<!-- 고객 당 상품 좋아요 개수 확인 -->
	<select id="checkLikeProductByCustomer" resultType="int">
		SELECT COUNT(*) 
			FROM 
				product_likes
			WHERE 
				product_id = #{product_id} AND
				customer_id = #{customer_id}
	</select>	
	
	
	<!--  상품 당 좋아요 개수 -->
	<select id="countLikeProductId" resultType="int">
		SELECT COUNT(*) 
		FROM product_likes
		WHERE product_id = #{product_id}
	</select>

ProductSqlMapper

	// 고객: 상품 좋아요 클릭
	public void likeProduct(ProductLikesDto productLikesDto);
	
	// 상품 좋아요 취소
	public void unlikeProduct(ProductLikesDto productLikesDto);
	
	// 고객의 상품 하나 좋아요 확인
	public int checkLikeProductByCustomer(ProductLikesDto productLikesDto);
	
	// 상품 당 좋아요 개수
	public int countLikeProductId(int product_id);

ProductServiceImpl

@Service
public class ProductServiceImpl {
	
	@Autowired
	private ProductSqlMapper productSqlMapper;
	@Autowired
	private SellerSqlMapper sellerSqlMapper;
	@Autowired
	private ReviewSqlMapper reviewSqlMapper;
	
	// 좋아요 아이콘 클릭
	public void toggleLike(ProductLikesDto productLikesDto) {
		
		if(productSqlMapper.checkLikeProductByCustomer(productLikesDto) > 0) {
			productSqlMapper.unlikeProduct(productLikesDto); // 좋아요를 클릭한 상태면 취소하기
		} else {
			productSqlMapper.likeProduct(productLikesDto); // 좋아요를 클릭한 적이 없다면 좋아요 누르기 (색 변경)
		}
		
	}

	
	// 고객이 하나의 상품에 대하여 좋아요를 하였는지 체크
	public boolean checkLikeProductByCustomer(ProductLikesDto productLikesDto) {
		return productSqlMapper.checkLikeProductByCustomer(productLikesDto) > 0;
	}
	
	// 상품 당 좋아요 개수
	public int getTotalLikeProductId(int product_id) {
		return productSqlMapper.countLikeProductId(product_id);
	}

RestProductController

@RestController
@RequestMapping("/product/*")
public class RestProductController {
	
	@Autowired
	private ProductServiceImpl productService;
	
	// 좋아요 클릭했다 뗐다 하기
	@RequestMapping("toggleLike") 
	public Map<String, Object> toggleLike(HttpSession session, ProductLikesDto params) {
		
		Map<String, Object> map = new HashMap<>();
		
		CustomerDto sessionUser = (CustomerDto) session.getAttribute("sessionUser");
		params.setCustomer_id(sessionUser.getId());
		
		productService.toggleLike(params);
		
		map.put("result", "success");
		
		return map;
	}
	
	
	// 고객이 하나의 상품에 대하여 좋아요를 하였는지 체크
	@RequestMapping("checkLikeProductByCustomer") 
	public Map<String, Object> checkLikeProductByCustomer(HttpSession session, ProductLikesDto params) {
		
		Map<String, Object> map = new HashMap<>();
		
		CustomerDto sessionUser = (CustomerDto) session.getAttribute("sessionUser");
		
		if (sessionUser == null) {
			map.put("result", "fail");
			map.put("reason", "로그인이 되어있지 않습니다.");
			return map;
		}
		
		params.setCustomer_id(sessionUser.getId());
		
		map.put("result", "success");
		map.put("checkLikeProductByCustomer", productService.checkLikeProductByCustomer(params));
		
		
		return map;
		
	}
	
	
	// 상품 좋아요 개수 체크
	@RequestMapping("getTotalLikeProductId")
	public Map<String, Object> getTotalLikeProductId(int product_id) {
		
		Map<String, Object> map = new HashMap<>();
		
		map.put("result", "success");
		
		map.put("count", productService.getTotalLikeProductId(product_id));
		
		return map;
		
	}

}

detail.jsp (좋아요 부분만)

    <div class="row mt-2">
            <div class="col">
                <i id="heartBox" onclick="toggleLike()" class="fs-1 text-danger bi bi-heart"></i>
                <span id="totalLikeCount"></span>
                <input type="hidden" name="product_id" value="${productDetail.productDto.id}">
                <input type="hidden" name="customer_id" value="${sessionUser.id}">						
            </div>
     </div>

detail.js

/**
 * 
 */
 

 
 function orderLimit() {
	 alert("고객 전용 서비스입니다.");
	 return false;
 }
 
 
var path = window.location.pathname;

//경로에서 변수 부분 추출
var parts = path.split('/');
var product_id = parts[parts.length - 1];

  
 let sessionId = null;

 function getSessionId() {
 		
     const xhr = new XMLHttpRequest();
     
     
     xhr.onreadystatechange = function () {
         if(xhr.readyState == 4 && xhr.status == 200){
             const response = JSON.parse(xhr.responseText);

             if(response.result == "success") {
                 sessionId = response.id;
                 console.log('sessionId::', sessionId);
             }
             
         }
     }	

   
     xhr.open("get", "/shop/customer/getCustomerId",false);
     xhr.send();

     
 }



 function refreshTotalLikeCount() {
 		
     const xhr = new XMLHttpRequest();
     
     xhr.onreadystatechange = function () {
         if(xhr.readyState == 4 && xhr.status == 200){
             const response = JSON.parse(xhr.responseText);
             

             const totalLikeCountBox = document.getElementById("totalLikeCount");
             totalLikeCountBox.innerHTML = response.count;
             
         }
     }	
     xhr.open("get", "/shop/product/getTotalLikeProductId?product_id=" + product_id);
     xhr.send();

     
 }

 function toggleLike() {
     if(sessionId == null) {
         if(confirm("로그인 후 서비스를 이용하실 수 있습니다.")) {
             location.href = "/shop/customer/loginPage";
         }
         return;
     }

     const xhr = new XMLHttpRequest();

     xhr.onreadystatechange = function(){
         if(xhr.readyState == 4 && xhr.status == 200){
             const response = JSON.parse(xhr.responseText);
      
             refreshTotalLikeCount();
             refreshMyHeart();
         }
     }

     xhr.open("get", "/shop/product/toggleLike?product_id=" + product_id);
     xhr.send();
 }


 function refreshMyHeart(){
 		
     if(sessionId == null) 
         return;
     
     
     const xhr = new XMLHttpRequest();
     
     xhr.onreadystatechange = function(){
         if(xhr.readyState == 4 && xhr.status == 200){
             const response = JSON.parse(xhr.responseText);
             // js 렌더링... 작업..
             const heartBox = document.getElementById("heartBox");
             
             if(response.checkLikeProductByCustomer){
                 heartBox.classList.remove("bi-heart");
                 heartBox.classList.add("bi-heart-fill");
             }else{
                 heartBox.classList.remove("bi-heart-fill");
                 heartBox.classList.add("bi-heart");
             }
         }
     }

     //get
     xhr.open("get", "/shop/product/checkLikeProductByCustomer?product_id=" + product_id);
     xhr.send();
     
 }


 window.addEventListener("DOMContentLoaded", function(){
     //사실상 시작 시점...
     getSessionId();
     refreshTotalLikeCount();
     refreshMyHeart();
 });

 

상품 좋아요 클릭 이전

상품 좋아요 클릭 후