Skip to content

Commit ec74332

Browse files
committed
Feat: 게시글 다건/단건 조회 API 구현
1 parent 9a64bb6 commit ec74332

File tree

8 files changed

+461
-5
lines changed

8 files changed

+461
-5
lines changed

src/main/java/com/back/domain/board/controller/PostController.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package com.back.domain.board.controller;
22

3-
import com.back.domain.board.dto.PostRequest;
4-
import com.back.domain.board.dto.PostResponse;
3+
import com.back.domain.board.dto.*;
54
import com.back.domain.board.service.PostService;
65
import com.back.global.common.dto.RsData;
76
import com.back.global.security.user.CustomUserDetails;
87
import jakarta.validation.Valid;
98
import lombok.RequiredArgsConstructor;
9+
import org.springframework.data.domain.Pageable;
10+
import org.springframework.data.domain.Sort;
11+
import org.springframework.data.web.PageableDefault;
1012
import org.springframework.http.HttpStatus;
1113
import org.springframework.http.ResponseEntity;
1214
import org.springframework.security.core.annotation.AuthenticationPrincipal;
@@ -32,4 +34,35 @@ public ResponseEntity<RsData<PostResponse>> createPost(
3234
response
3335
));
3436
}
37+
38+
// 게시글 다건 조회
39+
@GetMapping
40+
public ResponseEntity<RsData<PageResponse<PostListResponse>>> getPosts(
41+
@PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable,
42+
@RequestParam(required = false) String keyword,
43+
@RequestParam(required = false) String searchType,
44+
@RequestParam(required = false) Long categoryId
45+
) {
46+
PageResponse<PostListResponse> response = postService.getPosts(keyword, searchType, categoryId, pageable);
47+
return ResponseEntity
48+
.status(HttpStatus.OK)
49+
.body(RsData.success(
50+
"게시글 목록이 조회되었습니다.",
51+
response
52+
));
53+
}
54+
55+
// 게시글 단건 조회
56+
@GetMapping("/{postId}")
57+
public ResponseEntity<RsData<PostDetailResponse>> getPost(
58+
@PathVariable Long postId
59+
) {
60+
PostDetailResponse response = postService.getPost(postId);
61+
return ResponseEntity
62+
.status(HttpStatus.OK)
63+
.body(RsData.success(
64+
"게시글이 조회되었습니다.",
65+
response
66+
));
67+
}
3568
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.back.domain.board.dto;
2+
3+
import org.springframework.data.domain.Page;
4+
5+
import java.util.List;
6+
7+
/**
8+
* 페이지 응답 DTO
9+
*
10+
* @param items 목록 데이터
11+
* @param page 현재 페이지 번호
12+
* @param size 페이지 크기
13+
* @param totalElements 전체 요소 수
14+
* @param totalPages 전체 페이지 수
15+
* @param last 마지막 페이지 여부
16+
* @param <T> 제네릭 타입
17+
*/
18+
public record PageResponse<T>(
19+
List<T> items,
20+
int page,
21+
int size,
22+
long totalElements,
23+
int totalPages,
24+
boolean last
25+
) {
26+
public static <T> PageResponse<T> from(Page<T> page) {
27+
return new PageResponse<>(
28+
page.getContent(),
29+
page.getNumber(),
30+
page.getSize(),
31+
page.getTotalElements(),
32+
page.getTotalPages(),
33+
page.isLast()
34+
);
35+
}
36+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.back.domain.board.dto;
2+
3+
import com.back.domain.board.entity.Post;
4+
5+
import java.time.LocalDateTime;
6+
import java.util.List;
7+
8+
/**
9+
* 게시글 상세 응답 DTO
10+
*
11+
* @param postId 게시글 ID
12+
* @param author 작성자 정보
13+
* @param title 게시글 제목
14+
* @param content 게시글 내용
15+
* @param categories 게시글 카테고리 목록
16+
* @param likeCount 좋아요 수
17+
* @param bookmarkCount 북마크 수
18+
* @param commentCount 댓글 수
19+
* @param createdAt 게시글 생성 일시
20+
* @param updatedAt 게시글 수정 일시
21+
*/
22+
public record PostDetailResponse(
23+
Long postId,
24+
AuthorResponse author,
25+
String title,
26+
String content,
27+
List<CategoryResponse> categories,
28+
long likeCount,
29+
long bookmarkCount,
30+
long commentCount,
31+
LocalDateTime createdAt,
32+
LocalDateTime updatedAt
33+
) {
34+
public static PostDetailResponse from(Post post) {
35+
return new PostDetailResponse(
36+
post.getId(),
37+
AuthorResponse.from(post.getUser()),
38+
post.getTitle(),
39+
post.getContent(),
40+
post.getCategories().stream()
41+
.map(CategoryResponse::from)
42+
.toList(),
43+
post.getPostLikes().size(),
44+
post.getPostBookmarks().size(),
45+
post.getComments().size(),
46+
post.getCreatedAt(),
47+
post.getUpdatedAt()
48+
);
49+
}
50+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.back.domain.board.dto;
2+
3+
import com.querydsl.core.annotations.QueryProjection;
4+
import lombok.Getter;
5+
import lombok.Setter;
6+
7+
import java.time.LocalDateTime;
8+
import java.util.List;
9+
10+
/**
11+
* 게시글 목록 응답 DTO
12+
*/
13+
@Getter
14+
public class PostListResponse {
15+
private final Long postId;
16+
private final AuthorResponse author;
17+
private final String title;
18+
private final long likeCount;
19+
private final long bookmarkCount;
20+
private final long commentCount;
21+
private final LocalDateTime createdAt;
22+
private final LocalDateTime updatedAt;
23+
24+
@Setter
25+
private List<CategoryResponse> categories;
26+
27+
@QueryProjection
28+
public PostListResponse(Long postId,
29+
AuthorResponse author,
30+
String title,
31+
List<CategoryResponse> categories,
32+
long likeCount,
33+
long bookmarkCount,
34+
long commentCount,
35+
LocalDateTime createdAt,
36+
LocalDateTime updatedAt) {
37+
this.postId = postId;
38+
this.author = author;
39+
this.title = title;
40+
this.categories = categories;
41+
this.likeCount = likeCount;
42+
this.bookmarkCount = bookmarkCount;
43+
this.commentCount = commentCount;
44+
this.createdAt = createdAt;
45+
this.updatedAt = updatedAt;
46+
}
47+
48+
/**
49+
* 작성자 응답 DTO
50+
*/
51+
@Getter
52+
public static class AuthorResponse {
53+
private final Long id;
54+
private final String nickname;
55+
56+
@QueryProjection
57+
public AuthorResponse(Long userId, String nickname) {
58+
this.id = userId;
59+
this.nickname = nickname;
60+
}
61+
}
62+
63+
/**
64+
* 카테고리 응답 DTO
65+
*/
66+
@Getter
67+
public static class CategoryResponse {
68+
private final Long id;
69+
private final String name;
70+
71+
@QueryProjection
72+
public CategoryResponse(Long id, String name) {
73+
this.id = id;
74+
this.name = name;
75+
}
76+
}
77+
}

src/main/java/com/back/domain/board/repository/PostRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
import org.springframework.stereotype.Repository;
66

77
@Repository
8-
public interface PostRepository extends JpaRepository<Post, Long> {
8+
public interface PostRepository extends JpaRepository<Post, Long>, PostRepositoryCustom {
99
}
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.dto.PostListResponse;
4+
import org.springframework.data.domain.Page;
5+
import org.springframework.data.domain.Pageable;
6+
7+
public interface PostRepositoryCustom {
8+
Page<PostListResponse> searchPosts(String keyword, String searchType, Long categoryId, Pageable pageable);
9+
}

0 commit comments

Comments
 (0)