Skip to content

Commit 3237c7d

Browse files
committed
feat: 북마크한 유저픽 게시글 목록 조회 기능 추가(#121)
1 parent b607fce commit 3237c7d

File tree

13 files changed

+483
-5
lines changed

13 files changed

+483
-5
lines changed

src/docs/asciidoc/user-api.adoc

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@ include::{snippetsDir}/createBookmark/3/http-response.adoc[]
207207

208208
마이페이지 > 작성한 게시글 목록 > 더보기 버튼 클릭 시 내가 작성한 유저픽 게시글 목록을 조회하는 api 입니다. +
209209
무한 스크롤, 더보기 형식으로 조회하여 모든 데이터 개수와 번호를 부여하는 Page 방식이 아닌, +
210-
다음 페이지의 데이터가 존재하는지의 여부를 함께 응답하는 Slice 방식을 사용했습니다.
210+
다음 페이지의 데이터가 존재하는지의 여부를 함께 응답하는 Slice 방식을 사용했습니다. +
211+
최신순으로 조회합니다.
211212

212213
==== Request
213214
include::{snippetsDir}/loadMyPosts/1/http-request.adoc[]
@@ -232,4 +233,37 @@ include::{snippetsDir}/loadMyPosts/3/http-response.adoc[]
232233

233234
실패 3. 요청 페이지당 개수 유효성 검증에 실패할 경우
234235

235-
include::{snippetsDir}/loadMyPosts/4/http-response.adoc[]
236+
include::{snippetsDir}/loadMyPosts/4/http-response.adoc[]
237+
238+
239+
=== **12. 내가 북마크한 유저픽 게시글 목록 조회**
240+
241+
마이페이지 > 북마크한 게시글 목록 > 더보기 버튼 클릭 시 내가 작성한 유저픽 게시글 목록을 조회하는 api 입니다. +
242+
무한 스크롤, 더보기 형식으로 조회하여 모든 데이터 개수와 번호를 부여하는 Page 방식이 아닌, +
243+
다음 페이지의 데이터가 존재하는지의 여부를 함께 응답하는 Slice 방식을 사용했습니다. +
244+
최신순으로 조회합니다.
245+
246+
==== Request
247+
include::{snippetsDir}/loadMyBookmarkPosts/1/http-request.adoc[]
248+
249+
==== Request Query Parameter Fields
250+
include::{snippetsDir}/loadMyBookmarkPosts/1/query-parameters.adoc[]
251+
252+
==== 성공 Response
253+
include::{snippetsDir}/loadMyBookmarkPosts/1/http-response.adoc[]
254+
255+
==== Response Body Fields
256+
include::{snippetsDir}/loadMyBookmarkPosts/1/response-fields.adoc[]
257+
258+
==== 실패 Response
259+
실패 1. 인증되지 않은 유저인 경우
260+
261+
include::{snippetsDir}/loadMyBookmarkPosts/2/http-response.adoc[]
262+
263+
실패 2. 요청 페이지 번호 유효성 검증에 실패할 경우
264+
265+
include::{snippetsDir}/loadMyBookmarkPosts/3/http-response.adoc[]
266+
267+
실패 3. 요청 페이지당 개수 유효성 검증에 실패할 경우
268+
269+
include::{snippetsDir}/loadMyBookmarkPosts/4/http-response.adoc[]
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.ftm.server.adapter.in.web.user.controller;
2+
3+
import com.ftm.server.adapter.in.web.user.dto.response.LoadMyPostsResponse;
4+
import com.ftm.server.application.port.in.user.LoadMyBookmarkPostUseCase;
5+
import com.ftm.server.application.query.FindBookmarksByPagingQuery;
6+
import com.ftm.server.application.vo.post.PostPagingVo;
7+
import com.ftm.server.common.exception.CustomException;
8+
import com.ftm.server.common.response.ApiResponse;
9+
import com.ftm.server.common.response.enums.ErrorResponseCode;
10+
import com.ftm.server.common.response.enums.SuccessResponseCode;
11+
import com.ftm.server.infrastructure.security.UserPrincipal;
12+
import lombok.RequiredArgsConstructor;
13+
import org.springframework.http.HttpStatus;
14+
import org.springframework.http.ResponseEntity;
15+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
16+
import org.springframework.web.bind.annotation.GetMapping;
17+
import org.springframework.web.bind.annotation.RequestParam;
18+
import org.springframework.web.bind.annotation.RestController;
19+
20+
@RestController
21+
@RequiredArgsConstructor
22+
public class LoadMyBookmarkPostController {
23+
24+
private final LoadMyBookmarkPostUseCase loadMyBookmarkPostUseCase;
25+
26+
@GetMapping("/api/users/me/bookmarks")
27+
public ResponseEntity<ApiResponse<LoadMyPostsResponse>> loadMyBookmarkPosts(
28+
@AuthenticationPrincipal UserPrincipal userPrincipal,
29+
@RequestParam(value = "page", defaultValue = "0") int page,
30+
@RequestParam(value = "size", defaultValue = "5") int size) {
31+
// 요청 페이징 데이터 유효성 검증
32+
if (page < 0) throw new CustomException(ErrorResponseCode.BAD_REQUEST_PAGING_INDEX_RANGE);
33+
if (size < 1 || size > 10)
34+
throw new CustomException(ErrorResponseCode.BAD_REQUEST_PAGING_SIZE_RANGE);
35+
36+
PostPagingVo vo =
37+
loadMyBookmarkPostUseCase.execute(
38+
FindBookmarksByPagingQuery.of(userPrincipal.getId(), page, size));
39+
40+
return ResponseEntity.status(HttpStatus.OK)
41+
.body(ApiResponse.success(SuccessResponseCode.OK, LoadMyPostsResponse.from(vo)));
42+
}
43+
}

src/main/java/com/ftm/server/adapter/out/persistence/adapter/user/UserDomainPersistenceAdapter.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ public class UserDomainPersistenceAdapter
4141
DeleteBookmarkPort,
4242
SaveBookmarkPort,
4343
CheckBookmarkPort,
44-
CheckPostPort {
44+
CheckPostPort,
45+
LoadBookmarkPort {
4546

4647
// repository
4748
private final EmailVerificationLogsRepository emailVerificationLogsRepository;
@@ -202,6 +203,13 @@ public Slice<Post> loadPostsByUserIdWithPaging(FindPostsByPagingQuery query) {
202203
return postRepository.findAllByUserIdWithPaging(query).map(postMapper::toDomainEntity);
203204
}
204205

206+
@Override
207+
public List<Post> loadPostsByIds(FindByIdsQuery query) {
208+
return postRepository.findAllById(query.getIds()).stream()
209+
.map(postMapper::toDomainEntity)
210+
.toList();
211+
}
212+
205213
@Override
206214
public List<PostImage> loadRepresentativeImagesByPostIds(FindByIdsQuery query) {
207215
return postImageRepository.findRepresentativeImagesByPostIdIn(query).stream()
@@ -272,4 +280,11 @@ public Boolean checkIfBookmarkExists(FindBookmarkByUserIdAndPostIdQuery query) {
272280
public Boolean checksPostById(FindByPostIdQuery query) {
273281
return postRepository.existsById(query.getPostId());
274282
}
283+
284+
@Override
285+
public Slice<Bookmark> loadBookmarksByUserIdWithPaging(FindBookmarksByPagingQuery query) {
286+
return bookmarkRepository
287+
.findAllByUserIdWithPaging(query)
288+
.map(bookmarkMapper::toDomainEntity);
289+
}
275290
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.ftm.server.adapter.out.persistence.repository;
2+
3+
import com.ftm.server.adapter.out.persistence.model.BookmarkJpaEntity;
4+
import com.ftm.server.application.query.FindBookmarksByPagingQuery;
5+
import org.springframework.data.domain.Slice;
6+
7+
public interface BookmarkCustomRepository {
8+
9+
Slice<BookmarkJpaEntity> findAllByUserIdWithPaging(FindBookmarksByPagingQuery query);
10+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.ftm.server.adapter.out.persistence.repository;
2+
3+
import static com.ftm.server.adapter.out.persistence.model.QBookmarkJpaEntity.bookmarkJpaEntity;
4+
5+
import com.ftm.server.adapter.out.persistence.model.BookmarkJpaEntity;
6+
import com.ftm.server.application.query.FindBookmarksByPagingQuery;
7+
import com.querydsl.jpa.impl.JPAQueryFactory;
8+
import java.util.List;
9+
import lombok.RequiredArgsConstructor;
10+
import org.springframework.data.domain.Pageable;
11+
import org.springframework.data.domain.Slice;
12+
import org.springframework.data.domain.SliceImpl;
13+
import org.springframework.stereotype.Repository;
14+
15+
@Repository
16+
@RequiredArgsConstructor
17+
public class BookmarkCustomRepositoryImpl implements BookmarkCustomRepository {
18+
19+
private final JPAQueryFactory queryFactory;
20+
21+
@Override
22+
public Slice<BookmarkJpaEntity> findAllByUserIdWithPaging(FindBookmarksByPagingQuery query) {
23+
Pageable pageable = query.getPageable();
24+
List<BookmarkJpaEntity> content =
25+
queryFactory
26+
.selectFrom(bookmarkJpaEntity)
27+
.where(bookmarkJpaEntity.user.id.eq(query.getUserId()))
28+
.offset(pageable.getOffset())
29+
.limit(pageable.getPageSize() + 1) // 한 개 더 가져와서 hasNext 판별
30+
.orderBy(bookmarkJpaEntity.createdAt.desc(), bookmarkJpaEntity.id.desc())
31+
.fetch();
32+
33+
List<BookmarkJpaEntity> result = content;
34+
35+
boolean hasNext = content.size() > pageable.getPageSize();
36+
if (hasNext) {
37+
result = content.subList(0, pageable.getPageSize()); // 초과분 제거
38+
}
39+
40+
return new SliceImpl<>(result, pageable, hasNext);
41+
}
42+
}

src/main/java/com/ftm/server/adapter/out/persistence/repository/BookmarkRepository.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
import org.springframework.data.jpa.repository.Query;
88
import org.springframework.data.repository.query.Param;
99

10-
public interface BookmarkRepository extends JpaRepository<BookmarkJpaEntity, Long> {
10+
public interface BookmarkRepository
11+
extends JpaRepository<BookmarkJpaEntity, Long>, BookmarkCustomRepository {
1112
@Modifying
1213
@Query("DELETE FROM BookmarkJpaEntity b WHERE b.user.id in (:userIds)")
1314
void deleteAllByUserIdList(@Param("userIds") List<Long> userIds);

src/main/java/com/ftm/server/adapter/out/persistence/repository/PostCustomRepositoryImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public Slice<PostJpaEntity> findAllByUserIdWithPaging(FindPostsByPagingQuery que
3939
.where(postJpaEntity.user.id.eq(query.getUserId()))
4040
.offset(pageable.getOffset())
4141
.limit(pageable.getPageSize() + 1) // 한 개 더 가져와서 hasNext 판별
42-
.orderBy(postJpaEntity.createdAt.desc())
42+
.orderBy(postJpaEntity.createdAt.desc(), postJpaEntity.id.desc())
4343
.fetch();
4444

4545
List<PostJpaEntity> result = content;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.ftm.server.application.port.in.user;
2+
3+
import com.ftm.server.application.query.FindBookmarksByPagingQuery;
4+
import com.ftm.server.application.vo.post.PostPagingVo;
5+
import com.ftm.server.common.annotation.UseCase;
6+
7+
@UseCase
8+
public interface LoadMyBookmarkPostUseCase {
9+
10+
PostPagingVo execute(FindBookmarksByPagingQuery query);
11+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.ftm.server.application.port.out.persistence.user;
2+
3+
import com.ftm.server.application.query.FindBookmarksByPagingQuery;
4+
import com.ftm.server.common.annotation.Port;
5+
import com.ftm.server.domain.entity.Bookmark;
6+
import org.springframework.data.domain.Slice;
7+
8+
@Port
9+
public interface LoadBookmarkPort {
10+
11+
Slice<Bookmark> loadBookmarksByUserIdWithPaging(FindBookmarksByPagingQuery query);
12+
}

src/main/java/com/ftm/server/application/port/out/persistence/user/LoadPostUserDomainPort.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.ftm.server.application.port.out.persistence.user;
22

3+
import com.ftm.server.application.query.FindByIdsQuery;
34
import com.ftm.server.application.query.FindByUserIdQuery;
45
import com.ftm.server.application.query.FindPostsByPagingQuery;
56
import com.ftm.server.domain.entity.Post;
@@ -11,4 +12,6 @@ public interface LoadPostUserDomainPort {
1112
List<Post> loadPostListByUser(FindByUserIdQuery query);
1213

1314
Slice<Post> loadPostsByUserIdWithPaging(FindPostsByPagingQuery query);
15+
16+
List<Post> loadPostsByIds(FindByIdsQuery query);
1417
}

0 commit comments

Comments
 (0)