Skip to content

Commit bae5acf

Browse files
committed
Feat: 댓글 생성 API 구현
1 parent a57751f commit bae5acf

File tree

7 files changed

+155
-0
lines changed

7 files changed

+155
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.back.domain.board.controller;
2+
3+
import com.back.domain.board.dto.CommentRequest;
4+
import com.back.domain.board.dto.CommentResponse;
5+
import com.back.domain.board.service.CommentService;
6+
import com.back.global.common.dto.RsData;
7+
import com.back.global.security.user.CustomUserDetails;
8+
import jakarta.validation.Valid;
9+
import lombok.RequiredArgsConstructor;
10+
import org.springframework.http.HttpStatus;
11+
import org.springframework.http.ResponseEntity;
12+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
13+
import org.springframework.web.bind.annotation.*;
14+
15+
@RestController
16+
@RequestMapping("/api/posts/{postId}/comments")
17+
@RequiredArgsConstructor
18+
public class CommentController implements CommentControllerDocs {
19+
private final CommentService commentService;
20+
21+
// 댓글 생성
22+
@PostMapping
23+
public ResponseEntity<RsData<CommentResponse>> createComment(
24+
@PathVariable Long postId,
25+
@RequestBody @Valid CommentRequest request,
26+
@AuthenticationPrincipal CustomUserDetails user
27+
) {
28+
CommentResponse response = commentService.createComment(postId, request, user.getUserId());
29+
return ResponseEntity
30+
.status(HttpStatus.CREATED)
31+
.body(RsData.success(
32+
"댓글이 생성되었습니다.",
33+
response
34+
));
35+
}
36+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.back.domain.board.controller;
2+
3+
import io.swagger.v3.oas.annotations.tags.Tag;
4+
5+
@Tag(name = "Comment API", description = "댓글 관련 API")
6+
public interface CommentControllerDocs {
7+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.back.domain.board.dto;
2+
3+
import jakarta.validation.constraints.NotBlank;
4+
5+
/**
6+
* 댓글 작성 및 수정을 위한 요청 DTO
7+
*
8+
* @param content 댓글 내용
9+
*/
10+
public record CommentRequest(
11+
@NotBlank String content
12+
) {
13+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.back.domain.board.dto;
2+
3+
import com.back.domain.board.entity.Comment;
4+
5+
import java.time.LocalDateTime;
6+
7+
/**
8+
* 댓글 응답 DTO
9+
*
10+
* @param commentId 댓글 Id
11+
* @param postId 게시글 Id
12+
* @param author 작성자 정보
13+
* @param content 댓글 내용
14+
* @param createdAt 댓글 생성 일시
15+
* @param updatedAt 댓글 수정 일시
16+
*/
17+
public record CommentResponse(
18+
Long commentId,
19+
Long postId,
20+
AuthorResponse author,
21+
String content,
22+
LocalDateTime createdAt,
23+
LocalDateTime updatedAt
24+
) {
25+
public static CommentResponse from(Comment comment) {
26+
return new CommentResponse(
27+
comment.getId(),
28+
comment.getPost().getId(),
29+
AuthorResponse.from(comment.getUser()),
30+
comment.getContent(),
31+
comment.getCreatedAt(),
32+
comment.getUpdatedAt()
33+
);
34+
}
35+
}

src/main/java/com/back/domain/board/entity/Comment.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,11 @@ public class Comment extends BaseEntity {
3434

3535
@OneToMany(mappedBy = "comment", cascade = CascadeType.ALL, orphanRemoval = true)
3636
private List<CommentLike> commentLikes = new ArrayList<>();
37+
38+
// -------------------- 생성자 --------------------
39+
public Comment(Post post, User user, String content) {
40+
this.post = post;
41+
this.user = user;
42+
this.content = content;
43+
}
3744
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.back.domain.board.repository;
2+
3+
import com.back.domain.board.entity.Comment;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.stereotype.Repository;
6+
7+
@Repository
8+
public interface CommentRepository extends JpaRepository<Comment, Long> {
9+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.back.domain.board.service;
2+
3+
import com.back.domain.board.dto.CommentRequest;
4+
import com.back.domain.board.dto.CommentResponse;
5+
import com.back.domain.board.entity.Comment;
6+
import com.back.domain.board.entity.Post;
7+
import com.back.domain.board.repository.CommentRepository;
8+
import com.back.domain.board.repository.PostRepository;
9+
import com.back.domain.user.entity.User;
10+
import com.back.domain.user.repository.UserRepository;
11+
import com.back.global.exception.CustomException;
12+
import com.back.global.exception.ErrorCode;
13+
import lombok.RequiredArgsConstructor;
14+
import org.springframework.stereotype.Service;
15+
import org.springframework.transaction.annotation.Transactional;
16+
17+
@Service
18+
@RequiredArgsConstructor
19+
@Transactional
20+
public class CommentService {
21+
private final CommentRepository commentRepository;
22+
private final UserRepository userRepository;
23+
private final PostRepository postRepository;
24+
25+
/**
26+
* 댓글 생성 서비스
27+
* 1. User 조회
28+
* 2. Post 조회
29+
* 3. Comment 생성
30+
* 4. Comment 저장 및 CommentResponse 반환
31+
*/
32+
public CommentResponse createComment(Long postId, CommentRequest request, Long userId) {
33+
// User 조회
34+
User user = userRepository.findById(userId)
35+
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
36+
37+
// Post 조회
38+
Post post = postRepository.findById(postId)
39+
.orElseThrow(() -> new CustomException(ErrorCode.POST_NOT_FOUND));
40+
41+
// Comment 생성
42+
Comment comment = new Comment(post, user, request.content());
43+
44+
// Comment 저장 및 응답 반환
45+
commentRepository.save(comment);
46+
return CommentResponse.from(comment);
47+
}
48+
}

0 commit comments

Comments
 (0)