[SpringBoot] 좋아요 기능 구현 및 생각

2024. 3. 27. 20:28· Backend/🌿Spring
목차
  1. 요구사항 & 정리
  2. 구현
  3. Entity
  4. LikesRepository
  5. 네이티브 쿼리 사용시 서비스 로직
  6. JPA 사용시 서비스 로직
  7. LikesRepository 추가
  8. ReviewServiewImpl
  9. Test & 마무리

안녕하세요~ 오늘은 읽는곳곳 프로젝트에 공유 독후감을 등록했을 때 좋아요 기능도 있었으면 좋겠다! 싶어서.. 포스팅을 하게 되었습니다. 좋아요 기능을 해본 적은 있지만 숙련되지는 못해 나중에 더 좋은 방법이 있다면 업데이트하도록 하겠습니다.

 

요구사항 & 정리

요구사항은 아래와 같습니다.

 

> 한 독후감에 1개의 좋아요만 가능하다.

> 즉 좋아요 상태의 유무 관리가 필수

 

여기서 Review에 좋아요 카운트 칼럼을 만들어서 직접 하면 안 되냐 생각하실 분도 계시겠지만 중복으로 좋아요가 가능하고 상태 관리를 할 필요가 없다면 그러셔도 될 것 같습니다. 하지만 좋아요를 누를 때마다 DB에 접근하여 Update를 직접 해주어야 하는 것은 비효율적이라고 생각되기에 캐시나 배치 등 여러 방법을 통한 자신만의 최적화 방법을 찾으시면 좋을 것 같습니다.. 이 부분은 저도 공부가 필요합니다 ㅎ..

 

구현

현 요구사항은 좋아요의 상태 관리가 필수적이기 때문에 좋아요 개수와 상태를 @Transient로 설정하여 기존 엔티티에 칼럼을 추가하지 않고 Likes 테이블을 따로 만들어 관리해 주도록 하겠습니다.

    @Transient // 칼럼이 만들어지지 않는다.
    private Long likeCount;

    @Transient
    private boolean likeState;

 

Entity

✅ Likes Entity를 만들어주도록 합니다. 여기서 Likes라고 하는 이유는 SQL에서 like는 문법으로 사용되는 단어이기 때문에 User를 Users나 Member로 사용하는 이유와 같다고 보시면 됩니다.

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Entity
@Table(
        name="likes",
        uniqueConstraints={
                @UniqueConstraint(
                        name = "likes_uk",
                        columnNames={"review_id", "user_id"}
                )
        }
)
public class Likes {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "review_id")
    private Review review;

    @JsonIgnoreProperties({"reviews"})
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    @CreationTimestamp
    private Timestamp createAt;
}

 

✅ 아래의 @Table부분을 처음 보실 수도 있습니다!

 

@Table(
        name="likes",
        uniqueConstraints={
                @UniqueConstraint(
                        name = "likes_uk",
                        columnNames={"review_id", "user_id"}
                )
        }
)

✅ @Table 어노테이션 내에서 uniqueConstraints 속성을 사용하는 것은 JPA에서 특정 엔티티의 테이블에 대해 유니크 제약 조건을 추가하는 방법입니다. 이 구문은 likes 테이블에 대해 review_id와 user_id칼럼 조합으로 유니크 제약 조건을 생성하고 있고 같은 사용자가 동일한 리뷰에 대해 두 번 이상 좋아요를 할 수 없도록 하는 데 목적이 있습니다.

굳이 이걸 써야 하나 싶다면 비즈니스 로직을 코드 내에서 처리할 수도 있습니다. 예를 들어, 좋아요를 추가하기 전에 데이터베이스에서 해당 사용자와 리뷰에 대한 좋아요가 이미 존재하는지 확인하는 로직을 구현할 수 있습니다.

 

    boolean existsByUserIdAndReviewId(Long userId, Long reviewId);

✅ 모든 좋아요 기능을 수행할 때 이 구문을 사용한 뒤에 하면 됩니다. 하지만 그럼 연산 횟수도 많아지고 깔끔하지 못하다고 생각되니 @Table 어노테이션을 활용하여 설정해 주도록 합시다.

 

LikesRepository

이후 네이티브 쿼리를 통해 좋아요 기능을 구현해 주도록 합니다.

    @Modifying
    @Query(value = "INSERT INTO likes(review_id, user_id) VALUES(:reviewId, :userId)", nativeQuery = true)
    void mLike(@Param("userId") Long userId, @Param("reviewId") Long reviewId);

    @Modifying
    @Query(value = "DELETE FROM likes WHERE review_id = :reviewId AND user_id  = :userId", nativeQuery = true)
    void mUnLike(@Param("userId") Long userId, @Param("reviewId") Long reviewId);

여기서 왜 네이티브 쿼리로 하냐 Likes like = new Likes()를 통해 생성자를 만들어해 주면 되지 않냐 싶지만

 

네이티브 쿼리 사용시 서비스 로직

    @Override
    public void 좋아요(Long socialId, Long review_id) {
        User user = userRepository.findBySocialId(socialId).orElseThrow();
        likesRepository.mLike(user.getId(), review_id);
    }

 

JPA 사용시 서비스 로직

    @Override
    public void 좋아요(Long socialId, Long review_id) {
        User user = userRepository.findBySocialId(socialId).orElseThrow();
        Review review = reviewRepository.findById(review_id);
        Likes like = new Likes(user,review);
        likesRepository.save(like)
    }

