항해99/실전프로젝트

항해99-실전프로젝트 02(좋아요, 북마크)

연어조아 2021. 12. 6. 18:58
728x90

ER 다이어그램

게시글 필드안에 좋아요 필드만 존재하고 있다.

문제점

  • 어떤 사용자가 어떤 게시글에 좋아요를 눌렀는지 모른다.

해결방법

  • 어떤 사용자가 어떤 게시글에 좋아요를 눌렀는지 저장하는 테이블을 만든다.

유저 테이블과 게시글 테이블에 좋아요 테이블은 1:n으로 연결되어있다.

DB 예시

like 테이블의 데이터 예시

  • 게시판 입장에서
    • 4206번 게시판은 1번 유저와 32865번 유저가 좋아요를 눌렀다는 것을 알게된다.
    • 이를 이용해 만약 4206번 게시판에 1번 유저가 또 좋아요를 누른다면 반대로 좋아요를 취소하는 로직을 구현하면 된다.
  • 유저 입장에서
    • 1번 유저는 4206번 게시물과 33964번 게시물에 좋아요를 눌렀다.
    • 북마크를 위에 동일한 로직으로 구성하게 된다면 쉽게 북마크를 만들 수 있다

소스코드

게시글 테이블의 좋아요 테이블과의 1:n 맵핑
유저 테이블의 좋아요 테이블과 1:n 맵핑
게시글 테이블과 유저 테이블과의 연관관계 맵핑

소스코드 - 좋아요 누르기

 //좋아요
    @PostMapping("/board/like")
    public ResponseDto LikeInfo(@RequestParam Long cardId, @AuthenticationPrincipal UserDetailsImpl userDetails){
        LikeResponseDto likeResponseDto = likeService.LikeInfo(cardId, userDetails.getUser());

        if(likeResponseDto.getLikeCheck().equals(false)){
            return new ResponseDto(201L, "좋아요가 취소되었습니다..", likeResponseDto);
        }
        else{
            return new ResponseDto(200L, "좋아요가 등록되었습니다..", likeResponseDto);
        }
    }
  • 좋아요를 누르면 해당하는 게시글 아이디와 로그인한 유저의 유저정보를 가지고 서비스 계층으로 이동한다.
  • 후에 서비스 계층에서의 리턴 값을 확인하여 취소 혹은 등록 로직의 결과값을 리턴한다.
@Transactional
    public LikeResponseDto LikeInfo(Long boardId, User user){
         Board findBoard = boardRepository.findById(boardId).orElseThrow(
                () -> new NullPointerException("해당하는 게시글이 존재하지 않습니다.")
        );

        List<Like> findDuplicateLike = likeRepository.findAllByBoardAndUser(findBoard, user);

        // 좋아요 삭제
        if(findDuplicateLike.size() != 0){
            Like findLike = findDuplicateLike.get(0);
            deleteLike(findLike);

            int count = likeRepository.countByBoard(findBoard) ;

            findBoard.setLikeCount(Long.valueOf(count));

            LikeResponseDto likeResponseDto = new LikeResponseDto(boardId, false, Long.valueOf(count));
            return likeResponseDto;
        }

        //좋아요 증가
        else{
            Like newLike = new Like(findBoard,user);
            saveLike(newLike);

            int count = likeRepository.countByBoard(findBoard);
            findBoard.setLikeCount(Long.valueOf(count));

            LikeResponseDto likeResponseDto = new LikeResponseDto(boardId, true, Long.valueOf(count));
            return likeResponseDto;
        }

    }
  • List<Like> findDuplicateLike = likeRepository.findAllByBoardAndUser(findBoard, user);
    • 게시물id와 user 정보를 통해서 둘다 해당하는 좋아요 데이터를 찾는다. 만약 존재한다면 이미 유저가 해당하는 게시물에 좋아요를 눌렀다라는 것이며 없다면 좋아요를 누르지 않았다는 소리가 된다
  • if 문을 통해서 좋아요를 새로 넣거나 기존에 있던 데이터를 삭제하고 다시 좋아요를 count하여 board 필드의 likeCount 필드에 데이터를 업데이트 한다.
  • likeCheck를 통해서 해당 게시물의 하트에 색을 채울 것 인지 뺄 것 인지 판단한다.

소스코드 - 한 게시물의 좋아요 수, 결과 값 출력하기

new QCommunityDtoCustom(
                                board.id,
                                QUser.user.nickname,
                                board.title,
                                location.cityName,
                                board.address,
                                board.img,
                                board.content,
                                board.modifiedAt,
                                boardLikeCount(),
                                (userDetails == null) ? setFalse() : distinguishLikeExistUser(userDetails.getUser()),
                                (userDetails == null) ? setFalse() : distinguishBookmarkExistUser(userDetails.getUser())
                        )
private JPQLQuery<Long> boardLikeCount() {
        return JPAExpressions
                .select(like.count())
                .from(like)
                .where(boardIdEqLikeBoardId());
}
  • 한 게시물의 상세페이지를 조회할 때 likeCount 정보와 likeCheck 정보가 필요하다
  • 위는 querydsl을 통해서 count query를 날리는 문법이다.
  • 좋아요 수는 해당 함수에 서브 쿼리를 통해서 좋아요 수를 계산하여 사용자에게 제공한다.
private BooleanExpression distinguishLikeExistUser(User user) {
        return JPAExpressions
                .select(like)
                .from(like)
                .where(userIdEqLikeUserId(user).and(boardIdEqLikeBoardId()))
                .exists();
    }
private BooleanExpression setFalse() {
        return Expressions.asBoolean(false);
    }
  • likeCheck 또한 exists() 함수를 통해 true false 값을 가져올 수 있다.
  • 또한 만약 로그아웃 상황일땐 삼항연산자를 통해서 false 만을 리턴한다.

게시판 필드 내의 - likeCount

게시판 테이블의 likeCount 필드

해당 필드는 게시판 조회할 때 좋아요 수를 가져오는 것이 아는 좋아요 순으로 정렬하기 위해서 필드를 만들었다.


private OrderSpecifier<? extends Serializable> getOrderBy(String sort) {
    if(sort.equals("star"))
        return star.starGazing.desc();
    else if(sort.equals("like"))
        return board.likeCount.desc();
    else if(sort.equals("latest"))
        return board.modifiedAt.desc();
    else
        return null;
}

 

도메인 설계를 하고 나서 바로 설계된 내용으로 API 개발을 하기 보다는 좋아요와 북마크를 개발할 때 고민했었던 내용들을 적어놓고 싶어 이 게시물을 작성하였다.

 

다음 게시물은 아마 기본적인 JPA를 이용한 API 개발 방식을 포스팅 할 것 같다.

 

 

깃허브 : https://github.com/salmon2/StarProject

 

GitHub - salmon2/StarProject

Contribute to salmon2/StarProject development by creating an account on GitHub.

github.com

프로젝트 홈페이지 : https://stellakorea.co.kr/

 

별보러가지않을래?

캠핑 차박하실때 불멍만 즐기셨나요? 이제는 별도 구경해보세요! 별이 잘보이는 장소,날씨 정보보시고 나만의 캠핑,차박 장소도 공유 해보세요!

stellakorea.co.kr