후원 랭킹 캐시 추가
This commit is contained in:
@@ -14,6 +14,7 @@ import kr.co.vividnext.sodalive.explorer.profile.ChannelNotice
|
|||||||
import kr.co.vividnext.sodalive.explorer.profile.ChannelNoticeRepository
|
import kr.co.vividnext.sodalive.explorer.profile.ChannelNoticeRepository
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.CreatorCheers
|
import kr.co.vividnext.sodalive.explorer.profile.CreatorCheers
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.CreatorCheersRepository
|
import kr.co.vividnext.sodalive.explorer.profile.CreatorCheersRepository
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.CreatorDonationRankingService
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.PostWriteCheersRequest
|
import kr.co.vividnext.sodalive.explorer.profile.PostWriteCheersRequest
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.PutWriteCheersRequest
|
import kr.co.vividnext.sodalive.explorer.profile.PutWriteCheersRequest
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunityService
|
import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunityService
|
||||||
@@ -43,6 +44,8 @@ import kotlin.random.Random
|
|||||||
class ExplorerService(
|
class ExplorerService(
|
||||||
private val memberService: MemberService,
|
private val memberService: MemberService,
|
||||||
private val audioContentService: AudioContentService,
|
private val audioContentService: AudioContentService,
|
||||||
|
private val donationRankingService: CreatorDonationRankingService,
|
||||||
|
|
||||||
private val queryRepository: ExplorerQueryRepository,
|
private val queryRepository: ExplorerQueryRepository,
|
||||||
private val cheersRepository: CreatorCheersRepository,
|
private val cheersRepository: CreatorCheersRepository,
|
||||||
private val noticeRepository: ChannelNoticeRepository,
|
private val noticeRepository: ChannelNoticeRepository,
|
||||||
@@ -217,9 +220,9 @@ class ExplorerService(
|
|||||||
val memberDonationRanking = if (
|
val memberDonationRanking = if (
|
||||||
isCreator && (creatorId == member.id!! || creatorAccount.isVisibleDonationRank)
|
isCreator && (creatorId == member.id!! || creatorAccount.isVisibleDonationRank)
|
||||||
) {
|
) {
|
||||||
queryRepository.getMemberDonationRanking(
|
donationRankingService.getMemberDonationRanking(
|
||||||
creatorId,
|
creatorId = creatorId,
|
||||||
10,
|
limit = 10,
|
||||||
withDonationCan = creatorId == member.id!!
|
withDonationCan = creatorId == member.id!!
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package kr.co.vividnext.sodalive.explorer
|
package kr.co.vividnext.sodalive.explorer
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
data class GetDonationAllResponse(
|
data class GetDonationAllResponse(
|
||||||
val accumulatedCansToday: Int,
|
val accumulatedCansToday: Int,
|
||||||
val accumulatedCansLastWeek: Int,
|
val accumulatedCansLastWeek: Int,
|
||||||
@@ -7,11 +10,15 @@ data class GetDonationAllResponse(
|
|||||||
val isVisibleDonationRank: Boolean,
|
val isVisibleDonationRank: Boolean,
|
||||||
val totalCount: Int,
|
val totalCount: Int,
|
||||||
val userDonationRanking: List<MemberDonationRankingResponse>
|
val userDonationRanking: List<MemberDonationRankingResponse>
|
||||||
)
|
) : Serializable
|
||||||
|
|
||||||
data class MemberDonationRankingResponse(
|
data class MemberDonationRankingResponse(
|
||||||
val userId: Long,
|
@JsonProperty("userId") val userId: Long,
|
||||||
val nickname: String,
|
@JsonProperty("nickname") val nickname: String,
|
||||||
val profileImage: String,
|
@JsonProperty("profileImage") val profileImage: String,
|
||||||
val donationCan: Int
|
@JsonProperty("donationCan") val donationCan: Int
|
||||||
)
|
) : Serializable
|
||||||
|
|
||||||
|
data class MemberDonationRankingListResponse(
|
||||||
|
@JsonProperty("rankings") val rankings: List<MemberDonationRankingResponse>
|
||||||
|
) : Serializable
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package kr.co.vividnext.sodalive.explorer.profile
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import com.querydsl.core.annotations.QueryProjection
|
||||||
|
import com.querydsl.jpa.impl.JPAQueryFactory
|
||||||
|
import kr.co.vividnext.sodalive.can.use.CanUsage
|
||||||
|
import kr.co.vividnext.sodalive.can.use.QUseCan.useCan
|
||||||
|
import kr.co.vividnext.sodalive.can.use.QUseCanCalculate.useCanCalculate
|
||||||
|
import kr.co.vividnext.sodalive.member.QMember.member
|
||||||
|
import org.springframework.stereotype.Repository
|
||||||
|
import java.time.DayOfWeek
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.LocalTime
|
||||||
|
import java.time.temporal.TemporalAdjusters
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
class CreatorDonationRankingQueryRepository(private val queryFactory: JPAQueryFactory) {
|
||||||
|
fun getMemberDonationRanking(
|
||||||
|
creatorId: Long,
|
||||||
|
limit: Long
|
||||||
|
): List<DonationRankingProjection> {
|
||||||
|
val now = LocalDateTime.now()
|
||||||
|
val lastMonday = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
|
||||||
|
.minusWeeks(1)
|
||||||
|
.with(LocalTime.MIN)
|
||||||
|
val lastSunday = lastMonday.plusDays(6).with(LocalTime.MAX)
|
||||||
|
|
||||||
|
val donationCan = useCan.rewardCan.add(useCan.can).sum()
|
||||||
|
return queryFactory
|
||||||
|
.select(
|
||||||
|
QDonationRankingProjection(
|
||||||
|
member.id,
|
||||||
|
member.nickname,
|
||||||
|
member.profileImage,
|
||||||
|
donationCan
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.from(useCanCalculate)
|
||||||
|
.innerJoin(useCanCalculate.useCan, useCan)
|
||||||
|
.innerJoin(useCan.member, member)
|
||||||
|
.where(
|
||||||
|
useCan.member.isActive.isTrue
|
||||||
|
.and(useCan.isRefund.isFalse)
|
||||||
|
.and(useCanCalculate.recipientCreatorId.eq(creatorId))
|
||||||
|
.and(
|
||||||
|
useCan.canUsage.eq(CanUsage.DONATION)
|
||||||
|
.or(useCan.canUsage.eq(CanUsage.SPIN_ROULETTE))
|
||||||
|
.or(useCan.canUsage.eq(CanUsage.LIVE))
|
||||||
|
)
|
||||||
|
.and(useCan.createdAt.between(lastMonday, lastSunday))
|
||||||
|
)
|
||||||
|
.offset(0)
|
||||||
|
.limit(limit)
|
||||||
|
.groupBy(member.id)
|
||||||
|
.orderBy(donationCan.desc(), member.id.desc())
|
||||||
|
.fetch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class DonationRankingProjection @QueryProjection constructor(
|
||||||
|
@JsonProperty("memberId") val memberId: Long,
|
||||||
|
@JsonProperty("nickname") val nickname: String,
|
||||||
|
@JsonProperty("profileImage") val profileImage: String,
|
||||||
|
@JsonProperty("donationCan") val donationCan: Int
|
||||||
|
)
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package kr.co.vividnext.sodalive.explorer.profile
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.explorer.MemberDonationRankingListResponse
|
||||||
|
import kr.co.vividnext.sodalive.explorer.MemberDonationRankingResponse
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
import java.time.DayOfWeek
|
||||||
|
import java.time.Duration
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.LocalTime
|
||||||
|
import java.time.temporal.ChronoUnit
|
||||||
|
import java.time.temporal.TemporalAdjusters
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class CreatorDonationRankingService(
|
||||||
|
private val repository: CreatorDonationRankingQueryRepository,
|
||||||
|
private val redisTemplate: RedisTemplate<String, Any>
|
||||||
|
) {
|
||||||
|
fun getMemberDonationRanking(
|
||||||
|
creatorId: Long,
|
||||||
|
limit: Long,
|
||||||
|
withDonationCan: Boolean
|
||||||
|
): List<MemberDonationRankingResponse> {
|
||||||
|
val cacheKey = "creator_donation_ranking:$creatorId:$limit:$withDonationCan"
|
||||||
|
val cachedData = redisTemplate.opsForValue().get(cacheKey) as? MemberDonationRankingListResponse
|
||||||
|
if (cachedData != null) {
|
||||||
|
return cachedData.rankings
|
||||||
|
}
|
||||||
|
|
||||||
|
val memberDonationRanking = repository.getMemberDonationRanking(creatorId, limit)
|
||||||
|
|
||||||
|
val result = memberDonationRanking.map {
|
||||||
|
MemberDonationRankingResponse(
|
||||||
|
it.memberId,
|
||||||
|
it.nickname,
|
||||||
|
it.profileImage,
|
||||||
|
if (withDonationCan) it.donationCan else 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val now = LocalDateTime.now()
|
||||||
|
val nextMonday = now.with(TemporalAdjusters.next(DayOfWeek.MONDAY)).with(LocalTime.MIN)
|
||||||
|
val secondsUntilNextMonday = ChronoUnit.SECONDS.between(now, nextMonday)
|
||||||
|
|
||||||
|
redisTemplate.opsForValue().set(
|
||||||
|
cacheKey,
|
||||||
|
MemberDonationRankingListResponse(result),
|
||||||
|
Duration.ofSeconds(secondsUntilNextMonday)
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user