Skip to content

Commit 21d11be

Browse files
committed
Feat: 대댓글 생성 API 구현
1 parent db97e68 commit 21d11be

File tree

4 files changed

+100
-0
lines changed

4 files changed

+100
-0
lines changed

src/main/java/com/back/domain/board/comment/controller/CommentController.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.back.domain.board.comment.dto.CommentListResponse;
44
import com.back.domain.board.comment.dto.CommentRequest;
55
import com.back.domain.board.comment.dto.CommentResponse;
6+
import com.back.domain.board.comment.dto.ReplyResponse;
67
import com.back.domain.board.common.dto.PageResponse;
78
import com.back.domain.board.comment.service.CommentService;
89
import com.back.global.common.dto.RsData;
@@ -86,4 +87,21 @@ public ResponseEntity<RsData<Void>> deleteComment(
8687
null
8788
));
8889
}
90+
91+
// 대댓글 생성
92+
@PostMapping("/{commentId}/replies")
93+
public ResponseEntity<RsData<ReplyResponse>> createReply(
94+
@PathVariable Long postId,
95+
@PathVariable Long commentId,
96+
@RequestBody @Valid CommentRequest request,
97+
@AuthenticationPrincipal CustomUserDetails user
98+
) {
99+
ReplyResponse response = commentService.createReply(postId, commentId, request, user.getUserId());
100+
return ResponseEntity
101+
.status(HttpStatus.CREATED)
102+
.body(RsData.success(
103+
"대댓글이 생성되었습니다.",
104+
response
105+
));
106+
}
89107
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.back.domain.board.comment.dto;
2+
3+
import com.back.domain.board.comment.entity.Comment;
4+
import com.back.domain.board.common.dto.AuthorResponse;
5+
6+
import java.time.LocalDateTime;
7+
8+
/**
9+
* 대댓글 응답 DTO
10+
*
11+
* @param commentId 댓글 Id
12+
* @param postId 게시글 Id
13+
* @param parentId 부모 댓글 Id
14+
* @param author 작성자 정보
15+
* @param content 댓글 내용
16+
* @param createdAt 댓글 생성 일시
17+
* @param updatedAt 댓글 수정 일시
18+
*/
19+
public record ReplyResponse(
20+
Long commentId,
21+
Long postId,
22+
Long parentId,
23+
AuthorResponse author,
24+
String content,
25+
LocalDateTime createdAt,
26+
LocalDateTime updatedAt
27+
) {
28+
public static ReplyResponse from(Comment comment) {
29+
return new ReplyResponse(
30+
comment.getId(),
31+
comment.getPost().getId(),
32+
comment.getParent().getId(),
33+
AuthorResponse.from(comment.getUser()),
34+
comment.getContent(),
35+
comment.getCreatedAt(),
36+
comment.getUpdatedAt()
37+
);
38+
}
39+
}

src/main/java/com/back/domain/board/comment/service/CommentService.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.back.domain.board.comment.dto.CommentListResponse;
44
import com.back.domain.board.comment.dto.CommentRequest;
55
import com.back.domain.board.comment.dto.CommentResponse;
6+
import com.back.domain.board.comment.dto.ReplyResponse;
67
import com.back.domain.board.common.dto.PageResponse;
78
import com.back.domain.board.comment.entity.Comment;
89
import com.back.domain.board.post.entity.Post;
@@ -120,4 +121,44 @@ public void deleteComment(Long postId, Long commentId, Long userId) {
120121

121122
commentRepository.delete(comment);
122123
}
124+
125+
/**
126+
* 대댓글 생성 서비스
127+
* 1. User 조회
128+
* 2. Post 조회
129+
* 3. 부모 Comment 조회
130+
* 4. 부모 및 depth 검증
131+
* 5. 자식 Comment 생성
132+
* 6. Comment 저장 및 ReplyResponse 반환
133+
*/
134+
public ReplyResponse createReply(Long postId, Long parentCommentId, CommentRequest request, Long userId) {
135+
// User 조회
136+
User user = userRepository.findById(userId)
137+
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
138+
139+
// Post 조회
140+
Post post = postRepository.findById(postId)
141+
.orElseThrow(() -> new CustomException(ErrorCode.POST_NOT_FOUND));
142+
143+
// 부모 Comment 조회
144+
Comment parent = commentRepository.findById(parentCommentId)
145+
.orElseThrow(() -> new CustomException(ErrorCode.COMMENT_NOT_FOUND));
146+
147+
// 부모의 게시글 일치 검증
148+
if (!parent.getPost().getId().equals(postId)) {
149+
throw new CustomException(ErrorCode.COMMENT_PARENT_MISMATCH);
150+
}
151+
152+
// depth 검증: 부모가 이미 대댓글이면 예외
153+
if (parent.getParent() != null) {
154+
throw new CustomException(ErrorCode.COMMENT_DEPTH_EXCEEDED);
155+
}
156+
157+
// 자식 Comment 생성
158+
Comment reply = new Comment(post, user, request.content(), parent);
159+
160+
// 저장 및 응답 반환
161+
commentRepository.save(reply);
162+
return ReplyResponse.from(reply);
163+
}
123164
}

src/main/java/com/back/global/exception/ErrorCode.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ public enum ErrorCode {
8888
CATEGORY_NOT_FOUND(HttpStatus.NOT_FOUND, "POST_003", "존재하지 않는 카테고리입니다."),
8989
COMMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "COMMENT_001", "존재하지 않는 댓글입니다."),
9090
COMMENT_NO_PERMISSION(HttpStatus.FORBIDDEN, "COMMENT_002", "댓글 작성자만 수정/삭제할 수 있습니다."),
91+
COMMENT_PARENT_MISMATCH(HttpStatus.BAD_REQUEST, "COMMENT_003", "부모 댓글이 해당 게시글에 속하지 않습니다."),
92+
COMMENT_DEPTH_EXCEEDED(HttpStatus.BAD_REQUEST, "COMMENT_004", "대댓글은 한 단계까지만 작성할 수 있습니다."),
9193

9294
// ======================== 공통 에러 ========================
9395
BAD_REQUEST(HttpStatus.BAD_REQUEST, "COMMON_400", "잘못된 요청입니다."),

0 commit comments

Comments
 (0)