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