✅ 생성자로 따로 관리해주어야 할 뿐 아니라 좋아요를 누를 때마다 Entity를 생성해서 save 해주고 있습니다. 언듯 봐도 비효율 적이고 reviewReposity의 의존성도 추가해주어야 합니다. 그렇기 때문에 위와 같이 정리해 주도록 합니다!

 

✅ 이후에 유저가 독후감을 조회해 줄 때 likeCount와 likeState를 추가해서 클라이언트 측으로 반환해줘야 합니다. 그렇기 때문에 toDto를 수정하고 Count연산을 두어 클라이언트 쪽으로 보내줍시다!!

 

LikesRepository 추가

    Long countByReviewId(@Param("reviewId") Long reviewId);

    boolean existsByUserIdAndReviewId(Long userId, Long reviewId);

✅ Spring Data Jpa를 통해 카운트를 해주는 쿼리와 내가 독후감에 좋아요를 누른 상태를 반환해 주는 쿼리를 만들어줍니다.

 

ReviewServiewImpl

    public List<ReviewDto> 유저모든독후감조회(Long socialId) {
        List<Review> reviews = reviewRepository.mFindReviewsByUser(socialId);

        return reviews.stream().map(review -> {
            Long likeCount = likesRepository.countByReviewId(review.getId());
            boolean likeState = likesRepository.existsByUserIdAndReviewId(socialId, review.getId());
            return ReviewDto.toDto(review, likeCount, likeState);
        }).toList();
    }

✅ 마지막으로 ReviewDto에 파라미터를 추가하여 클라이언트로 전송해 주면 끝입니다.

 

Test & 마무리

잘 동작하는지 보기 위해 테스트 코드도 작성해 줍니다.. 좀 시간이 걸리긴 했지만 잘 되네요,,

 

근데 아직도 이렇게 리뷰마다 카운트연산과 상태연산을 해줘야 하는지 의문입니다. 상태의 경우는 해당하는 모든 Review의 상태를 한 번에 갖고 와서 그때그때 연산마다 상태를 체크해 주면 좋을 것 같은데... 지금은 어떻게 해야 할지 마땅히 떠오르지 않아서 나중에 더 고민해 본 뒤 로직을 수정해 보도록 하겠습니다.

 

오늘도 읽어주셔서 감사합니다😄

 

본 게시글은 메타코딩님의 수업에서 배운내용의 일부를 적용해 보았습니다.

https://www.youtube.com/c/%EB%A9%94%ED%83%80%EC%BD%94%EB%94%A9

'Backend > 🌿Spring' 카테고리의 다른 글

[SpringBoot] Redis 캐싱을 통한 좋아요 조회 성능 비교  (0) 2024.04.08
[SpringBoot] Docker를 통한 EC2환경 Redis 설치 & 테스트 통과하기  (0) 2024.04.02
[SpringBoot] 협업을 위한 Swagger 사용법  (0) 2024.03.11
[SpringBoot] AWS S3 Bucket을 이용한 이미지 업로드 + CloudFront설정  (0) 2024.03.06
[Spring Boot] @Value 어노테이션을 활용한 설정 값 관리  (0) 2024.02.14
  1. 요구사항 & 정리
  2. 구현
  3. Entity
  4. LikesRepository
  5. 네이티브 쿼리 사용시 서비스 로직
  6. JPA 사용시 서비스 로직
  7. LikesRepository 추가
  8. ReviewServiewImpl
  9. Test & 마무리
'Backend/🌿Spring' 카테고리의 다른 글
  • [SpringBoot] Redis 캐싱을 통한 좋아요 조회 성능 비교
  • [SpringBoot] Docker를 통한 EC2환경 Redis 설치 & 테스트 통과하기
  • [SpringBoot] 협업을 위한 Swagger 사용법
  • [SpringBoot] AWS S3 Bucket을 이용한 이미지 업로드 + CloudFront설정
발달중인 망고
발달중인 망고
Kangwon uni. Department of Computer Engineering
발달중인 망고
망고의 개발일기
발달중인 망고
전체
오늘
어제
  • ROOT (85)
    • 🥭Mango Odyssey (3)
    • Backend (1)
      • 🌿Spring (16)
    • Frontend (3)
      • React (1)
      • Thymeleaf (1)
      • Flutter (1)
    • DevOps (7)
      • AWS (5)
      • Docker (2)
    • Git (5)
    • Knowledge (18)
      • Java (12)
      • Python (6)
    • Activities (10)
      • 우아한 테크 프리코스 (7)
      • itwill (1)
      • 프리온보딩 백엔드 챌린지 12월 (0)
      • 스위프(SWYP) 3기 (1)
      • 팀 맥플러리 (1)
    • SQL (5)
    • IoT (4)
      • 아두이노 (4)
    • AI (1)
    • OS (1)
    • 일상 (8)
      • 일기 (6)
      • 독서 (0)
      • 잡생각 (1)
    • 언젠가 분류될 카테고리 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 깃허브
  • spring boot
  • AWS
  • 소스코드
  • EC2
  • baekjoon
  • python
  • DB
  • 자바
  • MVC
  • springboot
  • 파이썬
  • Spring
  • 백엔드
  • 문제풀이
  • 코딩테스트
  • 우테코
  • GIT
  • 알고리즘
  • 백준
  • 코드트리
  • 아두이노
  • 회고록
  • Model
  • SQL
  • 코드소스
  • Java
  • JPA
  • 스프링부트
  • 코드

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.1
발달중인 망고
[SpringBoot] 좋아요 기능 구현 및 생각
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.