Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ ResponseEntity<BaseResponse<CommentDetailResponse>> createComment(
@RequestBody @Valid CommentRequest request,
@Parameter(description = "댓글을 작성할 게시글 식별자", example = "1") @RequestParam Long postId);

@PostMapping("/{id}/like")
@Operation(summary = "댓글 좋아요 토글")
ResponseEntity<BaseResponse<Void>> toggleLike(@PathVariable Long id);

@GetMapping
@Operation(summary = "특정 게시글의 댓글 조회", description = "특정 게시글의 댓글 리스트를 조회합니다.")
ResponseEntity<BaseResponse<List<CommentDetailResponse>>> getAllCommentsByPostId(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ public ResponseEntity<BaseResponse<CommentDetailResponse>> createComment(
return ResponseEntity.ok(BaseResponse.success(response));
}

@Override
public ResponseEntity<BaseResponse<Void>> toggleLike(@PathVariable Long id) {

commentService.toggleLike(id);
return ResponseEntity.ok(BaseResponse.success());
}

@Override
public ResponseEntity<BaseResponse<List<CommentDetailResponse>>> getAllCommentsByPostId(
@RequestParam Long postId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ public class CommentRequest {
@NotBlank(message = "댓글 내용은 필수입니다.")
@Schema(description = "댓글 내용", example = "답변 감사합니다~~~")
private String content;

@Schema(description = "답글을 작성할 댓글의 식별자", example = "1")
private Long parentCommentId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package com.sku.refit.domain.comment.dto.response;

import java.time.LocalDateTime;
import java.util.List;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
Expand All @@ -20,9 +21,24 @@ public class CommentDetailResponse {
@Schema(description = "댓글 내용", example = "처음 가보는거라 질문 드립니다 ㅠㅠ")
private String content;

@Schema(description = "댓글 작성자", example = "김다입")
private String nickname;

@Schema(description = "댓글 작성자 여부", example = "true")
private Boolean isWriter;

@Schema(description = "댓글 작성 시간", example = "20250101T120000")
private LocalDateTime createdAt;

@Schema(description = "부모 댓글 ID (null이면 일반 댓글)", example = "null")
private Long parentCommentId;

@Schema(description = "좋아요 개수", example = "3")
private Long likeCount;

@Schema(description = "내가 좋아요를 눌렀는지 여부", example = "true")
private Boolean isLiked;

@Schema(description = "답글 리스트")
private List<CommentDetailResponse> replies;
}
13 changes: 13 additions & 0 deletions src/main/java/com/sku/refit/domain/comment/entity/Comment.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
*/
package com.sku.refit.domain.comment.entity;

import java.util.ArrayList;
import java.util.List;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
Expand All @@ -11,6 +15,7 @@
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;

import com.sku.refit.domain.post.entity.Post;
Expand Down Expand Up @@ -46,6 +51,14 @@ public class Comment extends BaseTimeEntity {
@JoinColumn(name = "post_id", nullable = false)
private Post post;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id")
private Comment parent;

@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
@Builder.Default
private List<Comment> replies = new ArrayList<>();

public void update(String content) {
this.content = content;
}
Expand Down
43 changes: 43 additions & 0 deletions src/main/java/com/sku/refit/domain/comment/entity/CommentLike.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) SKU 다시입을Lab
*/
package com.sku.refit.domain.comment.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;

import com.sku.refit.domain.user.entity.User;
import com.sku.refit.global.common.BaseTimeEntity;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Table(
name = "comment_like",
uniqueConstraints = {@UniqueConstraint(columnNames = {"comment_id", "user_id"})})
public class CommentLike extends BaseTimeEntity {

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

@ManyToOne(fetch = FetchType.LAZY)
private Comment comment;

@ManyToOne(fetch = FetchType.LAZY)
private User user;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
*/
package com.sku.refit.domain.comment.mapper;

import java.util.List;

import org.springframework.stereotype.Component;

import com.sku.refit.domain.comment.dto.request.CommentRequest;
Expand All @@ -14,17 +16,32 @@
@Component
public class CommentMapper {

public Comment toComment(CommentRequest request, User user, Post post) {
return Comment.builder().content(request.getContent()).user(user).post(post).build();
public Comment toComment(CommentRequest request, Comment parent, User user, Post post) {
return Comment.builder()
.content(request.getContent())
.parent(parent)
.user(user)
.post(post)
.build();
}

public CommentDetailResponse toDetailResponse(Comment comment, User user) {
public CommentDetailResponse toDetailResponse(
Comment comment,
User user,
Long likeCount,
Boolean isLiked,
List<CommentDetailResponse> replies) {

return CommentDetailResponse.builder()
.commentId(comment.getId())
.content(comment.getContent())
.nickname(comment.getUser().getNickname())
.isWriter(comment.getUser().getId().equals(user.getId()))
.createdAt(comment.getCreatedAt())
.parentCommentId(comment.getParent() != null ? comment.getParent().getId() : null)
.likeCount(likeCount)
.isLiked(isLiked)
.replies(replies)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) SKU 다시입을Lab
*/
package com.sku.refit.domain.comment.repository;

import java.util.List;
import java.util.Optional;
import java.util.Set;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import com.sku.refit.domain.comment.entity.Comment;
import com.sku.refit.domain.comment.entity.CommentLike;
import com.sku.refit.domain.user.entity.User;

@Repository
public interface CommentLikeRepository extends JpaRepository<CommentLike, Long> {

boolean existsByCommentAndUser(Comment comment, User user);

Optional<CommentLike> findByCommentAndUser(Comment comment, User user);

long countByComment(Comment comment);

@Query(
"""
select cl.comment.id, count(cl)
from CommentLike cl
where cl.comment.id in :commentIds
group by cl.comment.id
""")
List<Object[]> countByCommentIds(@Param("commentIds") List<Long> commentIds);

@Query(
"""
select cl.comment.id
from CommentLike cl
where cl.comment.id in :commentIds
and cl.user.id = :userId
""")
Set<Long> findLikedCommentIds(
@Param("commentIds") List<Long> commentIds, @Param("userId") Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ public interface CommentService {
*/
CommentDetailResponse createComment(CommentRequest request, Long postId);

/**
* 댓글 좋아요 등록
*
* @param commentId
*/
void toggleLike(Long commentId);

/**
* 특정 게시글의 댓글 전체 조회
*
Expand Down
Loading