Skip to content

Commit adcd57c

Browse files
committed
feat: 특정 다이어리 댓글 전체 조회(커서 기반) API 구현
1 parent e0d6dc9 commit adcd57c

File tree

7 files changed

+112
-40
lines changed

7 files changed

+112
-40
lines changed

src/main/java/com/example/log4u/domain/comment/Comment.java

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/main/java/com/example/log4u/domain/comment/controller/CommentController.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@
22

33
import org.springframework.http.ResponseEntity;
44
import org.springframework.web.bind.annotation.DeleteMapping;
5+
import org.springframework.web.bind.annotation.GetMapping;
56
import org.springframework.web.bind.annotation.PathVariable;
67
import org.springframework.web.bind.annotation.PostMapping;
78
import org.springframework.web.bind.annotation.RequestBody;
89
import org.springframework.web.bind.annotation.RequestMapping;
10+
import org.springframework.web.bind.annotation.RequestParam;
911
import org.springframework.web.bind.annotation.RestController;
1012

13+
import com.example.log4u.common.dto.PageResponse;
1114
import com.example.log4u.domain.comment.dto.request.CommentCreateRequestDto;
1215
import com.example.log4u.domain.comment.dto.response.CommentCreateResponseDto;
16+
import com.example.log4u.domain.comment.dto.response.CommentResponseDto;
1317
import com.example.log4u.domain.comment.service.CommentService;
1418

1519
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -39,4 +43,14 @@ public ResponseEntity<Void> deleteComment(@PathVariable Long commentId) {
3943
commentService.deleteComment(userId, commentId);
4044
return ResponseEntity.noContent().build();
4145
}
46+
47+
@GetMapping("/{diaryId}")
48+
public ResponseEntity<PageResponse<CommentResponseDto>> getCommentListByDiary(
49+
@PathVariable Long diaryId,
50+
@RequestParam(required = false) Long cursorCommentId,
51+
@RequestParam(defaultValue = "5") int size
52+
) {
53+
PageResponse<CommentResponseDto> response = commentService.getCommentListByDiary(diaryId, cursorCommentId, size);
54+
return ResponseEntity.ok(response);
55+
}
4256
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.example.log4u.domain.comment.dto.response;
2+
3+
import com.example.log4u.domain.comment.entity.Comment;
4+
5+
public record CommentResponseDto(
6+
Long commentId,
7+
String content
8+
) {
9+
public static CommentResponseDto of(Comment comment) {
10+
return new CommentResponseDto(
11+
comment.getCommentId(),
12+
comment.getContent()
13+
);
14+
}
15+
}
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
package com.example.log4u.domain.comment.repository;
22

3+
import java.time.LocalDateTime;
4+
import java.util.List;
5+
6+
import org.springframework.data.domain.Pageable;
37
import org.springframework.data.jpa.repository.JpaRepository;
8+
import org.springframework.data.jpa.repository.Query;
9+
import org.springframework.data.repository.query.Param;
410

511
import com.example.log4u.domain.comment.entity.Comment;
612

