티스토리 뷰
회원로직, 게시글, 댓글 CRUD까지 구현 완료했으니 이젠 댓글 좋아요 기능을 구현해보겠다.
Entity 설계
package com.example.MyFreshmanCommunity.entity;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
@NoArgsConstructor
@AllArgsConstructor
@Getter
@ToString
@Entity
public class LikeComment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "member_id")
@OnDelete(action = OnDeleteAction.CASCADE) //멤버가 지워지면, likeComment 레코드도 삭제됨
private Member member;
@ManyToOne
@JoinColumn(name = "comment_id")
private Comment comment;
@Column(nullable = false)
private boolean status;
public static LikeComment createLike(Member member, Comment comment) {
return new LikeComment(
null,
member,
comment,
true
);
}
public void deleteLike(Comment comment) {
this.status = false;
}
}
member가 지워지면, likeComment 레코드도 사라질 수 있도록 하기 위해 외래키 제약조건 CASCADE를 사용해주었다.
또한 boolean 타입의 status가 있는데, 이는 좋아요 상태를 나타내주는 값이다. 좋아요를 눌렀으면 true, 좋아요가 누르지 않았거나 취소했다면 false 이다. 이를 통해 각 댓글에 대한 사용자의 좋아요 상태를 명확하게 관리할 수 있다.
또한 createLike, deleteLike 두 개의 메소드를 만들어서 새로운 좋아요(LikeComment) 객체를 생성하고 초기 상태를 '좋아요 됨'(true)으로 설정하거나, Comment에 대한 좋아요의 상태를 '좋아요 취소됨'(false)으로 변경할 수 있도록 해주었다.
DTO
LikeDto
package com.example.MyFreshmanCommunity.dto;
import com.example.MyFreshmanCommunity.entity.LikeComment;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LikeDto {
private String message;
private boolean status;
public static LikeDto createLikeDto(String message, LikeComment likeComment) {
return new LikeDto(
message,
likeComment.isStatus()
);
}
}
LikeDto는 서버에서 클라이언트로 데이터를 전송하는 데 사용되는 dto로,
좋아요 처리가 되었다는 message와 좋아요 상태(true, false)를 반환한다.
Repository
LikeCommentRepository
package com.example.MyFreshmanCommunity.repository;
import com.example.MyFreshmanCommunity.entity.Comment;
import com.example.MyFreshmanCommunity.entity.LikeComment;
import com.example.MyFreshmanCommunity.entity.Member;
import org.springframework.data.jpa.repository.JpaRepository;
public interface LikeCommentRepository extends JpaRepository<LikeComment, Long> {
LikeComment findByMemberAndComment(Member member, Comment comment);
void deleteByMemberAndComment(Member member, Comment comment);
}
특정 Member(사용자)와 Comment(댓글) 조합으로 좋아요 객체(LikeComment)를 찾아 반환하는 findByMemberAndComment 메서드를 만들어주었다. 이 메서드는 특정 사용자가 특정 댓글에 대해 좋아요를 했는지 확인하는 데 사용된다.
반면, deleteByMemberAndComment는 특정 Member(사용자)와 Comment(댓글) 조합에 해당하는 좋아요를 데이터베이스에서 삭제하는 메서드이다. 사용자가 댓글에 대한 좋아요를 취소할 때 이 메서드가 사용된다.
Service
LikeCommentService
package com.example.MyFreshmanCommunity.service;
import com.example.MyFreshmanCommunity.dto.LikeDto;
import com.example.MyFreshmanCommunity.entity.Comment;
import com.example.MyFreshmanCommunity.entity.LikeComment;
import com.example.MyFreshmanCommunity.entity.Member;
import com.example.MyFreshmanCommunity.exception.MemberNotFoundException;
import com.example.MyFreshmanCommunity.exception.NotFoundException;
import com.example.MyFreshmanCommunity.repository.CommentRepository;
import com.example.MyFreshmanCommunity.repository.LikeCommentRepository;
import jakarta.servlet.http.HttpSession;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class LikeCommentService {
private final CommentService commentService;
private final CommentRepository commentRepository;
private final LikeCommentRepository likeCommentRepository;
@Transactional
public LikeDto addLike(Long commentId, HttpSession session) {
Member member = (Member) session.getAttribute("member");
Comment comment = commentRepository.findById(commentId).
orElseThrow(() -> new NotFoundException("대상 댓글이 없습니다."));
if(member == null) throw new MemberNotFoundException("로그인하지 않은 상태에선 좋아요를 누를 수 없습니다.");
if (likeCommentRepository.findByMemberAndComment(member, comment) == null) { //좋아요가 없으면
comment.setLikesCount(comment.getLikesCount() + 1); //1씩 증가
LikeComment likeComment = LikeComment.createLike(member, comment); //true처리
likeCommentRepository.save(likeComment);
return LikeDto.createLikeDto("좋아요 처리 완료", likeComment);
}
else { //이미 좋아요 눌렀으면
comment.setLikesCount(comment.getLikesCount() - 1);
LikeComment likeComment = likeCommentRepository.findByMemberAndComment(member, comment);
likeComment.deleteLike(comment); //false처리
likeCommentRepository.deleteByMemberAndComment(member, comment);
return LikeDto.createLikeDto("좋아요 취소 완료", likeComment);
}
}
}
사용자가 댓글에 좋아요를 추가하거나 취소할 때 사용되는 addLike 메서드는 사용자 세션에서 멤버 정보를 가져오고, 댓글 ID를 사용하여 해당 댓글을 찾는다.
좋아요가 아직 없으면 해당 댓글의 좋아요 수를 1만큼 증가시켜 주고 새로운 좋아요를 추가하고,
이미 좋아요를 눌렀다면 좋아요를 취소하는 것이므로 해당 댓글의 좋아요 수를 1만큼 감소시켜주고, 좋아요를 취소해준다. (LikeComment 테이블에서 삭제)
Controller
LikeCommentApiController
package com.example.MyFreshmanCommunity.api;
import com.example.MyFreshmanCommunity.dto.LikeDto;
import com.example.MyFreshmanCommunity.service.LikeCommentService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class LikeCommentApiController {
private final LikeCommentService likeCommentService;
@PostMapping("/comment/{commentId}/like")
public ResponseEntity<LikeDto> addLike(@PathVariable Long commentId, HttpServletRequest request) {
HttpSession session = request.getSession();
LikeDto like = likeCommentService.addLike(commentId, session);
return ResponseEntity.status(HttpStatus.OK).body(like);
}
}
@PathVariable을 사용하여 URL 경로의 일부(commentId) 를 메서드의 파라미터로 바인딩해주었다.
Postman을 통한 데이터 확인
postman을 통해 데이터가 잘 넘어가는지 확인해주었다.
'Spring' 카테고리의 다른 글
스프링 커뮤니티 만들기 #8 북마크 목록 조회 (0) | 2024.03.03 |
---|---|
스프링 커뮤니티 만들기 #7 - 게시글 북마크 (0) | 2024.03.03 |
스프링부트 커뮤니티 만들기 #5 - 댓글 CRUD (0) | 2024.03.03 |
스프링부트 커뮤니티 만들기 # 회고록 (2) | 2024.02.29 |
스프링부트 커뮤니티 만들기 #4 - 게시글 CRUD (1) | 2024.02.28 |
- Total
- Today
- Yesterday
- 스프링
- 백준
- 로그아웃
- 자바
- EnumType.ORDINAL
- 비영속
- 영속
- 커뮤니티
- 다이나믹 프로그래밍
- 백준 파이썬
- 북마크
- 스프링부트
- elasticsearch
- DP
- 지연로딩
- 스프링 북마크
- 회원탈퇴
- SQLD
- 로깅
- 인텔리제이
- 파이썬
- JPA
- SQL
- 프론트엔드
- 스프링 커뮤니티
- 자바 스프링
- SQL 레벨업
- 웹MVC
- 웹 MVC
- 준영속
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |