Merge pull request '로딩 속도를 위해 @Cacheable 적용' (#50) from test into main
Reviewed-on: #50
This commit is contained in:
commit
4aff0111aa
|
@ -1,5 +1,9 @@
|
||||||
package kr.co.vividnext.sodalive.common
|
package kr.co.vividnext.sodalive.common
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import javax.persistence.GeneratedValue
|
import javax.persistence.GeneratedValue
|
||||||
import javax.persistence.GenerationType
|
import javax.persistence.GenerationType
|
||||||
|
@ -14,7 +18,12 @@ abstract class BaseEntity {
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
var id: Long? = null
|
var id: Long? = null
|
||||||
|
|
||||||
|
@JsonSerialize(using = LocalDateTimeSerializer::class)
|
||||||
|
@JsonDeserialize(using = LocalDateTimeDeserializer::class)
|
||||||
var createdAt: LocalDateTime? = null
|
var createdAt: LocalDateTime? = null
|
||||||
|
|
||||||
|
@JsonSerialize(using = LocalDateTimeSerializer::class)
|
||||||
|
@JsonDeserialize(using = LocalDateTimeDeserializer::class)
|
||||||
var updatedAt: LocalDateTime? = null
|
var updatedAt: LocalDateTime? = null
|
||||||
|
|
||||||
@PrePersist
|
@PrePersist
|
||||||
|
|
|
@ -1,14 +1,22 @@
|
||||||
package kr.co.vividnext.sodalive.configs
|
package kr.co.vividnext.sodalive.configs
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
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 org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer
|
||||||
|
import org.springframework.data.redis.serializer.RedisSerializationContext
|
||||||
|
import org.springframework.data.redis.serializer.StringRedisSerializer
|
||||||
|
import java.time.Duration
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@EnableCaching
|
||||||
@EnableRedisRepositories
|
@EnableRedisRepositories
|
||||||
class RedisConfig(
|
class RedisConfig(
|
||||||
@Value("\${spring.redis.host}")
|
@Value("\${spring.redis.host}")
|
||||||
|
@ -27,4 +35,31 @@ class RedisConfig(
|
||||||
redisTemplate.setConnectionFactory(redisConnectionFactory())
|
redisTemplate.setConnectionFactory(redisConnectionFactory())
|
||||||
return redisTemplate
|
return redisTemplate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun cacheManager(connectionFactory: RedisConnectionFactory): RedisCacheManager {
|
||||||
|
val defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
|
||||||
|
.entryTtl(Duration.ofHours(1)) // Default TTL
|
||||||
|
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer()))
|
||||||
|
.serializeValuesWith(
|
||||||
|
RedisSerializationContext.SerializationPair.fromSerializer(
|
||||||
|
GenericJackson2JsonRedisSerializer()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val weekLivedCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
|
||||||
|
.entryTtl(Duration.ofDays(3))
|
||||||
|
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer()))
|
||||||
|
.serializeValuesWith(
|
||||||
|
RedisSerializationContext.SerializationPair.fromSerializer(
|
||||||
|
GenericJackson2JsonRedisSerializer()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return RedisCacheManager.RedisCacheManagerBuilder
|
||||||
|
.fromConnectionFactory(connectionFactory)
|
||||||
|
.cacheDefaults(defaultConfig)
|
||||||
|
.withCacheConfiguration("weekLivedCache", weekLivedCacheConfig)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ data class AudioContent(
|
||||||
var content: String? = null
|
var content: String? = null
|
||||||
var coverImage: String? = null
|
var coverImage: String? = null
|
||||||
|
|
||||||
@OneToOne(fetch = FetchType.LAZY)
|
@OneToOne(fetch = FetchType.EAGER)
|
||||||
@JoinColumn(name = "theme_id", nullable = false)
|
@JoinColumn(name = "theme_id", nullable = false)
|
||||||
var theme: AudioContentTheme? = null
|
var theme: AudioContentTheme? = null
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import kr.co.vividnext.sodalive.content.order.QOrder.order
|
||||||
import kr.co.vividnext.sodalive.content.theme.QAudioContentTheme.audioContentTheme
|
import kr.co.vividnext.sodalive.content.theme.QAudioContentTheme.audioContentTheme
|
||||||
import kr.co.vividnext.sodalive.event.QEvent.event
|
import kr.co.vividnext.sodalive.event.QEvent.event
|
||||||
import kr.co.vividnext.sodalive.member.QMember.member
|
import kr.co.vividnext.sodalive.member.QMember.member
|
||||||
|
import org.springframework.cache.annotation.Cacheable
|
||||||
import org.springframework.data.jpa.repository.JpaRepository
|
import org.springframework.data.jpa.repository.JpaRepository
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
@ -336,6 +337,10 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory)
|
||||||
.fetch()
|
.fetch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable(
|
||||||
|
value = ["getNewContentUploadCreatorList"],
|
||||||
|
cacheManager = "cacheManager"
|
||||||
|
)
|
||||||
override fun getNewContentUploadCreatorList(
|
override fun getNewContentUploadCreatorList(
|
||||||
cloudfrontHost: String,
|
cloudfrontHost: String,
|
||||||
isAdult: Boolean
|
isAdult: Boolean
|
||||||
|
@ -371,6 +376,10 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory)
|
||||||
.toList()
|
.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable(
|
||||||
|
value = ["getAudioContentMainBannerList"],
|
||||||
|
cacheManager = "cacheManager"
|
||||||
|
)
|
||||||
override fun getAudioContentMainBannerList(isAdult: Boolean): List<AudioContentBanner> {
|
override fun getAudioContentMainBannerList(isAdult: Boolean): List<AudioContentBanner> {
|
||||||
var where = audioContentBanner.isActive.isTrue
|
var where = audioContentBanner.isActive.isTrue
|
||||||
|
|
||||||
|
@ -387,6 +396,10 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory)
|
||||||
.fetch()
|
.fetch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable(
|
||||||
|
value = ["getAudioContentCurations"],
|
||||||
|
cacheManager = "cacheManager"
|
||||||
|
)
|
||||||
override fun getAudioContentCurations(isAdult: Boolean): List<AudioContentCuration> {
|
override fun getAudioContentCurations(isAdult: Boolean): List<AudioContentCuration> {
|
||||||
var where = audioContentCuration.isActive.isTrue
|
var where = audioContentCuration.isActive.isTrue
|
||||||
|
|
||||||
|
@ -438,6 +451,10 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory)
|
||||||
.fetch()
|
.fetch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable(
|
||||||
|
value = ["weekLivedCache"],
|
||||||
|
cacheManager = "cacheManager"
|
||||||
|
)
|
||||||
override fun getAudioContentRanking(
|
override fun getAudioContentRanking(
|
||||||
cloudfrontHost: String,
|
cloudfrontHost: String,
|
||||||
isAdult: Boolean,
|
isAdult: Boolean,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package kr.co.vividnext.sodalive.content.main
|
package kr.co.vividnext.sodalive.content.main
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.querydsl.core.annotations.QueryProjection
|
import com.querydsl.core.annotations.QueryProjection
|
||||||
|
|
||||||
data class GetAudioContentRanking(
|
data class GetAudioContentRanking(
|
||||||
|
@ -9,12 +10,12 @@ data class GetAudioContentRanking(
|
||||||
)
|
)
|
||||||
|
|
||||||
data class GetAudioContentRankingItem @QueryProjection constructor(
|
data class GetAudioContentRankingItem @QueryProjection constructor(
|
||||||
val contentId: Long,
|
@JsonProperty("contentId") val contentId: Long,
|
||||||
val title: String,
|
@JsonProperty("title") val title: String,
|
||||||
val coverImageUrl: String,
|
@JsonProperty("coverImageUrl") val coverImageUrl: String,
|
||||||
val themeStr: String,
|
@JsonProperty("themeStr") val themeStr: String,
|
||||||
val price: Int,
|
@JsonProperty("price") val price: Int,
|
||||||
val duration: String,
|
@JsonProperty("duration") val duration: String,
|
||||||
val creatorId: Long,
|
@JsonProperty("creatorId") val creatorId: Long,
|
||||||
val creatorNickname: String
|
@JsonProperty("creatorNickname") val creatorNickname: String
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package kr.co.vividnext.sodalive.content.main
|
package kr.co.vividnext.sodalive.content.main
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.querydsl.core.annotations.QueryProjection
|
import com.querydsl.core.annotations.QueryProjection
|
||||||
|
|
||||||
data class GetNewContentUploadCreator @QueryProjection constructor(
|
data class GetNewContentUploadCreator @QueryProjection constructor(
|
||||||
val creatorId: Long,
|
@JsonProperty("creatorId") val creatorId: Long,
|
||||||
val creatorNickname: String,
|
@JsonProperty("creatorNickname") val creatorNickname: String,
|
||||||
val creatorProfileImageUrl: String
|
@JsonProperty("creatorProfileImageUrl") val creatorProfileImageUrl: String
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package kr.co.vividnext.sodalive.content.main.curation
|
package kr.co.vividnext.sodalive.content.main.curation
|
||||||
|
|
||||||
import kr.co.vividnext.sodalive.common.BaseEntity
|
import kr.co.vividnext.sodalive.common.BaseEntity
|
||||||
import kr.co.vividnext.sodalive.content.AudioContent
|
|
||||||
import javax.persistence.Column
|
import javax.persistence.Column
|
||||||
import javax.persistence.Entity
|
import javax.persistence.Entity
|
||||||
import javax.persistence.OneToMany
|
|
||||||
import javax.persistence.Table
|
import javax.persistence.Table
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
|
@ -20,7 +18,4 @@ data class AudioContentCuration(
|
||||||
var isActive: Boolean = true,
|
var isActive: Boolean = true,
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
var orders: Int = 1
|
var orders: Int = 1
|
||||||
) : BaseEntity() {
|
) : BaseEntity()
|
||||||
@OneToMany(mappedBy = "curation")
|
|
||||||
val audioContents: MutableList<AudioContent> = mutableListOf()
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import kr.co.vividnext.sodalive.aws.s3.S3Uploader
|
||||||
import kr.co.vividnext.sodalive.common.SodaException
|
import kr.co.vividnext.sodalive.common.SodaException
|
||||||
import kr.co.vividnext.sodalive.utils.generateFileName
|
import kr.co.vividnext.sodalive.utils.generateFileName
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
import org.springframework.cache.annotation.Cacheable
|
||||||
import org.springframework.data.repository.findByIdOrNull
|
import org.springframework.data.repository.findByIdOrNull
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import org.springframework.transaction.annotation.Transactional
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
@ -20,6 +21,10 @@ class EventService(
|
||||||
@Value("\${cloud.aws.cloud-front.host}")
|
@Value("\${cloud.aws.cloud-front.host}")
|
||||||
private val cloudFrontHost: String
|
private val cloudFrontHost: String
|
||||||
) {
|
) {
|
||||||
|
@Cacheable(
|
||||||
|
value = ["getEventList"],
|
||||||
|
cacheManager = "cacheManager"
|
||||||
|
)
|
||||||
fun getEventList(): GetEventResponse {
|
fun getEventList(): GetEventResponse {
|
||||||
val eventList = repository.getEventList()
|
val eventList = repository.getEventList()
|
||||||
.asSequence()
|
.asSequence()
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
package kr.co.vividnext.sodalive.event
|
package kr.co.vividnext.sodalive.event
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.querydsl.core.annotations.QueryProjection
|
import com.querydsl.core.annotations.QueryProjection
|
||||||
|
|
||||||
data class GetEventResponse(
|
data class GetEventResponse(
|
||||||
val totalCount: Int,
|
@JsonProperty("totalCount") val totalCount: Int,
|
||||||
val eventList: List<EventItem>
|
@JsonProperty("eventList") val eventList: List<EventItem>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class EventItem @QueryProjection constructor(
|
data class EventItem @QueryProjection constructor(
|
||||||
val id: Long,
|
@JsonProperty("id") val id: Long,
|
||||||
val title: String? = null,
|
@JsonProperty("title") val title: String? = null,
|
||||||
var thumbnailImageUrl: String,
|
@JsonProperty("thumbnailImageUrl") var thumbnailImageUrl: String,
|
||||||
var detailImageUrl: String? = null,
|
@JsonProperty("detailImageUrl") var detailImageUrl: String? = null,
|
||||||
var popupImageUrl: String? = null,
|
@JsonProperty("popupImageUrl") var popupImageUrl: String? = null,
|
||||||
val link: String? = null,
|
@JsonProperty("link") val link: String? = null,
|
||||||
val isPopup: Boolean
|
@JsonProperty("isPopup") val isPopup: Boolean
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package kr.co.vividnext.sodalive.live.recommend
|
package kr.co.vividnext.sodalive.live.recommend
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
|
||||||
data class GetRecommendLiveResponse(
|
data class GetRecommendLiveResponse(
|
||||||
val imageUrl: String,
|
@JsonProperty("imageUrl") val imageUrl: String,
|
||||||
val creatorId: Long
|
@JsonProperty("creatorId") val creatorId: Long
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,6 +9,7 @@ import kr.co.vividnext.sodalive.member.MemberRole
|
||||||
import kr.co.vividnext.sodalive.member.QMember.member
|
import kr.co.vividnext.sodalive.member.QMember.member
|
||||||
import kr.co.vividnext.sodalive.member.following.QCreatorFollowing.creatorFollowing
|
import kr.co.vividnext.sodalive.member.following.QCreatorFollowing.creatorFollowing
|
||||||
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
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
|
@ -19,6 +20,10 @@ class LiveRecommendRepository(
|
||||||
@Value("\${cloud.aws.cloud-front.host}")
|
@Value("\${cloud.aws.cloud-front.host}")
|
||||||
private val cloudFrontHost: String
|
private val cloudFrontHost: String
|
||||||
) {
|
) {
|
||||||
|
@Cacheable(
|
||||||
|
value = ["getRecommendLive"],
|
||||||
|
cacheManager = "cacheManager"
|
||||||
|
)
|
||||||
fun getRecommendLive(
|
fun getRecommendLive(
|
||||||
memberId: Long,
|
memberId: Long,
|
||||||
isBlocked: (Long) -> Boolean,
|
isBlocked: (Long) -> Boolean,
|
||||||
|
|
|
@ -73,6 +73,8 @@ spring:
|
||||||
multipart:
|
multipart:
|
||||||
max-file-size: 1024MB
|
max-file-size: 1024MB
|
||||||
max-request-size: 1024MB
|
max-request-size: 1024MB
|
||||||
|
cache:
|
||||||
|
type: redis
|
||||||
---
|
---
|
||||||
spring:
|
spring:
|
||||||
config:
|
config:
|
||||||
|
|
|
@ -47,3 +47,5 @@ spring:
|
||||||
hibernate:
|
hibernate:
|
||||||
show_sql: true
|
show_sql: true
|
||||||
format_sql: true
|
format_sql: true
|
||||||
|
cache:
|
||||||
|
type: redis
|
||||||
|
|
Loading…
Reference in New Issue