후원 랭킹 캐시 추가
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.CreatorCheers
|
||||
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.PutWriteCheersRequest
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunityService
|
||||
@@ -43,6 +44,8 @@ import kotlin.random.Random
|
||||
class ExplorerService(
|
||||
private val memberService: MemberService,
|
||||
private val audioContentService: AudioContentService,
|
||||
private val donationRankingService: CreatorDonationRankingService,
|
||||
|
||||
private val queryRepository: ExplorerQueryRepository,
|
||||
private val cheersRepository: CreatorCheersRepository,
|
||||
private val noticeRepository: ChannelNoticeRepository,
|
||||
@@ -217,9 +220,9 @@ class ExplorerService(
|
||||
val memberDonationRanking = if (
|
||||
isCreator && (creatorId == member.id!! || creatorAccount.isVisibleDonationRank)
|
||||
) {
|
||||
queryRepository.getMemberDonationRanking(
|
||||
creatorId,
|
||||
10,
|
||||
donationRankingService.getMemberDonationRanking(
|
||||
creatorId = creatorId,
|
||||
limit = 10,
|
||||
withDonationCan = creatorId == member.id!!
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package kr.co.vividnext.sodalive.explorer
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import java.io.Serializable
|
||||
|
||||
data class GetDonationAllResponse(
|
||||
val accumulatedCansToday: Int,
|
||||
val accumulatedCansLastWeek: Int,
|
||||
@@ -7,11 +10,15 @@ data class GetDonationAllResponse(
|
||||
val isVisibleDonationRank: Boolean,
|
||||
val totalCount: Int,
|
||||
val userDonationRanking: List<MemberDonationRankingResponse>
|
||||
)
|
||||
) : Serializable
|
||||
|
||||
data class MemberDonationRankingResponse(
|
||||
val userId: Long,
|
||||
val nickname: String,
|
||||
val profileImage: String,
|
||||
val donationCan: Int
|
||||
)
|
||||
@JsonProperty("userId") val userId: Long,
|
||||
@JsonProperty("nickname") val nickname: String,
|
||||
@JsonProperty("profileImage") val profileImage: String,
|
||||
@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