7-
public interface CommentRepository extends JpaRepository<Comment, Long> {
8-
13+
public interface CommentRepository extends JpaRepository<Comment, Long>, CommentRepositoryCustom {
914
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.example.log4u.domain.comment.repository;
2+
3+
import org.springframework.data.domain.Pageable;
4+
import org.springframework.data.domain.Slice;
5+
6+
import com.example.log4u.domain.comment.entity.Comment;
7+
8+
public interface CommentRepositoryCustom {
9+
10+
Slice<Comment> findByDiaryIdWithCursor(Long diaryId, Long cursorCommentId, Pageable pageable);
11+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.example.log4u.domain.comment.repository;
2+
3+
import static com.example.log4u.domain.comment.entity.QComment.*;
4+
5+
import java.util.List;
6+
7+
import org.springframework.data.domain.Pageable;
8+
import org.springframework.data.domain.Slice;
9+
import org.springframework.data.domain.SliceImpl;
10+
import org.springframework.stereotype.Repository;
11+
12+
import com.example.log4u.domain.comment.entity.Comment;
13+
import com.querydsl.jpa.impl.JPAQueryFactory;
14+
15+
import lombok.RequiredArgsConstructor;
16+
17+
@Repository
18+
@RequiredArgsConstructor
19+
public class CommentRepositoryImpl implements CommentRepositoryCustom {
20+
21+
private final JPAQueryFactory queryFactory;
22+
23+
@Override
24+
public Slice<Comment> findByDiaryIdWithCursor(Long diaryId, Long cursorCommentId, Pageable pageable) {
25+
List<Comment> result = queryFactory
26+
.selectFrom(comment)
27+
.where(
28+
comment.diaryId.eq(diaryId),
29+
cursorCommentId != null ? comment.commentId.lt(cursorCommentId) : null
30+
)
31+
.orderBy(comment.commentId.desc())
32+
.limit(pageable.getPageSize() + 1) // 커서 기반 페이징
33+
.fetch();
34+
35+
boolean hasNext = result.size() > pageable.getPageSize();
36+
List<Comment> content = hasNext ? result.subList(0, pageable.getPageSize()) : result;
37+
38+
return new SliceImpl<>(content, pageable, hasNext);
39+
}
40+
}

src/main/java/com/example/log4u/domain/comment/service/CommentService.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
package com.example.log4u.domain.comment.service;
22

3+
import java.util.List;
4+
5+
import org.springframework.data.domain.PageRequest;
6+
import org.springframework.data.domain.Pageable;
7+
import org.springframework.data.domain.Slice;
8+
import org.springframework.data.domain.SliceImpl;
39
import org.springframework.stereotype.Service;
410
import org.springframework.transaction.annotation.Transactional;
511

12+
import com.example.log4u.common.dto.PageResponse;
613
import com.example.log4u.domain.comment.dto.request.CommentCreateRequestDto;
714
import com.example.log4u.domain.comment.dto.response.CommentCreateResponseDto;
15+
import com.example.log4u.domain.comment.dto.response.CommentResponseDto;
816
import com.example.log4u.domain.comment.entity.Comment;
917
import com.example.log4u.domain.comment.exception.NotFoundCommentException;
1018
import com.example.log4u.domain.comment.exception.UnauthorizedAccessException;
@@ -22,7 +30,7 @@ public class CommentService {
2230

2331
@Transactional
2432
public CommentCreateResponseDto addComment(Long userId, CommentCreateRequestDto requestDto) {
25-
checkDiaryExists(requestDto);
33+
checkDiaryExists(requestDto.diaryId());
2634
Comment comment = requestDto.toEntity(userId);
2735
commentRepository.save(comment);
2836
return CommentCreateResponseDto.of(comment);
@@ -35,8 +43,8 @@ public void deleteComment(Long userId, Long commentId) {
3543
commentRepository.delete(comment);
3644
}
3745

38-
private void checkDiaryExists(CommentCreateRequestDto requestDto) {
39-
diaryService.checkDiaryExists(requestDto.diaryId());
46+
private void checkDiaryExists(Long diaryId) {
47+
diaryService.checkDiaryExists(diaryId);
4048
}
4149

4250
private void validateCommentOwner(Long userId, Comment comment) {
@@ -49,4 +57,18 @@ private Comment getComment(Long commentId) {
4957
return commentRepository.findById(commentId)
5058
.orElseThrow(NotFoundCommentException::new);
5159
}
60+
61+
@Transactional(readOnly = true)
62+
public PageResponse<CommentResponseDto> getCommentListByDiary(Long diaryId, Long cursorCommentId, int size) {
63+
checkDiaryExists(diaryId);
64+
Pageable pageable = PageRequest.of(0, size);
65+
Slice<Comment> slice = commentRepository.findByDiaryIdWithCursor(diaryId, cursorCommentId, pageable);
66+
67+
List<CommentResponseDto> dtoList = slice.getContent().stream()
68+
.map(CommentResponseDto::of)
69+
.toList();
70+
71+
Long nextCursor = slice.hasNext() ? dtoList.getLast().commentId() : null;
72+
return PageResponse.of(new SliceImpl<>(dtoList, pageable, slice.hasNext()), nextCursor);
73+
}
5274
}

0 commit comments

Comments
 (0)