[01.02] 내일배움캠프[Spring] TIL-44
1. Spring 중간 미니 프로젝트
- 1) 현재 유저로그인 기능 -> 팀원 : 이재원님
2) 게시글 작성 기능 -> 팀원 : 장현재님
3) 게시글의 댓글 기능 -> 팀원 : 손혜은님
4) 게시글의 좋아요 기능 -> 팀장 : 박상훈
5) 댓글의 좋아요 기능 -> 팀원 : 김민수님
오늘 내가 한 일
- 아직 회원가입, 게시글 ,댓글의 기능이 완성되어 Merge되지 않았기 때문에 기존에 앞선 작업들이 되어있는 코드에 게시글 좋아요 기능을 구현 해봤다.
2. 게시글의 좋아요 기능 구현
- 구상
1) Entity
를 만들자 -> User
와 Board
와 연관이 있는 속성을 가진 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) 유저가 좋아요 누름 -> 해당 LikeBoarEntity
의 isCheck
속성을 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
, Board
의 Id
값만 필요하지만 굳이 객체 자체를 매핑 시켜줬다.
-> 그냥 userId
or boardId
의 변수를 선언해서 쓰자...!!