feat(admin-character-list): 캐릭터 검색에 페이징 추가

This commit is contained in:
Klaus 2025-09-18 19:29:34 +09:00
parent 67186bba55
commit eb2d093b02
3 changed files with 12 additions and 43 deletions

View File

@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.admin.chat.character
import com.amazonaws.services.s3.model.ObjectMetadata import com.amazonaws.services.s3.model.ObjectMetadata
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import kr.co.vividnext.sodalive.admin.chat.character.dto.ChatCharacterRegisterRequest import kr.co.vividnext.sodalive.admin.chat.character.dto.ChatCharacterRegisterRequest
import kr.co.vividnext.sodalive.admin.chat.character.dto.ChatCharacterSearchListPageResponse
import kr.co.vividnext.sodalive.admin.chat.character.dto.ChatCharacterUpdateRequest import kr.co.vividnext.sodalive.admin.chat.character.dto.ChatCharacterUpdateRequest
import kr.co.vividnext.sodalive.admin.chat.character.dto.ExternalApiResponse import kr.co.vividnext.sodalive.admin.chat.character.dto.ExternalApiResponse
import kr.co.vividnext.sodalive.admin.chat.character.service.AdminChatCharacterService import kr.co.vividnext.sodalive.admin.chat.character.service.AdminChatCharacterService
@ -73,14 +74,21 @@ class AdminChatCharacterController(
/** /**
* 캐릭터 검색(관리자) * 캐릭터 검색(관리자)
* - 이름/설명/MBTI/태그 기준 부분 검색, 활성 캐릭터만 대상 * - 이름/설명/MBTI/태그 기준 부분 검색, 활성 캐릭터만 대상
* - 페이징 제거: 전체 목록 반환 * - 페이징 지원: page, size 파라미터 사용
*/ */
@GetMapping("/search") @GetMapping("/search")
fun searchCharacters( fun searchCharacters(
@RequestParam("searchTerm") searchTerm: String @RequestParam("searchTerm") searchTerm: String,
@RequestParam(defaultValue = "0") page: Int,
@RequestParam(defaultValue = "20") size: Int
) = run { ) = run {
val list = adminService.searchCharactersAll(searchTerm, imageHost) val pageable = adminService.createDefaultPageRequest(page, size)
ApiResponse.ok(list) val resultPage = adminService.searchCharacters(searchTerm, pageable, imageHost)
val response = ChatCharacterSearchListPageResponse(
totalCount = resultPage.totalElements,
content = resultPage.content
)
ApiResponse.ok(response)
} }
/** /**

View File

@ -76,20 +76,4 @@ class AdminChatCharacterService(
val characters = chatCharacterRepository.searchCharacters(searchTerm, pageable) val characters = chatCharacterRepository.searchCharacters(searchTerm, pageable)
return characters.map { ChatCharacterSearchResponse.from(it, imageHost) } return characters.map { ChatCharacterSearchResponse.from(it, imageHost) }
} }
/**
* 캐릭터 검색 (이름, 설명, MBTI, 태그 기반) - 무페이징
*
* @param searchTerm 검색어
* @param imageHost 이미지 호스트 URL
* @return 검색된 캐릭터 목록 (전체)
*/
@Transactional(readOnly = true)
fun searchCharactersAll(
searchTerm: String,
imageHost: String = ""
): List<ChatCharacterSearchResponse> {
val characters = chatCharacterRepository.searchCharactersNoPaging(searchTerm)
return characters.map { ChatCharacterSearchResponse.from(it, imageHost) }
}
} }

View File

@ -12,7 +12,6 @@ import org.springframework.stereotype.Repository
interface ChatCharacterRepository : JpaRepository<ChatCharacter, Long> { interface ChatCharacterRepository : JpaRepository<ChatCharacter, Long> {
fun findByName(name: String): ChatCharacter? fun findByName(name: String): ChatCharacter?
fun findByIsActiveTrue(pageable: Pageable): Page<ChatCharacter> fun findByIsActiveTrue(pageable: Pageable): Page<ChatCharacter>
fun findByOriginalWorkIdAndIsActiveTrueOrderByCreatedAtDesc(originalWorkId: Long): List<ChatCharacter>
fun findByOriginalWorkIdAndIsActiveTrue(originalWorkId: Long, pageable: Pageable): Page<ChatCharacter> fun findByOriginalWorkIdAndIsActiveTrue(originalWorkId: Long, pageable: Pageable): Page<ChatCharacter>
/** /**
@ -54,28 +53,6 @@ interface ChatCharacterRepository : JpaRepository<ChatCharacter, Long> {
pageable: Pageable pageable: Pageable
): Page<ChatCharacter> ): Page<ChatCharacter>
/**
* 이름, 설명, MBTI, 태그로 캐릭터 검색 - 무페이징 전체 목록
*/
@Query(
"""
SELECT DISTINCT c FROM ChatCharacter c
LEFT JOIN c.tagMappings tm
LEFT JOIN tm.tag t
WHERE c.isActive = true AND
(
LOWER(c.name) LIKE LOWER(CONCAT('%', :searchTerm, '%')) OR
LOWER(c.description) LIKE LOWER(CONCAT('%', :searchTerm, '%')) OR
(c.mbti IS NOT NULL AND LOWER(c.mbti) LIKE LOWER(CONCAT('%', :searchTerm, '%'))) OR
(t.tag IS NOT NULL AND LOWER(t.tag) LIKE LOWER(CONCAT('%', :searchTerm, '%')))
)
ORDER BY c.createdAt DESC
"""
)
fun searchCharactersNoPaging(
@Param("searchTerm") searchTerm: String
): List<ChatCharacter>
/** /**
* 특정 캐릭터와 태그를 공유하는 다른 캐릭터를 무작위로 조회 (현재 캐릭터 제외) * 특정 캐릭터와 태그를 공유하는 다른 캐릭터를 무작위로 조회 (현재 캐릭터 제외)
*/ */