From e64b81db953aaf04ec9ad601a40c906381540ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=8F=84=EA=B2=BD?= Date: Mon, 14 Oct 2024 02:27:14 +0900 Subject: [PATCH 1/6] add :: cache --- .../domain/user/model/UserCache.kt | 13 ++++++++++++ .../domain/entity/UserCacheRedisEntity.kt | 20 +++++++++++++++++++ .../domain/repository/UserCacheRepository.kt | 8 ++++++++ 3 files changed, 41 insertions(+) create mode 100644 application-domain/src/main/kotlin/hs/kr/equus/application/domain/user/model/UserCache.kt create mode 100644 application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/entity/UserCacheRedisEntity.kt create mode 100644 application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/repository/UserCacheRepository.kt diff --git a/application-domain/src/main/kotlin/hs/kr/equus/application/domain/user/model/UserCache.kt b/application-domain/src/main/kotlin/hs/kr/equus/application/domain/user/model/UserCache.kt new file mode 100644 index 00000000..b55b3003 --- /dev/null +++ b/application-domain/src/main/kotlin/hs/kr/equus/application/domain/user/model/UserCache.kt @@ -0,0 +1,13 @@ +package hs.kr.equus.application.domain.user.model + +import java.util.* + +data class UserCache ( + val id: UUID, + val phoneNumber: String, + val name: String, + val isParent: Boolean, + val receiptCode: Long?, + val role: String, + val ttl: Long +) \ No newline at end of file diff --git a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/entity/UserCacheRedisEntity.kt b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/entity/UserCacheRedisEntity.kt new file mode 100644 index 00000000..21d0d0da --- /dev/null +++ b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/entity/UserCacheRedisEntity.kt @@ -0,0 +1,20 @@ +package hs.kr.equus.application.domain.user.domain.entity + +import hs.kr.equus.application.global.security.jwt.UserRole +import org.springframework.data.annotation.Id +import org.springframework.data.redis.core.RedisHash +import org.springframework.data.redis.core.TimeToLive +import java.util.* + +@RedisHash(value = "status_cache") +class UserCacheRedisEntity ( + @Id + val id: UUID, + val phoneNumber: String, + val name: String, + val isParent: Boolean, + val receiptCode: Long?, + val role: UserRole, + @TimeToLive + val ttl: Long +) \ No newline at end of file diff --git a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/repository/UserCacheRepository.kt b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/repository/UserCacheRepository.kt new file mode 100644 index 00000000..1510c1cd --- /dev/null +++ b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/repository/UserCacheRepository.kt @@ -0,0 +1,8 @@ +package hs.kr.equus.application.domain.user.domain.repository + +import hs.kr.equus.application.domain.user.domain.entity.UserCacheRedisEntity +import org.springframework.data.repository.CrudRepository +import java.util.UUID + +interface UserCacheRepository : CrudRepository { +} \ No newline at end of file From c62765ce7f771d55ffe9a4546a51c901565a84a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=8F=84=EA=B2=BD?= Date: Mon, 14 Oct 2024 02:27:21 +0900 Subject: [PATCH 2/6] modify :: User --- .../spi/ApplicationQueryUserPort.kt | 5 ++- .../user/domain/UserPersistenceAdapter.kt | 30 ++++++++++++--- .../global/feign/client/UserClient.kt | 37 ++++++++++++++++++- 3 files changed, 63 insertions(+), 9 deletions(-) diff --git a/application-domain/src/main/kotlin/hs/kr/equus/application/domain/application/spi/ApplicationQueryUserPort.kt b/application-domain/src/main/kotlin/hs/kr/equus/application/domain/application/spi/ApplicationQueryUserPort.kt index f2fadc3c..451fe247 100644 --- a/application-domain/src/main/kotlin/hs/kr/equus/application/domain/application/spi/ApplicationQueryUserPort.kt +++ b/application-domain/src/main/kotlin/hs/kr/equus/application/domain/application/spi/ApplicationQueryUserPort.kt @@ -1,8 +1,11 @@ package hs.kr.equus.application.domain.application.spi import hs.kr.equus.application.domain.user.model.User +import hs.kr.equus.application.domain.user.model.UserCache import java.util.UUID interface ApplicationQueryUserPort { - fun queryUserByUserId(userId: UUID): User + fun queryUserByUserId(userId: UUID): User? + + fun queryUserByUserIdInCache(userId: UUID): UserCache? } diff --git a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/UserPersistenceAdapter.kt b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/UserPersistenceAdapter.kt index c6275418..525c0fa7 100644 --- a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/UserPersistenceAdapter.kt +++ b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/UserPersistenceAdapter.kt @@ -1,6 +1,8 @@ package hs.kr.equus.application.domain.user.domain +import hs.kr.equus.application.domain.user.domain.repository.UserCacheRepository import hs.kr.equus.application.domain.user.model.User +import hs.kr.equus.application.domain.user.model.UserCache import hs.kr.equus.application.domain.user.spi.UserPort import hs.kr.equus.application.global.feign.client.UserClient import org.springframework.stereotype.Component @@ -9,15 +11,31 @@ import java.util.UUID @Component class UserPersistenceAdapter( private val userClient: UserClient, + private val userCacheRepository: UserCacheRepository ) : UserPort { - override fun queryUserByUserId(userId: UUID): User { - return userClient.getUserInfoByUserId(userId).run { + override fun queryUserByUserId(userId: UUID): User? { + return userClient.getUserInfoByUserId(userId)?.let { User( - id = id, - phoneNumber = phoneNumber, - name = name, - isParent = isParent, + id = it.id, + phoneNumber = it.phoneNumber, + name = it.name, + isParent = it.isParent, ) } } + + override fun queryUserByUserIdInCache(userId: UUID): UserCache? { + return userCacheRepository.findById(userId) + .map { + UserCache( + id = it.id, + phoneNumber = it.phoneNumber, + name = it.name, + isParent = it.isParent, + receiptCode = it.receiptCode, + role = it.role.name, + ttl = it.ttl + ) + }.orElse(null) + } } diff --git a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/UserClient.kt b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/UserClient.kt index df0e0915..a7d2e515 100644 --- a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/UserClient.kt +++ b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/UserClient.kt @@ -1,15 +1,48 @@ package hs.kr.equus.application.global.feign.client +import hs.kr.equus.application.domain.status.spi.StatusPort +import hs.kr.equus.application.domain.user.model.UserCache +import hs.kr.equus.application.domain.user.spi.UserPort +import hs.kr.equus.application.global.feign.client.dto.response.StatusInfoElement import hs.kr.equus.application.global.feign.client.dto.response.UserInfoElement +import hs.kr.equus.application.global.security.jwt.UserRole import org.springframework.cloud.openfeign.FeignClient +import org.springframework.context.annotation.Lazy +import org.springframework.stereotype.Component import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import java.util.UUID -@FeignClient(name = "UserClient", url = "\${url.user}") +@FeignClient(name = "UserClient", url = "\${url.user}", fallback = UserFallBack::class) interface UserClient { @GetMapping("/user/{userId}") fun getUserInfoByUserId( @PathVariable("userId") userId: UUID, - ): UserInfoElement + ): UserInfoElement? + +} + +@Component +class UserFallBack( + @Lazy private val userPort: UserPort +) : UserClient { + + override fun getUserInfoByUserId(userId: UUID): UserInfoElement? { + val user = userPort.queryUserByUserIdInCache(userId) + return user?.let { + UserInfoElement( + id = it.id, + isParent = it.isParent, + phoneNumber = it.phoneNumber, + name = it.name, + role = UserRole.valueOf(it.role) + ) + } ?: UserInfoElement( + id = userId, + phoneNumber = "", + name = "", + isParent = false, + role = UserRole.USER + ) + } } From 7628292054acb325071d73ed2ee7b51bad271298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=8F=84=EA=B2=BD?= Date: Mon, 14 Oct 2024 08:27:23 +0900 Subject: [PATCH 3/6] modify :: user client --- .../application/global/feign/client/UserClient.kt | 14 ++++++++------ .../feign/client/dto/response/UserInfoElement.kt | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/UserClient.kt b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/UserClient.kt index a7d2e515..a76da175 100644 --- a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/UserClient.kt +++ b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/UserClient.kt @@ -18,7 +18,7 @@ interface UserClient { @GetMapping("/user/{userId}") fun getUserInfoByUserId( @PathVariable("userId") userId: UUID, - ): UserInfoElement? + ): UserInfoElement } @@ -27,7 +27,7 @@ class UserFallBack( @Lazy private val userPort: UserPort ) : UserClient { - override fun getUserInfoByUserId(userId: UUID): UserInfoElement? { + override fun getUserInfoByUserId(userId: UUID): UserInfoElement { val user = userPort.queryUserByUserIdInCache(userId) return user?.let { UserInfoElement( @@ -35,14 +35,16 @@ class UserFallBack( isParent = it.isParent, phoneNumber = it.phoneNumber, name = it.name, - role = UserRole.valueOf(it.role) + role = UserRole.valueOf(it.role), + receiptCode = it.receiptCode ) } ?: UserInfoElement( id = userId, - phoneNumber = "", - name = "", + phoneNumber = "01000000000", + name = "홍길동", isParent = false, - role = UserRole.USER + role = UserRole.USER, + receiptCode = 0 ) } } diff --git a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/dto/response/UserInfoElement.kt b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/dto/response/UserInfoElement.kt index 598ea10a..0cf91d98 100644 --- a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/dto/response/UserInfoElement.kt +++ b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/dto/response/UserInfoElement.kt @@ -8,5 +8,6 @@ data class UserInfoElement( val phoneNumber: String, val name: String, val isParent: Boolean, + val receiptCode: Long?, val role: UserRole, ) From 943e2daa8f40d9dd8f4596c0f51ea80e652db524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=8F=84=EA=B2=BD?= Date: Mon, 14 Oct 2024 08:29:38 +0900 Subject: [PATCH 4/6] refactor --- .../application/spi/ApplicationQueryUserPort.kt | 2 +- .../domain/user/domain/UserPersistenceAdapter.kt | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/application-domain/src/main/kotlin/hs/kr/equus/application/domain/application/spi/ApplicationQueryUserPort.kt b/application-domain/src/main/kotlin/hs/kr/equus/application/domain/application/spi/ApplicationQueryUserPort.kt index 451fe247..f2780c03 100644 --- a/application-domain/src/main/kotlin/hs/kr/equus/application/domain/application/spi/ApplicationQueryUserPort.kt +++ b/application-domain/src/main/kotlin/hs/kr/equus/application/domain/application/spi/ApplicationQueryUserPort.kt @@ -5,7 +5,7 @@ import hs.kr.equus.application.domain.user.model.UserCache import java.util.UUID interface ApplicationQueryUserPort { - fun queryUserByUserId(userId: UUID): User? + fun queryUserByUserId(userId: UUID): User fun queryUserByUserIdInCache(userId: UUID): UserCache? } diff --git a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/UserPersistenceAdapter.kt b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/UserPersistenceAdapter.kt index 525c0fa7..689caf37 100644 --- a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/UserPersistenceAdapter.kt +++ b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/domain/user/domain/UserPersistenceAdapter.kt @@ -13,13 +13,13 @@ class UserPersistenceAdapter( private val userClient: UserClient, private val userCacheRepository: UserCacheRepository ) : UserPort { - override fun queryUserByUserId(userId: UUID): User? { - return userClient.getUserInfoByUserId(userId)?.let { + override fun queryUserByUserId(userId: UUID): User { + return userClient.getUserInfoByUserId(userId).run { User( - id = it.id, - phoneNumber = it.phoneNumber, - name = it.name, - isParent = it.isParent, + id = id, + phoneNumber = phoneNumber, + name = name, + isParent = isParent, ) } } From 03a0cb47b6a4ca9e3b829133e8e639b92661abe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=8F=84=EA=B2=BD?= Date: Mon, 14 Oct 2024 08:30:42 +0900 Subject: [PATCH 5/6] delete :: receipt code --- .../kr/equus/application/global/feign/client/UserClient.kt | 6 ++---- .../global/feign/client/dto/response/UserInfoElement.kt | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/UserClient.kt b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/UserClient.kt index a76da175..95b0285f 100644 --- a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/UserClient.kt +++ b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/UserClient.kt @@ -35,16 +35,14 @@ class UserFallBack( isParent = it.isParent, phoneNumber = it.phoneNumber, name = it.name, - role = UserRole.valueOf(it.role), - receiptCode = it.receiptCode + role = UserRole.valueOf(it.role) ) } ?: UserInfoElement( id = userId, phoneNumber = "01000000000", name = "홍길동", isParent = false, - role = UserRole.USER, - receiptCode = 0 + role = UserRole.USER ) } } diff --git a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/dto/response/UserInfoElement.kt b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/dto/response/UserInfoElement.kt index 0cf91d98..598ea10a 100644 --- a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/dto/response/UserInfoElement.kt +++ b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/feign/client/dto/response/UserInfoElement.kt @@ -8,6 +8,5 @@ data class UserInfoElement( val phoneNumber: String, val name: String, val isParent: Boolean, - val receiptCode: Long?, val role: UserRole, ) From 02b94d62d6001e6f35492b60e8257ae4ddd3eeee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=8F=84=EA=B2=BD?= Date: Mon, 14 Oct 2024 09:27:19 +0900 Subject: [PATCH 6/6] ktlint --- .../kotlin/hs/kr/equus/application/global/config/RedisConfig.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/config/RedisConfig.kt b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/config/RedisConfig.kt index 1ba14894..b79bae97 100644 --- a/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/config/RedisConfig.kt +++ b/application-infrastructure/src/main/kotlin/hs/kr/equus/application/global/config/RedisConfig.kt @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule import com.fasterxml.jackson.module.kotlin.KotlinModule import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -31,6 +32,7 @@ class RedisConfig { mapper.registerModule(KotlinModule()) mapper.activateDefaultTyping(LaissezFaireSubTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY) mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + mapper.registerModule(JavaTimeModule()) return mapper } } \ No newline at end of file