[01.02] 내일배움캠프[Spring] TIL-44

박상훈·2023년 1월 2일
0

내일배움캠프[TIL]

목록 보기
44/72

[01.02] 내일배움캠프[Spring] TIL-44

1. Spring 중간 미니 프로젝트

  • 1) 현재 유저로그인 기능 -> 팀원 : 이재원님
    2) 게시글 작성 기능 -> 팀원 : 장현재님
    3) 게시글의 댓글 기능 -> 팀원 : 손혜은님
    4) 게시글의 좋아요 기능 -> 팀장 : 박상훈
    5) 댓글의 좋아요 기능 -> 팀원 : 김민수님

오늘 내가 한 일

    1. 아직 회원가입, 게시글 ,댓글의 기능이 완성되어 Merge되지 않았기 때문에 기존에 앞선 작업들이 되어있는 코드에 게시글 좋아요 기능을 구현 해봤다.

2. 게시글의 좋아요 기능 구현

  • 구상
    1) Entity를 만들자 -> UserBoard와 연관이 있는 속성을 가진 Entity
package com.sparta.spartaboard.entity;


import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor
public class LikeBoard {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(nullable = false)
    private boolean isCheck;

    @ManyToOne
    @JoinColumn(name = "USER_ID")
    private User user;

    @ManyToOne
    @JoinColumn(name = "BOARD_ID")
    private Board board;

    public LikeBoard(User user, Board board,boolean isCheck) {
        this.user = user;
        this.board = board;
        this.isCheck = isCheck;
    }


    public void update(boolean isCheck){
        this.isCheck = isCheck;
    }
}
  • 사실 @ManyToOne의 연관 관계는 Jpa에게 연관이 있다고 알려주는 것이고, 사실상 연관 관계에서 사용하는 것은 ID값 밖에 없으므로, 굳이 User,Board의 객체를 연관 시켜주지 않고, userId,boardId를 컬럼으로 지정해주는 것이 좋을 수 있다.
  • 구상
    2) 유저가 좋아요 누름 -> 해당 LikeBoarEntityisCheck속성을 true로 바꾸고, 만약 이미 누른 상태에서 또 누르게 된다면 , false로 바꿔준다.
    3) 그리고 해당 게시글의 총 좋아요의 갯수를 알고 싶다?
    -> isCheck = true인 것을 filter해서 갯수를 update해주자!
package com.sparta.spartaboard.service;

import com.sparta.spartaboard.dto.LikeBoardResponseDto;
import com.sparta.spartaboard.entity.Board;
import com.sparta.spartaboard.entity.LikeBoard;
import com.sparta.spartaboard.entity.User;
import com.sparta.spartaboard.repository.BoardRepository;
import com.sparta.spartaboard.repository.LikeBoardRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Stream;

@Service
@RequiredArgsConstructor
@Slf4j
public class LikeBoardService {

    private final LikeBoardRepository likeBoardRepository;
    private final BoardRepository boardRepository;

    @Transactional
    public LikeBoardResponseDto changeLike(Long id, User user) {


        Board board = boardRepository.findById(id).orElseThrow(
                () -> new IllegalArgumentException("좋아요를 누를 게시글이 없습니다!")
        );


            LikeBoard likeBoard = likeBoardRepository.findAllByBoardAndUser(board, user);

            if(likeBoard==null) {

                LikeBoard likeBoardFirst = new LikeBoard(user, board, true);
                likeBoardRepository.saveAndFlush(likeBoardFirst);

                Long updateLikeNum = getLikeNum(board);
                board.updateLikeNum(updateLikeNum);
                log.info("좋아요 최초생성! 갯수 => " + updateLikeNum);

                return new LikeBoardResponseDto("좋아요 최초생성!", HttpStatus.OK.value());


            }else{
                if (likeBoard.isCheck()) {

                    likeBoard.update(false);
                    log.info("좋아요 다시 눌러서 풀림!");

                    Long updateLikeNum = getLikeNum(board);
                    board.updateLikeNum(updateLikeNum);
                    log.info("좋아요 다시 눌러서 풀림! 갯수 => " + updateLikeNum);
                    return new LikeBoardResponseDto("좋아요 다시 눌러서 풀림!", HttpStatus.OK.value());

                } else {
                    likeBoard.update(true);
                    log.info("좋아요 다시 생성!(눌림)");
                    Long updateLikeNum = getLikeNum(board);
                    board.updateLikeNum(updateLikeNum);
                    log.info("좋아요 다시 생성!(눌림) 갯수 => " + updateLikeNum);
                    return new LikeBoardResponseDto("좋아요 다시 생성!(눌림)", HttpStatus.OK.value());
                }
            }


    }

    public Long getLikeNum(Board board) {
        return board.getLikeBoards().stream().filter(s -> s.isCheck()).count();
    }
}
  • 사실 내가 봐도 엄청 비효율적 코드인 것 같다. 중복되는 로직도 많고, 코드도 길고... 불필요한 객체도 많고..

마주했던 문제점

  • LikeBoardService딴에서 최초 좋아요 생성시 계속해서 count의 갯수가 update()되지 않는 오류가 발생했다.
    -> jpa가 만들어주는 쿼리를 보니, count를 센 후 쿼리가 날라가는 것을 볼 수 있었다..
    -> @Tranactional의 선언으로 쿼리가 한방에 날라가는 것 같아 save()가 아닌 saveAndFlush()를 사용했더니 해결되었다.
    -> 하지만 만약 마지막 쿼리에서 오류가 터진다면, 전부 롤백되어야 하는데, 그렇게 되지 못한다는 단점이 있다..

앞으로 해결해야 할 문제점

  • 항상 뇌리에 스치는 말이 있었다.
    -> 양방향 연관관계에서 특히 @OneToMany의 연관관계에서 만약 해당 연관 객체가 수백 수천개가 된다면,
    항상 그 엔티티를 사용하거나 조회할 때 마다 그 많은 값을 가져와야 한다... -> 서버 터짐..!!!
  • @ManyToOne또한 마찬가지다 우리는 여태까지 User, BoardId값만 필요하지만 굳이 객체 자체를 매핑 시켜줬다.
    -> 그냥 userId or boardId의 변수를 선언해서 쓰자...!!
profile
기록하는 습관

0개의 댓글