콘텐츠 메인 캐싱 전략 변경 - repository 에 있던 @Cacheable 을 service 코드로 이동

This commit is contained in:
Klaus 2023-10-27 01:08:40 +09:00
parent 3ec16b5045
commit 1c7fdfac69
3 changed files with 119 additions and 79 deletions

View File

@ -4,10 +4,13 @@ import org.springframework.beans.factory.annotation.Value
import org.springframework.cache.annotation.EnableCaching import org.springframework.cache.annotation.EnableCaching
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Configuration
import org.springframework.data.redis.cache.RedisCacheConfiguration
import org.springframework.data.redis.cache.RedisCacheManager
import org.springframework.data.redis.connection.RedisConnectionFactory import org.springframework.data.redis.connection.RedisConnectionFactory
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory
import org.springframework.data.redis.core.RedisTemplate import org.springframework.data.redis.core.RedisTemplate
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories import org.springframework.data.redis.repository.configuration.EnableRedisRepositories
import java.time.Duration
@Configuration @Configuration
@EnableCaching @EnableCaching
@ -29,4 +32,21 @@ class RedisConfig(
redisTemplate.setConnectionFactory(redisConnectionFactory()) redisTemplate.setConnectionFactory(redisConnectionFactory())
return redisTemplate return redisTemplate
} }
@Bean
fun cacheManager(redisConnectionFactory: RedisConnectionFactory): RedisCacheManager {
val defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
val cacheConfigMap = mutableMapOf<String, RedisCacheConfiguration>()
cacheConfigMap["default"] = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
cacheConfigMap["cache_ttl_3_days"] = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(3))
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(defaultCacheConfig)
.withInitialCacheConfigurations(cacheConfigMap)
.build()
}
} }

View File

