시행착오 - 좋아요 기능

dev_archive_v·2025년 3월 14일

스프링 부트

목록 보기
9/22

스프링부트+리액트간의 통신이 어떻게 이루어지는지 알기 위해서 게시판+좋아요 기능이 담긴 프로젝트를 진행하고 있었다.
좋아요 기능은 생각보다 고려해야 되는 점이 꽤나 있었다..

개발 환경

backend : spring boot
frontend : react

문제 상황 1

두 개의 창을 띄워놓고서 좋아요 기능을 테스트해보는 상황이었다.
왼쪽은 사용자 A가 로그인 한 화면, 오른쪽은 사용자 B가 로그인 한 화면이다.

당연히 사용자 A가 클릭한 것은 사용자 A의 정보가 등록되어야했다.
그러나 사용자 B가 클릭한 것으로 인식되어서 기능이 정상적으로 작동하지 못했다.

해결 방법

Backend

.sessionManagement(session -> session
                        .maximumSessions(2) // 여러 계정이 동시에 유지되도록 설정 (원하는 숫자로 변경 가능)
                        .maxSessionsPreventsLogin(false) // 기존 세션을 만료하지 않도록 설정
                )

우선 security.config에 다음과 같이 설정을 해주었다.
여러계정이 동시에 유지되도록 우선 설정해보았다.
1. Controller

 public class LikeController {
    private final HeartLikeService heartLikeService;
   
    @PostMapping("/article/like/{articleId}")
    public ResponseEntity<HeartDto> articleLike(@PathVariable("articleId") Long articleId,@RequestBody Map<String, String> requestData){

      
        HeartDto heartDto=heartLikeService.addLike(articleId,requestData);
        return ResponseEntity.status(HttpStatus.OK).body(heartDto);


    }

    }
  1. Service
public class HeartLikeService {
   @Transactional
    public HeartDto addLike(Long articleId,Map<String, String> requestData){
        String userEmail = requestData.get("userEmail"); // 프론트에서 받은 userEmail
        User currentUser=userService.getUserInfo(userEmail);
        Authentication authentication= SecurityContextHolder.getContext().getAuthentication();
        String email=authentication.getName();
        User user = userService.getUserInfo(email);
        System.out.println("요청한 currentUser"+currentUser);
     
        Article article=articleRepository.findByArticleId(articleId);
   
  if(likeRepository.findByArticleAndUser(article, currentUser)==null){ //해당 게시글에 articleUser가 없는경우 +1
            article.setLikeCnt(article.getLikeCnt()+1);
            HeartLike heartLike=HeartLike.addLike(currentUser, article);
            likeRepository.save(heartLike);
           
            return HeartDto.createHeartDto("좋아요 완료❤️",heartLike);
        }
      

Frontend

현재 세션을 backend로 넘겨주도록 했다.

 const userEmail = sessionStorage.getItem("email");
   const responseLike = await axios({
                url: `http://localhost:8080/article/like/${params}`,
                method: 'POST',
                withCredentials: true,
                data: { userEmail },
                headers: {
                    "Content-Type":
                        "application/json"
                }
            });

이렇게 문제상황 1은 종료되었다. 그러나 또 한가지 기능의 문제가 있었다.


문제 상황 2

현재 login한 사용자가 이미 좋아요를 누른 게시글이라면 채워진 하트여야 했다. 처음에는 게시글 상세조회를 GetMapping메서드로 가져오고 있었다.
GetMapping은 요청시에 body가 비어있다. 따라서 PostMapping으로 body에 session email이 담긴 요청을 해주어야 한다고 판단했다.

backend

  1. Controller
 @PostMapping("/article/{articleId}")
    public ResponseEntity<Map<String,Object>> detail(@PathVariable("articleId") Long articleId,@RequestBody Map<String, String> requestData){
       
       Map<String,Object> response=articleService.getArticleInfoAndUser(articleId,requestData);

     return ResponseEntity.status(HttpStatus.OK).body(response);
    }
  1. Service
public Map<String,Object> getArticleInfoAndUser(Long articleId,Map<String, String> requestData){
        Article article=articleRepository.findByArticleId(articleId);
        String userEmail = requestData.get("userEmail"); // 프론트에서 받은 userEmail
        User currentUser=userService.getUserInfo(userEmail);
        System.out.println("요청한 currentUser"+currentUser);
        //like여부 정보 가져오기
        boolean isLiked=likeRepository.existsByArticleIdAndUserId(articleId, currentUser.getId());
        Map<String,Object> response=new HashMap<>();
        response.put("article",article);
        response.put("isLiked",isLiked);
   
        return response;
    }

frontend

  try {
            const userEmail = sessionStorage.getItem("email");
            const response = await axios({
                url: `http://localhost:8080/article/${params}`,
                method: 'POST',
                data: { userEmail },
                headers: {
                    "Content-Type":
                        "application/json"
                },
                withCredentials: true,
            });
            console.log(response.data.article);
            setDetail(response.data.article);
            setLike(response.data.isLiked);
            console.log(response.data.isLiked);

        } catch (error) {
            console.log("에러 발생", error);
        }
  • setLike를 통해서 현재 session에 있는 사용자가 좋아요를 눌렀는지에 따라 하트가 다르게 표시되도록 하였다. <HeartButton like={like ? true : false} onClick={handleLike} />

0개의 댓글