feat(character): 캐릭터 상세 조회 API 추가
- 캐릭터 ID로 상세 정보를 조회하는 API 엔드포인트 추가 - 캐릭터 상세 정보 조회 서비스 메서드 구현 - 캐릭터 상세 정보 응답 DTO 클래스 추가
This commit is contained in:
parent
7e7a1122fa
commit
60172ae84d
|
@ -1,18 +1,24 @@
|
||||||
package kr.co.vividnext.sodalive.chat.character.controller
|
package kr.co.vividnext.sodalive.chat.character.controller
|
||||||
|
|
||||||
import kr.co.vividnext.sodalive.chat.character.dto.Character
|
import kr.co.vividnext.sodalive.chat.character.dto.Character
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.dto.CharacterBackgroundResponse
|
||||||
import kr.co.vividnext.sodalive.chat.character.dto.CharacterBannerResponse
|
import kr.co.vividnext.sodalive.chat.character.dto.CharacterBannerResponse
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.dto.CharacterDetailResponse
|
||||||
import kr.co.vividnext.sodalive.chat.character.dto.CharacterMainResponse
|
import kr.co.vividnext.sodalive.chat.character.dto.CharacterMainResponse
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.dto.CharacterMemoryResponse
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.dto.CharacterPersonalityResponse
|
||||||
import kr.co.vividnext.sodalive.chat.character.dto.CurationSection
|
import kr.co.vividnext.sodalive.chat.character.dto.CurationSection
|
||||||
import kr.co.vividnext.sodalive.chat.character.dto.RecentCharacter
|
import kr.co.vividnext.sodalive.chat.character.dto.RecentCharacter
|
||||||
import kr.co.vividnext.sodalive.chat.character.service.ChatCharacterBannerService
|
import kr.co.vividnext.sodalive.chat.character.service.ChatCharacterBannerService
|
||||||
import kr.co.vividnext.sodalive.chat.character.service.ChatCharacterService
|
import kr.co.vividnext.sodalive.chat.character.service.ChatCharacterService
|
||||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
|
import kr.co.vividnext.sodalive.common.SodaException
|
||||||
import kr.co.vividnext.sodalive.member.Member
|
import kr.co.vividnext.sodalive.member.Member
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
import org.springframework.data.domain.PageRequest
|
import org.springframework.data.domain.PageRequest
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||||
import org.springframework.web.bind.annotation.GetMapping
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable
|
||||||
import org.springframework.web.bind.annotation.RequestMapping
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
import org.springframework.web.bind.annotation.RestController
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
|
@ -85,4 +91,76 @@ class ChatCharacterController(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 캐릭터 상세 정보 조회 API
|
||||||
|
* 캐릭터 ID를 받아 해당 캐릭터의 상세 정보를 반환합니다.
|
||||||
|
*/
|
||||||
|
@GetMapping("/{characterId}")
|
||||||
|
fun getCharacterDetail(
|
||||||
|
@PathVariable characterId: Long,
|
||||||
|
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
|
||||||
|
) = run {
|
||||||
|
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
|
||||||
|
if (member.auth == null) throw SodaException("본인인증을 하셔야 합니다.")
|
||||||
|
|
||||||
|
// 캐릭터 상세 정보 조회
|
||||||
|
val character = service.getCharacterDetail(characterId)
|
||||||
|
?: throw SodaException("캐릭터를 찾을 수 없습니다.")
|
||||||
|
|
||||||
|
// 태그, 가치관, 취미, 목표 추출
|
||||||
|
val tags = character.tagMappings.map { it.tag.tag }
|
||||||
|
val values = character.valueMappings.map { it.value.value }
|
||||||
|
val hobbies = character.hobbyMappings.map { it.hobby.hobby }
|
||||||
|
val goals = character.goalMappings.map { it.goal.goal }
|
||||||
|
|
||||||
|
// 메모리, 성격, 배경, 관계 변환
|
||||||
|
val memories = character.memories.map {
|
||||||
|
CharacterMemoryResponse(
|
||||||
|
title = it.title,
|
||||||
|
content = it.content,
|
||||||
|
emotion = it.emotion
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val personalities = character.personalities.map {
|
||||||
|
CharacterPersonalityResponse(
|
||||||
|
trait = it.trait,
|
||||||
|
description = it.description
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val backgrounds = character.backgrounds.map {
|
||||||
|
CharacterBackgroundResponse(
|
||||||
|
topic = it.topic,
|
||||||
|
description = it.description
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val relationships = character.relationships.map { it.relationShip }
|
||||||
|
|
||||||
|
// 응답 생성
|
||||||
|
ApiResponse.ok(
|
||||||
|
CharacterDetailResponse(
|
||||||
|
characterId = character.id!!,
|
||||||
|
name = character.name,
|
||||||
|
description = character.description,
|
||||||
|
age = character.age,
|
||||||
|
gender = character.gender,
|
||||||
|
mbti = character.mbti,
|
||||||
|
speechPattern = character.speechPattern,
|
||||||
|
speechStyle = character.speechStyle,
|
||||||
|
appearance = character.appearance,
|
||||||
|
imageUrl = "$imageHost/${character.imagePath ?: "profile/default-profile.png"}",
|
||||||
|
memories = memories,
|
||||||
|
personalities = personalities,
|
||||||
|
backgrounds = backgrounds,
|
||||||
|
relationships = relationships,
|
||||||
|
tags = tags,
|
||||||
|
values = values,
|
||||||
|
hobbies = hobbies,
|
||||||
|
goals = goals
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package kr.co.vividnext.sodalive.chat.character.dto
|
||||||
|
|
||||||
|
data class CharacterDetailResponse(
|
||||||
|
val characterId: Long,
|
||||||
|
val name: String,
|
||||||
|
val description: String,
|
||||||
|
val age: Int?,
|
||||||
|
val gender: String?,
|
||||||
|
val mbti: String?,
|
||||||
|
val speechPattern: String?,
|
||||||
|
val speechStyle: String?,
|
||||||
|
val appearance: String?,
|
||||||
|
val imageUrl: String,
|
||||||
|
val memories: List<CharacterMemoryResponse> = emptyList(),
|
||||||
|
val personalities: List<CharacterPersonalityResponse> = emptyList(),
|
||||||
|
val backgrounds: List<CharacterBackgroundResponse> = emptyList(),
|
||||||
|
val relationships: List<String> = emptyList(),
|
||||||
|
val tags: List<String> = emptyList(),
|
||||||
|
val values: List<String> = emptyList(),
|
||||||
|
val hobbies: List<String> = emptyList(),
|
||||||
|
val goals: List<String> = emptyList()
|
||||||
|
)
|
||||||
|
|
||||||
|
data class CharacterMemoryResponse(
|
||||||
|
val title: String,
|
||||||
|
val content: String,
|
||||||
|
val emotion: String
|
||||||
|
)
|
||||||
|
|
||||||
|
data class CharacterPersonalityResponse(
|
||||||
|
val trait: String,
|
||||||
|
val description: String
|
||||||
|
)
|
||||||
|
|
||||||
|
data class CharacterBackgroundResponse(
|
||||||
|
val topic: String,
|
||||||
|
val description: String
|
||||||
|
)
|
|
@ -172,6 +172,27 @@ class ChatCharacterService(
|
||||||
return chatCharacterRepository.findById(id).orElse(null)
|
return chatCharacterRepository.findById(id).orElse(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 캐릭터 ID로 상세 정보를 조회합니다.
|
||||||
|
* 태그, 가치관, 취미, 목표 등의 관계 정보도 함께 조회합니다.
|
||||||
|
*/
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
fun getCharacterDetail(id: Long): ChatCharacter? {
|
||||||
|
val character = findById(id) ?: return null
|
||||||
|
|
||||||
|
// 지연 로딩된 관계 데이터 초기화
|
||||||
|
character.tagMappings.size
|
||||||
|
character.valueMappings.size
|
||||||
|
character.hobbyMappings.size
|
||||||
|
character.goalMappings.size
|
||||||
|
character.memories.size
|
||||||
|
character.personalities.size
|
||||||
|
character.backgrounds.size
|
||||||
|
character.relationships.size
|
||||||
|
|
||||||
|
return character
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 캐릭터 생성 및 관련 엔티티 연결
|
* 캐릭터 생성 및 관련 엔티티 연결
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue