diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/OriginalWorkRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/OriginalWorkRepository.kt index 97856f5..4e40d33 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/OriginalWorkRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/OriginalWorkRepository.kt @@ -33,13 +33,13 @@ interface OriginalWorkRepository : JpaRepository { ): List /** - * 앱용 원작 목록 조회 + * 앱용 원작 목록 조회 (페이징) * - 소프트 삭제 제외 * - includeAdult=false이면 19금 제외 * - 활성 캐릭터가 하나라도 연결된 원작만 조회 */ @Query( - """ + value = """ SELECT ow FROM OriginalWork ow WHERE ow.isDeleted = false AND (:includeAdult = true OR ow.isAdult = false) @@ -48,7 +48,16 @@ interface OriginalWorkRepository : JpaRepository { WHERE c.originalWork = ow AND c.isActive = true ) ORDER BY ow.createdAt DESC + """, + countQuery = """ + SELECT COUNT(ow) FROM OriginalWork ow + WHERE ow.isDeleted = false + AND (:includeAdult = true OR ow.isAdult = false) + AND EXISTS ( + SELECT 1 FROM ChatCharacter c + WHERE c.originalWork = ow AND c.isActive = true + ) """ ) - fun findAllForApp(@Param("includeAdult") includeAdult: Boolean): List + fun findAllForAppPage(@Param("includeAdult") includeAdult: Boolean, pageable: Pageable): Page } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/controller/OriginalWorkController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/controller/OriginalWorkController.kt index e8b6301..62ccf19 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/controller/OriginalWorkController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/controller/OriginalWorkController.kt @@ -31,20 +31,23 @@ class OriginalWorkController( ) { /** - * 원작 목록 + * 원작 목록 (페이징) * - 로그인 불필요 * - 본인인증하지 않은 경우 19금 제외 * - 활성 캐릭터가 하나라도 연결된 원작만 노출 + * - 요청: page(기본 0), size(기본 20) * - 반환: totalCount + [imageUrl, title, contentType] */ @GetMapping("/list") fun list( + @RequestParam(defaultValue = "0") page: Int, + @RequestParam(defaultValue = "20") size: Int, @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? ) = run { val includeAdult = member?.auth != null - val list = queryService.listForApp(includeAdult) - val content = list.map { OriginalWorkListItemResponse.from(it, imageHost) } - ApiResponse.ok(OriginalWorkListResponse(totalCount = content.size.toLong(), content = content)) + val pageRes = queryService.listForAppPage(includeAdult, page, size) + val content = pageRes.content.map { OriginalWorkListItemResponse.from(it, imageHost) } + ApiResponse.ok(OriginalWorkListResponse(totalCount = pageRes.totalElements, content = content)) } /** diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/service/OriginalWorkQueryService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/service/OriginalWorkQueryService.kt index 01dc3e6..b6b88f5 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/service/OriginalWorkQueryService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/service/OriginalWorkQueryService.kt @@ -21,12 +21,21 @@ class OriginalWorkQueryService( private val chatCharacterRepository: ChatCharacterRepository ) { /** - * 앱용 원작 목록 조회 + * 앱용 원작 목록 조회 (페이징) * @param includeAdult true면 19금 포함, false면 제외 + * @param page 페이지 번호(0부터) + * @param size 페이지 크기(기본 20, 최대 50) */ @Transactional(readOnly = true) - fun listForApp(includeAdult: Boolean): List { - return originalWorkRepository.findAllForApp(includeAdult) + fun listForAppPage(includeAdult: Boolean, page: Int = 0, size: Int = 20): Page { + val safePage = if (page < 0) 0 else page + val safeSize = when { + size <= 0 -> 20 + size > 50 -> 50 + else -> size + } + val pageable = PageRequest.of(safePage, safeSize, Sort.by("createdAt").descending()) + return originalWorkRepository.findAllForAppPage(includeAdult, pageable) } /**