From 046c163e6f809e2b3855cabfcda48d4ffc154c79 Mon Sep 17 00:00:00 2001 From: Klaus Date: Mon, 21 Jul 2025 15:14:47 +0900 Subject: [PATCH 1/8] =?UTF-8?q?feat:=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=20?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20API=20-=20=EA=B8=B0=EC=A1=B4=EC=97=90=20?= =?UTF-8?q?=EC=84=B9=EC=85=98=EB=B3=84=EB=A1=9C=20=EB=94=B0=EB=A1=9C?= =?UTF-8?q?=EB=94=B0=EB=A1=9C=20=ED=98=B8=EC=B6=9C=ED=95=98=EB=8D=98=20?= =?UTF-8?q?=EA=B2=83=EC=9D=84=20=ED=95=98=EB=82=98=EB=A1=9C=20=ED=95=A9?= =?UTF-8?q?=EC=B3=90=EC=84=9C=20=ED=98=B8=EC=B6=9C=ED=95=A0=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EB=8F=84=EB=A1=9D=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sodalive/api/live/LiveApiController.kt | 33 ++++++ .../sodalive/api/live/LiveApiService.kt | 106 ++++++++++++++++++ .../sodalive/api/live/LiveMainResponse.kt | 18 +++ .../vividnext/sodalive/configs/RedisConfig.kt | 27 +++++ .../sodalive/configs/SecurityConfig.kt | 1 + .../sodalive/content/AudioContentService.kt | 5 + .../CreatorCommunityService.kt | 6 + .../live/recommend/LiveRecommendService.kt | 8 +- .../room/GetLatestFinishedLiveResponse.kt | 6 +- .../sodalive/live/room/LiveRoomRepository.kt | 1 - .../sodalive/live/room/LiveRoomService.kt | 7 ++ 11 files changed, 212 insertions(+), 6 deletions(-) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiController.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiService.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveMainResponse.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiController.kt new file mode 100644 index 0000000..263db9f --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiController.kt @@ -0,0 +1,33 @@ +package kr.co.vividnext.sodalive.api.live + +import kr.co.vividnext.sodalive.common.ApiResponse +import kr.co.vividnext.sodalive.content.ContentType +import kr.co.vividnext.sodalive.member.Member +import org.springframework.security.core.annotation.AuthenticationPrincipal +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/api/live") +class LiveApiController( + private val service: LiveApiService +) { + @GetMapping + fun fetchData( + @RequestParam timezone: String, + @RequestParam("contentType", required = false) contentType: ContentType? = null, + @RequestParam("isAdultContentVisible", required = false) isAdultContentVisible: Boolean? = null, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + ApiResponse.ok( + service.fetchData( + isAdultContentVisible = isAdultContentVisible ?: true, + contentType = contentType ?: ContentType.ALL, + timezone = timezone, + member = member + ) + ) + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiService.kt new file mode 100644 index 0000000..d7d60e2 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiService.kt @@ -0,0 +1,106 @@ +package kr.co.vividnext.sodalive.api.live + +import kr.co.vividnext.sodalive.content.AudioContentService +import kr.co.vividnext.sodalive.content.ContentType +import kr.co.vividnext.sodalive.explorer.ExplorerQueryRepository +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunityService +import kr.co.vividnext.sodalive.live.recommend.LiveRecommendService +import kr.co.vividnext.sodalive.live.room.LiveRoomService +import kr.co.vividnext.sodalive.live.room.LiveRoomStatus +import kr.co.vividnext.sodalive.member.Member +import kr.co.vividnext.sodalive.member.block.BlockMemberRepository +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Service + +@Service +class LiveApiService( + private val liveService: LiveRoomService, + private val contentService: AudioContentService, + private val recommendService: LiveRecommendService, + private val creatorCommunityService: CreatorCommunityService, + + private val blockMemberRepository: BlockMemberRepository, + private val explorerQueryRepository: ExplorerQueryRepository +) { + fun fetchData( + isAdultContentVisible: Boolean, + contentType: ContentType, + timezone: String, + member: Member? + ): LiveMainResponse { + val memberId = member?.id + val isAdult = member?.auth != null && isAdultContentVisible + + val liveOnAirRoomList = liveService.getRoomList( + dateString = null, + status = LiveRoomStatus.NOW, + isAdultContentVisible = isAdultContentVisible, + pageable = Pageable.ofSize(20), + member = member, + timezone = timezone + ) + + val communityPostList = if (memberId != null) { + creatorCommunityService.getLatestPostListFromCreatorsYouFollow( + timezone = timezone, + memberId = memberId, + isAdult = isAdult + ) + } else { + listOf() + } + + val recommendLiveList = recommendService.getRecommendLive(member) + + val latestFinishedLiveList = liveService.getLatestFinishedLive(member) + .map { + if (memberId != null) { + it.isFollowing = explorerQueryRepository.getCreatorFollowing( + creatorId = it.memberId, + memberId = memberId + )?.isFollow ?: false + } + + it + } + + val replayLive = contentService.getLatestContentByTheme( + theme = listOf("다시듣기"), + contentType = contentType, + isFree = false, + isAdult = isAdult + ) + .filter { content -> + if (memberId != null) { + !blockMemberRepository.isBlocked(blockedMemberId = memberId, memberId = content.creatorId) + } else { + true + } + } + + val followingChannelList = if (memberId != null) { + recommendService.getFollowingChannelList(member) + } else { + listOf() + } + + val liveReservationRoomList = liveService.getRoomList( + dateString = null, + status = LiveRoomStatus.RESERVATION, + isAdultContentVisible = isAdultContentVisible, + pageable = Pageable.ofSize(10), + member = member, + timezone = timezone + ) + + return LiveMainResponse( + liveOnAirRoomList = liveOnAirRoomList, + communityPostList = communityPostList, + recommendLiveList = recommendLiveList, + latestFinishedLiveList = latestFinishedLiveList, + replayLive = replayLive, + followingChannelList = followingChannelList, + liveReservationRoomList = liveReservationRoomList + ) + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveMainResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveMainResponse.kt new file mode 100644 index 0000000..a1e16bd --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveMainResponse.kt @@ -0,0 +1,18 @@ +package kr.co.vividnext.sodalive.api.live + +import kr.co.vividnext.sodalive.content.AudioContentMainItem +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.GetCommunityPostListResponse +import kr.co.vividnext.sodalive.live.recommend.GetRecommendChannelResponse +import kr.co.vividnext.sodalive.live.recommend.GetRecommendLiveResponse +import kr.co.vividnext.sodalive.live.room.GetLatestFinishedLiveResponse +import kr.co.vividnext.sodalive.live.room.GetRoomListResponse + +data class LiveMainResponse( + val liveOnAirRoomList: List, + val communityPostList: List, + val recommendLiveList: List, + val latestFinishedLiveList: List, + val replayLive: List, + val followingChannelList: List, + val liveReservationRoomList: List +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/configs/RedisConfig.kt b/src/main/kotlin/kr/co/vividnext/sodalive/configs/RedisConfig.kt index cf2a581..04a6c2c 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/configs/RedisConfig.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/configs/RedisConfig.kt @@ -96,6 +96,33 @@ class RedisConfig( ) ) + cacheConfigMap["cache_ttl_10_minutes"] = RedisCacheConfiguration.defaultCacheConfig() + .entryTtl(Duration.ofMinutes(10)) + .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer())) + .serializeValuesWith( + RedisSerializationContext.SerializationPair.fromSerializer( + GenericJackson2JsonRedisSerializer() + ) + ) + + cacheConfigMap["cache_ttl_5_minutes"] = RedisCacheConfiguration.defaultCacheConfig() + .entryTtl(Duration.ofMinutes(5)) + .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer())) + .serializeValuesWith( + RedisSerializationContext.SerializationPair.fromSerializer( + GenericJackson2JsonRedisSerializer() + ) + ) + + cacheConfigMap["cache_ttl_3_minutes"] = RedisCacheConfiguration.defaultCacheConfig() + .entryTtl(Duration.ofMinutes(3)) + .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer())) + .serializeValuesWith( + RedisSerializationContext.SerializationPair.fromSerializer( + GenericJackson2JsonRedisSerializer() + ) + ) + return RedisCacheManager.builder(redisConnectionFactory) .cacheDefaults(defaultCacheConfig) .withInitialCacheConfigurations(cacheConfigMap) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/configs/SecurityConfig.kt b/src/main/kotlin/kr/co/vividnext/sodalive/configs/SecurityConfig.kt index e6c2470..b317300 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/configs/SecurityConfig.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/configs/SecurityConfig.kt @@ -83,6 +83,7 @@ class SecurityConfig( .antMatchers("/api/home").permitAll() .antMatchers("/api/home/latest-content").permitAll() .antMatchers("/api/home/day-of-week-series").permitAll() + .antMatchers(HttpMethod.GET, "/api/live").permitAll() .antMatchers(HttpMethod.GET, "/faq").permitAll() .antMatchers(HttpMethod.GET, "/faq/category").permitAll() .antMatchers("/audition").permitAll() diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt index b651166..91476f6 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt @@ -939,6 +939,11 @@ class AudioContentService( return GenerateUrlResponse(contentUrl) } + @Transactional(readOnly = true) + @Cacheable( + cacheNames = ["default"], + key = "'getLatestContentByTheme:' + #theme + ':' + #contentType + ':' + #isAdult" + ) fun getLatestContentByTheme( theme: List, contentType: ContentType, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt index a209742..c9820bc 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt @@ -24,6 +24,7 @@ import kr.co.vividnext.sodalive.member.block.BlockMemberRepository import kr.co.vividnext.sodalive.utils.generateFileName import kr.co.vividnext.sodalive.utils.validateImage import org.springframework.beans.factory.annotation.Value +import org.springframework.cache.annotation.Cacheable import org.springframework.context.ApplicationEventPublisher import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service @@ -441,6 +442,11 @@ class CreatorCommunityService( return GetCommunityPostCommentListResponse(totalCount = totalCount, items = commentList) } + @Transactional(readOnly = true) + @Cacheable( + cacheNames = ["cache_ttl_5_minutes"], + key = "'getLatestPostListFromCreatorsYouFollow:' + #memberId + ':' + #isAdult + ':' + #timezone" + ) fun getLatestPostListFromCreatorsYouFollow( timezone: String, memberId: Long, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendService.kt index 67d86fa..066dbda 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendService.kt @@ -3,15 +3,21 @@ package kr.co.vividnext.sodalive.live.recommend import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.MemberRole import kr.co.vividnext.sodalive.member.block.BlockMemberRepository +import org.springframework.cache.annotation.Cacheable import org.springframework.data.domain.Pageable import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional @Service class LiveRecommendService( private val repository: LiveRecommendRepository, private val blockMemberRepository: BlockMemberRepository ) { - + @Transactional(readOnly = true) + @Cacheable( + cacheNames = ["cache_ttl_3_hours"], + key = "'getRecommendLive:' + (#member ?: 'guest')" + ) fun getRecommendLive(member: Member?): List { return repository.getRecommendLive( isBlocked = { diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt index 8955da6..8f7f98f 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt @@ -8,7 +8,6 @@ data class GetLatestFinishedLiveQueryResponse @QueryProjection constructor( val memberId: Long, val nickname: String, val profileImageUrl: String, - val title: String, val updatedAt: LocalDateTime ) @@ -16,14 +15,13 @@ data class GetLatestFinishedLiveResponse( val memberId: Long, val nickname: String, val profileImageUrl: String, - val title: String, - val timeAgo: String + val timeAgo: String, + var isFollowing: Boolean = false ) { constructor(response: GetLatestFinishedLiveQueryResponse) : this( response.memberId, response.nickname, response.profileImageUrl, - response.title, response.updatedAt.getTimeAgoString() ) } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomRepository.kt index 5967fb9..4006683 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomRepository.kt @@ -404,7 +404,6 @@ class LiveRoomQueryRepositoryImpl( member.id, member.nickname, member.profileImage.prepend("/").prepend(cloudFrontHost), - liveRoom.title, liveRoom.updatedAt ) ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt index b8a6e27..953b542 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt @@ -56,6 +56,7 @@ import kr.co.vividnext.sodalive.member.MemberRole import kr.co.vividnext.sodalive.member.block.BlockMemberRepository import kr.co.vividnext.sodalive.utils.generateFileName import org.springframework.beans.factory.annotation.Value +import org.springframework.cache.annotation.Cacheable import org.springframework.context.ApplicationEventPublisher import org.springframework.data.domain.Pageable import org.springframework.data.repository.findByIdOrNull @@ -113,6 +114,7 @@ class LiveRoomService( ) { private val tokenLocks: MutableMap = mutableMapOf() + @Transactional(readOnly = true) fun getRoomList( dateString: String?, status: LiveRoomStatus, @@ -1297,6 +1299,11 @@ class LiveRoomService( ) } + @Transactional(readOnly = true) + @Cacheable( + cacheNames = ["cache_ttl_10_minutes"], + key = "'getLatestFinishedLive:' + (#member ?: 'guest')" + ) fun getLatestFinishedLive(member: Member?): List { return repository.getLatestFinishedLive() .filter { -- 2.40.1 From ab877beae11941c2b7ee87fb081cef254699f7d1 Mon Sep 17 00:00:00 2001 From: Klaus Date: Mon, 21 Jul 2025 15:48:40 +0900 Subject: [PATCH 2/8] =?UTF-8?q?fix:=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=20?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20API=20-=20redis=20caching=EC=9D=B4=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9=EB=90=9C=20data=20class=EC=97=90=20@JsonProp?= =?UTF-8?q?erty=20=EC=95=A0=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sodalive/api/live/LiveApiService.kt | 2 +- .../sodalive/content/AudioContentMainItem.kt | 2 +- .../GetCommunityPostListResponse.kt | 33 ++++++++++--------- .../room/GetLatestFinishedLiveResponse.kt | 11 ++++--- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiService.kt index d7d60e2..bce1c34 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiService.kt @@ -55,7 +55,7 @@ class LiveApiService( val latestFinishedLiveList = liveService.getLatestFinishedLive(member) .map { if (memberId != null) { - it.isFollowing = explorerQueryRepository.getCreatorFollowing( + it.following = explorerQueryRepository.getCreatorFollowing( creatorId = it.memberId, memberId = memberId )?.isFollow ?: false diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentMainItem.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentMainItem.kt index 6329435..9f384d9 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentMainItem.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentMainItem.kt @@ -9,5 +9,5 @@ data class AudioContentMainItem @QueryProjection constructor( @JsonProperty("title") val title: String, @JsonProperty("coverImageUrl") val coverImageUrl: String, @JsonProperty("creatorNickname") val creatorNickname: String, - @JsonProperty("isPointAvailable") val isPointAvailable: Boolean + @get:JsonProperty("isPointAvailable") val isPointAvailable: Boolean ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt index 81a5f22..241dc86 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt @@ -1,23 +1,24 @@ package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity +import com.fasterxml.jackson.annotation.JsonProperty import com.querydsl.core.annotations.QueryProjection import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.GetCommunityPostCommentListItem data class GetCommunityPostListResponse @QueryProjection constructor( - val postId: Long, - val creatorId: Long, - val creatorNickname: String, - val creatorProfileUrl: String, - val imageUrl: String?, - val audioUrl: String?, - val content: String, - val price: Int, - val date: String, - val isCommentAvailable: Boolean, - val isAdult: Boolean, - val isLike: Boolean, - val existOrdered: Boolean, - val likeCount: Int, - val commentCount: Int, - val firstComment: GetCommunityPostCommentListItem? + @JsonProperty("postId") val postId: Long, + @JsonProperty("creatorId") val creatorId: Long, + @JsonProperty("creatorNickname") val creatorNickname: String, + @JsonProperty("creatorProfileUrl") val creatorProfileUrl: String, + @JsonProperty("imageUrl") val imageUrl: String?, + @JsonProperty("audioUrl") val audioUrl: String?, + @JsonProperty("content") val content: String, + @JsonProperty("price") val price: Int, + @JsonProperty("date") val date: String, + @get:JsonProperty("isCommentAvailable") val isCommentAvailable: Boolean, + @get:JsonProperty("isAdult") val isAdult: Boolean, + @get:JsonProperty("isLike") val isLike: Boolean, + @JsonProperty("existOrdered") val existOrdered: Boolean, + @JsonProperty("likeCount") val likeCount: Int, + @JsonProperty("commentCount") val commentCount: Int, + @JsonProperty("firstComment") val firstComment: GetCommunityPostCommentListItem? ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt index 8f7f98f..8fb1272 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt @@ -1,5 +1,6 @@ package kr.co.vividnext.sodalive.live.room +import com.fasterxml.jackson.annotation.JsonProperty import com.querydsl.core.annotations.QueryProjection import kr.co.vividnext.sodalive.extensions.getTimeAgoString import java.time.LocalDateTime @@ -12,11 +13,11 @@ data class GetLatestFinishedLiveQueryResponse @QueryProjection constructor( ) data class GetLatestFinishedLiveResponse( - val memberId: Long, - val nickname: String, - val profileImageUrl: String, - val timeAgo: String, - var isFollowing: Boolean = false + @JsonProperty("memberId") val memberId: Long, + @JsonProperty("nickname") val nickname: String, + @JsonProperty("profileImageUrl") val profileImageUrl: String, + @JsonProperty("timeAgo") val timeAgo: String, + @get:JsonProperty("following") var following: Boolean = false ) { constructor(response: GetLatestFinishedLiveQueryResponse) : this( response.memberId, -- 2.40.1 From 800b8d3216d9148f537321c3d99c2086d30a2fdb Mon Sep 17 00:00:00 2001 From: Klaus Date: Mon, 21 Jul 2025 16:18:33 +0900 Subject: [PATCH 3/8] =?UTF-8?q?fix:=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=20?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20API=20-=20@JsonProperty=20=EC=95=A0?= =?UTF-8?q?=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../co/vividnext/sodalive/content/AudioContentMainItem.kt | 2 +- .../creatorCommunity/GetCommunityPostListResponse.kt | 6 +++--- .../sodalive/live/room/GetLatestFinishedLiveResponse.kt | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentMainItem.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentMainItem.kt index 9f384d9..6329435 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentMainItem.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentMainItem.kt @@ -9,5 +9,5 @@ data class AudioContentMainItem @QueryProjection constructor( @JsonProperty("title") val title: String, @JsonProperty("coverImageUrl") val coverImageUrl: String, @JsonProperty("creatorNickname") val creatorNickname: String, - @get:JsonProperty("isPointAvailable") val isPointAvailable: Boolean + @JsonProperty("isPointAvailable") val isPointAvailable: Boolean ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt index 241dc86..0b09c42 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt @@ -14,9 +14,9 @@ data class GetCommunityPostListResponse @QueryProjection constructor( @JsonProperty("content") val content: String, @JsonProperty("price") val price: Int, @JsonProperty("date") val date: String, - @get:JsonProperty("isCommentAvailable") val isCommentAvailable: Boolean, - @get:JsonProperty("isAdult") val isAdult: Boolean, - @get:JsonProperty("isLike") val isLike: Boolean, + @JsonProperty("isCommentAvailable") val isCommentAvailable: Boolean, + @JsonProperty("isAdult") val isAdult: Boolean, + @JsonProperty("isLike") val isLike: Boolean, @JsonProperty("existOrdered") val existOrdered: Boolean, @JsonProperty("likeCount") val likeCount: Int, @JsonProperty("commentCount") val commentCount: Int, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt index 8fb1272..5cf9322 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt @@ -17,7 +17,7 @@ data class GetLatestFinishedLiveResponse( @JsonProperty("nickname") val nickname: String, @JsonProperty("profileImageUrl") val profileImageUrl: String, @JsonProperty("timeAgo") val timeAgo: String, - @get:JsonProperty("following") var following: Boolean = false + @JsonProperty("following") var following: Boolean = false ) { constructor(response: GetLatestFinishedLiveQueryResponse) : this( response.memberId, -- 2.40.1 From 7c1082f83354da152ae6e0598075c1cdb2090ef0 Mon Sep 17 00:00:00 2001 From: Klaus Date: Mon, 21 Jul 2025 16:31:05 +0900 Subject: [PATCH 4/8] =?UTF-8?q?fix:=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=20?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20API=20-=20@JsonProperty=20=EC=95=A0?= =?UTF-8?q?=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../profile/creatorCommunity/CreatorCommunityService.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt index c9820bc..6698959 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt @@ -24,7 +24,6 @@ import kr.co.vividnext.sodalive.member.block.BlockMemberRepository import kr.co.vividnext.sodalive.utils.generateFileName import kr.co.vividnext.sodalive.utils.validateImage import org.springframework.beans.factory.annotation.Value -import org.springframework.cache.annotation.Cacheable import org.springframework.context.ApplicationEventPublisher import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service @@ -443,10 +442,6 @@ class CreatorCommunityService( } @Transactional(readOnly = true) - @Cacheable( - cacheNames = ["cache_ttl_5_minutes"], - key = "'getLatestPostListFromCreatorsYouFollow:' + #memberId + ':' + #isAdult + ':' + #timezone" - ) fun getLatestPostListFromCreatorsYouFollow( timezone: String, memberId: Long, -- 2.40.1 From c90df4b02bfdb437b6783c139b5cec9f6037efc3 Mon Sep 17 00:00:00 2001 From: Klaus Date: Mon, 21 Jul 2025 16:44:10 +0900 Subject: [PATCH 5/8] =?UTF-8?q?fix:=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=20?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20API=20-=20=ED=85=8C=EB=A7=88=EB=B3=84=20?= =?UTF-8?q?=EC=B5=9C=EC=8B=A0=EC=BD=98=ED=85=90=EC=B8=A0=20=EC=BA=90?= =?UTF-8?q?=EC=8B=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kr/co/vividnext/sodalive/content/AudioContentService.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt index 91476f6..aa5aeb3 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt @@ -940,10 +940,6 @@ class AudioContentService( } @Transactional(readOnly = true) - @Cacheable( - cacheNames = ["default"], - key = "'getLatestContentByTheme:' + #theme + ':' + #contentType + ':' + #isAdult" - ) fun getLatestContentByTheme( theme: List, contentType: ContentType, -- 2.40.1 From 811810cd3662000b33af44e8825ac169c28ed2ea Mon Sep 17 00:00:00 2001 From: Klaus Date: Mon, 21 Jul 2025 16:45:58 +0900 Subject: [PATCH 6/8] =?UTF-8?q?fix:=20GetCommunityPostListResponse=20-=20j?= =?UTF-8?q?son=20property=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GetCommunityPostListResponse.kt | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt index 0b09c42..81a5f22 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt @@ -1,24 +1,23 @@ package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity -import com.fasterxml.jackson.annotation.JsonProperty import com.querydsl.core.annotations.QueryProjection import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.GetCommunityPostCommentListItem data class GetCommunityPostListResponse @QueryProjection constructor( - @JsonProperty("postId") val postId: Long, - @JsonProperty("creatorId") val creatorId: Long, - @JsonProperty("creatorNickname") val creatorNickname: String, - @JsonProperty("creatorProfileUrl") val creatorProfileUrl: String, - @JsonProperty("imageUrl") val imageUrl: String?, - @JsonProperty("audioUrl") val audioUrl: String?, - @JsonProperty("content") val content: String, - @JsonProperty("price") val price: Int, - @JsonProperty("date") val date: String, - @JsonProperty("isCommentAvailable") val isCommentAvailable: Boolean, - @JsonProperty("isAdult") val isAdult: Boolean, - @JsonProperty("isLike") val isLike: Boolean, - @JsonProperty("existOrdered") val existOrdered: Boolean, - @JsonProperty("likeCount") val likeCount: Int, - @JsonProperty("commentCount") val commentCount: Int, - @JsonProperty("firstComment") val firstComment: GetCommunityPostCommentListItem? + val postId: Long, + val creatorId: Long, + val creatorNickname: String, + val creatorProfileUrl: String, + val imageUrl: String?, + val audioUrl: String?, + val content: String, + val price: Int, + val date: String, + val isCommentAvailable: Boolean, + val isAdult: Boolean, + val isLike: Boolean, + val existOrdered: Boolean, + val likeCount: Int, + val commentCount: Int, + val firstComment: GetCommunityPostCommentListItem? ) -- 2.40.1 From e068b5706207ae3a590d87ce766370001bb935e1 Mon Sep 17 00:00:00 2001 From: Klaus Date: Mon, 21 Jul 2025 18:05:33 +0900 Subject: [PATCH 7/8] =?UTF-8?q?fix:=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=20?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20API=20-=20=EC=B5=9C=EA=B7=BC=20=EC=A2=85?= =?UTF-8?q?=EB=A3=8C=ED=95=9C=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=20-=20?= =?UTF-8?q?=ED=8C=94=EB=A1=9C=EC=9E=89=20=EC=97=AC=EB=B6=80=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vividnext/sodalive/api/live/LiveApiService.kt | 14 +------------- .../live/room/GetLatestFinishedLiveResponse.kt | 3 +-- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiService.kt index bce1c34..1bc1c8a 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/api/live/LiveApiService.kt @@ -2,7 +2,6 @@ package kr.co.vividnext.sodalive.api.live import kr.co.vividnext.sodalive.content.AudioContentService import kr.co.vividnext.sodalive.content.ContentType -import kr.co.vividnext.sodalive.explorer.ExplorerQueryRepository import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunityService import kr.co.vividnext.sodalive.live.recommend.LiveRecommendService import kr.co.vividnext.sodalive.live.room.LiveRoomService @@ -19,8 +18,7 @@ class LiveApiService( private val recommendService: LiveRecommendService, private val creatorCommunityService: CreatorCommunityService, - private val blockMemberRepository: BlockMemberRepository, - private val explorerQueryRepository: ExplorerQueryRepository + private val blockMemberRepository: BlockMemberRepository ) { fun fetchData( isAdultContentVisible: Boolean, @@ -53,16 +51,6 @@ class LiveApiService( val recommendLiveList = recommendService.getRecommendLive(member) val latestFinishedLiveList = liveService.getLatestFinishedLive(member) - .map { - if (memberId != null) { - it.following = explorerQueryRepository.getCreatorFollowing( - creatorId = it.memberId, - memberId = memberId - )?.isFollow ?: false - } - - it - } val replayLive = contentService.getLatestContentByTheme( theme = listOf("다시듣기"), diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt index 5cf9322..e242ecb 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/GetLatestFinishedLiveResponse.kt @@ -16,8 +16,7 @@ data class GetLatestFinishedLiveResponse( @JsonProperty("memberId") val memberId: Long, @JsonProperty("nickname") val nickname: String, @JsonProperty("profileImageUrl") val profileImageUrl: String, - @JsonProperty("timeAgo") val timeAgo: String, - @JsonProperty("following") var following: Boolean = false + @JsonProperty("timeAgo") val timeAgo: String ) { constructor(response: GetLatestFinishedLiveQueryResponse) : this( response.memberId, -- 2.40.1 From 3d695069a26a4d089ce96df5b044d940ce513d9e Mon Sep 17 00:00:00 2001 From: Klaus Date: Mon, 21 Jul 2025 18:21:53 +0900 Subject: [PATCH 8/8] =?UTF-8?q?fix:=20=ED=99=88=20=EB=A9=94=EC=9D=B8=20API?= =?UTF-8?q?=20-=20=EC=9D=B8=EA=B8=B0=20=ED=81=AC=EB=A6=AC=EC=97=90?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20-=20=ED=8C=94=EB=A1=9C=EC=9E=89=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kr/co/vividnext/sodalive/api/home/HomeService.kt | 8 +++++++- .../vividnext/sodalive/explorer/GetExplorerResponse.kt | 1 + .../kotlin/kr/co/vividnext/sodalive/member/Member.kt | 9 +++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/api/home/HomeService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/api/home/HomeService.kt index fb30d96..4f9e75e 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/api/home/HomeService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/api/home/HomeService.kt @@ -75,7 +75,13 @@ class HomeService( } .map { val followerCount = explorerQueryRepository.getNotificationUserIds(it.id!!).size - it.toExplorerSectionCreator(imageHost, followerCount) + val follow = if (memberId != null) { + explorerQueryRepository.isFollow(it.id!!, memberId = memberId) + } else { + false + } + + it.toExplorerSectionCreator(imageHost, follow, followerCount = followerCount) } val latestContentThemeList = contentThemeService.getActiveThemeOfContent( diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetExplorerResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetExplorerResponse.kt index 0ff055c..1c890b7 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetExplorerResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetExplorerResponse.kt @@ -15,5 +15,6 @@ data class GetExplorerSectionCreatorResponse( val nickname: String, val tags: String, val profileImageUrl: String, + val follow: Boolean, val followerCount: Int ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/member/Member.kt b/src/main/kotlin/kr/co/vividnext/sodalive/member/Member.kt index d4ca483..0a9ba25 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/member/Member.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/Member.kt @@ -123,7 +123,11 @@ data class Member( } } - fun toExplorerSectionCreator(imageHost: String, followerCount: Int = 0): GetExplorerSectionCreatorResponse { + fun toExplorerSectionCreator( + imageHost: String, + follow: Boolean = false, + followerCount: Int = 0 + ): GetExplorerSectionCreatorResponse { return GetExplorerSectionCreatorResponse( id = id!!, nickname = nickname, @@ -136,7 +140,8 @@ data class Member( } else { "$imageHost/profile/default-profile.png" }, - followerCount = followerCount + followerCount = followerCount, + follow = follow ) } } -- 2.40.1