@ -10,6 +10,7 @@ import kr.co.vividnext.sodalive.event.EventItem
import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
import org.springframework.beans.factory.annotation.Value import org.springframework.beans.factory.annotation.Value
import org.springframework.cache.annotation.Cacheable
import org.springframework.data.domain.Pageable import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import java.time.DayOfWeek import java.time.DayOfWeek
@ -29,21 +30,103 @@ class AudioContentMainService(
) { ) {
fun getMain(member: Member): GetAudioContentMainResponse { fun getMain(member: Member): GetAudioContentMainResponse {
val isAdult = member.auth != null val isAdult = member.auth != null
val memberId = member.id!!
// 2주일 이내에 콘텐츠를 올린 크리에이터 20명 조회 // 2주일 이내에 콘텐츠를 올린 크리에이터 20명 조회
val newContentUploadCreatorList = repository.getNewContentUploadCreatorList( val newContentUploadCreatorList = getNewContentUploadCreatorList(memberId = memberId, isAdult = isAdult)
val bannerList = getAudioContentMainBannerList(memberId = memberId, isAdult = isAdult)
// 구매목록 20개
val orderList = orderService.getAudioContentMainOrderList(
member = member,
limit = 20
)
// 콘텐츠 테마
val themeList = audioContentThemeRepository.getActiveThemeOfContent(isAdult = isAdult)
// 새 콘텐츠 20개 - 시간 내림차순 정렬
val newContentList = repository.findByTheme(
cloudfrontHost = imageHost, cloudfrontHost = imageHost,
isAdult = isAdult isAdult = isAdult
) )
.asSequence() .asSequence()
.filter { !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.creatorId) } .filter { !blockMemberRepository.isBlocked(blockedMemberId = memberId, memberId = it.creatorId) }
.toList() .toList()
val bannerList = repository.getAudioContentMainBannerList(isAdult = isAdult) val curationList = getAudioContentCurationList(memberId = memberId, isAdult = isAdult)
val currentDateTime = LocalDateTime.now()
val startDate = currentDateTime
.minusWeeks(1)
.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
.withHour(15)
.withMinute(0)
.withSecond(0)
val endDate = startDate.plusDays(7)
val contentRanking = getContentRanking(isAdult = isAdult, startDate = startDate, endDate = endDate)
return GetAudioContentMainResponse(
newContentUploadCreatorList = newContentUploadCreatorList,
bannerList = bannerList,
orderList = orderList,
themeList = themeList,
newContentList = newContentList,
curationList = curationList,
contentRanking = contentRanking
)
}
fun getThemeList(member: Member): List<String> {
return audioContentThemeRepository.getActiveThemeOfContent(isAdult = member.auth != null)
}
fun getNewContentByTheme(theme: String, member: Member, pageable: Pageable): List<GetAudioContentMainItem> {
return repository.findByTheme(
cloudfrontHost = imageHost,
theme = theme,
isAdult = member.auth != null,
offset = pageable.offset,
limit = pageable.pageSize.toLong()
)
.asSequence()
.filter { !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.creatorId) }
.toList()
}
fun getNewContentFor2WeeksByTheme(theme: String, member: Member, pageable: Pageable): GetNewContentAllResponse {
val totalCount = repository.totalCountNewContentFor2Weeks(theme, isAdult = member.auth != null)
val items = repository.findByThemeFor2Weeks(
cloudfrontHost = imageHost,
theme = theme,
isAdult = member.auth != null,
offset = pageable.offset,
limit = pageable.pageSize.toLong()
)
return GetNewContentAllResponse(totalCount, items)
}
@Cacheable(cacheNames = ["default"], key = "'getNewContentUploadCreatorList:' + #memberId + ':' + #isAdult")
fun getNewContentUploadCreatorList(memberId: Long, isAdult: Boolean): List<GetNewContentUploadCreator> {
return repository.getNewContentUploadCreatorList(
cloudfrontHost = imageHost,
isAdult = isAdult
)
.asSequence()
.filter { !blockMemberRepository.isBlocked(blockedMemberId = memberId, memberId = it.creatorId) }
.toList()
}
@Cacheable(cacheNames = ["default"], key = "'getAudioContentMainBannerList:' + #memberId + ':' + #isAdult")
fun getAudioContentMainBannerList(memberId: Long, isAdult: Boolean) =
repository.getAudioContentMainBannerList(isAdult = isAdult)
.asSequence() .asSequence()
.filter { .filter {
if (it.type == AudioContentBannerType.CREATOR && it.creator != null) { if (it.type == AudioContentBannerType.CREATOR && it.creator != null) {
!blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.creator!!.id!!) !blockMemberRepository.isBlocked(blockedMemberId = memberId, memberId = it.creator!!.id!!)
} else { } else {
true true
} }
@ -86,26 +169,9 @@ class AudioContentMainService(
} }
.toList() .toList()
// 구매목록 20개 @Cacheable(cacheNames = ["default"], key = "'getAudioContentCurationList:' + #memberId + ':' + #isAdult")
val orderList = orderService.getAudioContentMainOrderList( fun getAudioContentCurationList(memberId: Long, isAdult: Boolean) =
member = member, repository.getAudioContentCurations(isAdult = isAdult)
limit = 20
)
// 콘텐츠 테마
val themeList = audioContentThemeRepository.getActiveThemeOfContent(isAdult = isAdult)
// 새 콘텐츠 20개 - 시간 내림차순 정렬
val newContentList = repository.findByTheme(
cloudfrontHost = imageHost,
isAdult = isAdult
)
.asSequence()
.filter { !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.creatorId) }
.toList()
val curationList = repository
.getAudioContentCurations(isAdult = isAdult)
.asSequence() .asSequence()
.map { .map {
GetAudioContentCurationResponse( GetAudioContentCurationResponse(
@ -119,10 +185,7 @@ class AudioContentMainService(
) )
.asSequence() .asSequence()
.filter { content -> .filter { content ->
!blockMemberRepository.isBlocked( !blockMemberRepository.isBlocked(blockedMemberId = memberId, memberId = content.creatorId)
blockedMemberId = member.id!!,
memberId = content.creatorId
)
} }
.toList() .toList()
) )
@ -130,16 +193,11 @@ class AudioContentMainService(
.filter { it.contents.isNotEmpty() } .filter { it.contents.isNotEmpty() }
.toList() .toList()
val currentDateTime = LocalDateTime.now() @Cacheable(
val startDate = currentDateTime cacheNames = ["cache_ttl_3_days"],
.minusWeeks(1) key = "'getAudioContentCurationList:' + ':' + #isAdult + ':' + #startDate + ':' + #endDate"
.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)) )
.withHour(15) fun getContentRanking(isAdult: Boolean, startDate: LocalDateTime, endDate: LocalDateTime): GetAudioContentRanking {
.withMinute(0)
.withSecond(0)
val endDate = startDate
.plusDays(7)
val startDateFormatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일") val startDateFormatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일")
val endDateFormatter = DateTimeFormatter.ofPattern("MM월 dd일") val endDateFormatter = DateTimeFormatter.ofPattern("MM월 dd일")
@ -151,50 +209,10 @@ class AudioContentMainService(
isAdult = isAdult isAdult = isAdult
) )
val contentRanking = GetAudioContentRanking( return GetAudioContentRanking(
startDate = startDate.format(startDateFormatter), startDate = startDate.format(startDateFormatter),
endDate = endDate.minusDays(1).format(endDateFormatter), endDate = endDate.minusDays(1).format(endDateFormatter),
contentRankingItemList contentRankingItemList
) )
return GetAudioContentMainResponse(
newContentUploadCreatorList = newContentUploadCreatorList,
bannerList = bannerList,
orderList = orderList,
themeList = themeList,
newContentList = newContentList,
curationList = curationList,
contentRanking = contentRanking
)
}
fun getThemeList(member: Member): List<String> {
return audioContentThemeRepository.getActiveThemeOfContent(isAdult = member.auth != null)
}
fun getNewContentByTheme(theme: String, member: Member, pageable: Pageable): List<GetAudioContentMainItem> {
return repository.findByTheme(
cloudfrontHost = imageHost,
theme = theme,
isAdult = member.auth != null,
offset = pageable.offset,
limit = pageable.pageSize.toLong()
)
.asSequence()
.filter { !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.creatorId) }
.toList()
}
fun getNewContentFor2WeeksByTheme(theme: String, member: Member, pageable: Pageable): GetNewContentAllResponse {
val totalCount = repository.totalCountNewContentFor2Weeks(theme, isAdult = member.auth != null)
val items = repository.findByThemeFor2Weeks(
cloudfrontHost = imageHost,
theme = theme,
isAdult = member.auth != null,
offset = pageable.offset,
limit = pageable.pageSize.toLong()
)
return GetNewContentAllResponse(totalCount, items)
} }
} }

View File

@ -4,6 +4,7 @@ import com.querydsl.jpa.impl.JPAQueryFactory
import kr.co.vividnext.sodalive.content.QAudioContent.audioContent import kr.co.vividnext.sodalive.content.QAudioContent.audioContent
import kr.co.vividnext.sodalive.content.theme.QAudioContentTheme.audioContentTheme import kr.co.vividnext.sodalive.content.theme.QAudioContentTheme.audioContentTheme
import org.springframework.beans.factory.annotation.Value import org.springframework.beans.factory.annotation.Value
import org.springframework.cache.annotation.Cacheable
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
@Repository @Repository
@ -27,6 +28,7 @@ class AudioContentThemeQueryRepository(
.fetch() .fetch()
} }
@Cacheable(cacheNames = ["default"], key = "'getActiveThemeOfContent:' + ':' + #isAdult")
fun getActiveThemeOfContent(isAdult: Boolean = false): List<String> { fun getActiveThemeOfContent(isAdult: Boolean = false): List<String> {
var where = audioContent.isActive.isTrue var where = audioContent.isActive.isTrue
.and(audioContentTheme.isActive.isTrue) .and(audioContentTheme.isActive.isTrue)