feat(chat-banner): 다국어 캐릭터 배너 등록과 노출을 지원한다
배너를 언어별로 저장하고 요청 언어 우선 조회 후 한국어로 fallback 하도록 맞춘다.
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
package kr.co.vividnext.sodalive.chat.character
|
||||
|
||||
import kr.co.vividnext.sodalive.common.BaseEntity
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import javax.persistence.Column
|
||||
import javax.persistence.Entity
|
||||
import javax.persistence.EnumType
|
||||
import javax.persistence.Enumerated
|
||||
import javax.persistence.FetchType
|
||||
import javax.persistence.JoinColumn
|
||||
import javax.persistence.ManyToOne
|
||||
@@ -24,6 +28,10 @@ class ChatCharacterBanner(
|
||||
// 정렬 순서 (낮을수록 먼저 표시)
|
||||
var sortOrder: Int = 0,
|
||||
|
||||
@Column(nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
var lang: Lang = Lang.KO,
|
||||
|
||||
// 활성화 여부 (소프트 삭제용)
|
||||
var isActive: Boolean = true
|
||||
) : BaseEntity()
|
||||
|
||||
@@ -62,7 +62,7 @@ class ChatCharacterController(
|
||||
val isAdultAccessible = resolveIsAdultAccessible(member)
|
||||
|
||||
// 배너 조회 (최대 10개)
|
||||
val banners = bannerService.getActiveBanners(PageRequest.of(0, 10))
|
||||
val banners = bannerService.getDisplayBanners(PageRequest.of(0, 10), langContext.lang)
|
||||
.content
|
||||
.map {
|
||||
CharacterBannerResponse(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.chat.character.repository
|
||||
|
||||
import kr.co.vividnext.sodalive.chat.character.ChatCharacterBanner
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import org.springframework.data.domain.Page
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
@@ -12,6 +13,8 @@ interface ChatCharacterBannerRepository : JpaRepository<ChatCharacterBanner, Lon
|
||||
// 활성화된 배너 목록 조회 (정렬 순서대로)
|
||||
fun findByIsActiveTrueOrderBySortOrderAsc(pageable: Pageable): Page<ChatCharacterBanner>
|
||||
|
||||
fun findByIsActiveTrueAndLangOrderBySortOrderAsc(lang: Lang, pageable: Pageable): Page<ChatCharacterBanner>
|
||||
|
||||
// 활성화된 배너 중 최대 정렬 순서 값 조회
|
||||
@Query("SELECT MAX(b.sortOrder) FROM ChatCharacterBanner b WHERE b.isActive = true")
|
||||
fun findMaxSortOrder(): Int?
|
||||
|
||||
@@ -4,6 +4,7 @@ import kr.co.vividnext.sodalive.chat.character.ChatCharacterBanner
|
||||
import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterBannerRepository
|
||||
import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterRepository
|
||||
import kr.co.vividnext.sodalive.common.SodaException
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import org.springframework.data.domain.Page
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.stereotype.Service
|
||||
@@ -21,6 +22,19 @@ class ChatCharacterBannerService(
|
||||
return bannerRepository.findByIsActiveTrueOrderBySortOrderAsc(pageable)
|
||||
}
|
||||
|
||||
fun getDisplayBanners(pageable: Pageable, lang: Lang): Page<ChatCharacterBanner> {
|
||||
if (lang == Lang.KO) {
|
||||
return bannerRepository.findByIsActiveTrueAndLangOrderBySortOrderAsc(Lang.KO, pageable)
|
||||
}
|
||||
|
||||
val localizedBanners = bannerRepository.findByIsActiveTrueAndLangOrderBySortOrderAsc(lang, pageable)
|
||||
return if (localizedBanners.hasContent()) {
|
||||
localizedBanners
|
||||
} else {
|
||||
bannerRepository.findByIsActiveTrueAndLangOrderBySortOrderAsc(Lang.KO, pageable)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 배너 상세 조회
|
||||
*/
|
||||
@@ -37,7 +51,10 @@ class ChatCharacterBannerService(
|
||||
* @return 등록된 배너
|
||||
*/
|
||||
@Transactional
|
||||
fun registerBanner(characterId: Long, imagePath: String): ChatCharacterBanner {
|
||||
fun registerBanner(characterId: Long, imagePath: String, lang: Lang? = null): ChatCharacterBanner {
|
||||
val finalLang = lang ?: Lang.KO
|
||||
validateRegisterLang(finalLang)
|
||||
|
||||
val character = characterRepository.findById(characterId)
|
||||
.orElseThrow { SodaException(messageKey = "chat.character.not_found") }
|
||||
|
||||
@@ -51,12 +68,21 @@ class ChatCharacterBannerService(
|
||||
val banner = ChatCharacterBanner(
|
||||
imagePath = imagePath,
|
||||
chatCharacter = character,
|
||||
sortOrder = finalSortOrder
|
||||
sortOrder = finalSortOrder,
|
||||
lang = finalLang
|
||||
)
|
||||
|
||||
return bannerRepository.save(banner)
|
||||
}
|
||||
|
||||
private fun validateRegisterLang(lang: Lang) {
|
||||
if (lang == Lang.KO || lang == Lang.EN || lang == Lang.JA) {
|
||||
return
|
||||
}
|
||||
|
||||
throw SodaException(messageKey = "common.error.invalid_request")
|
||||
}
|
||||
|
||||
/**
|
||||
* 배너 수정
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user