From 475051df780fa4c7b42a9851cb617cc91ed80409 Mon Sep 17 00:00:00 2001 From: smagles Date: Wed, 20 Aug 2025 22:39:28 +0200 Subject: [PATCH] add online field and cache for user info --- .../java/ua/everybuy/config/RedisConfig.java | 37 +++++++++++++++---- .../routing/dto/ShortUserInfoDto.java | 3 ++ .../integration/UserProfileService.java | 26 +++++++++++-- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/main/java/ua/everybuy/config/RedisConfig.java b/src/main/java/ua/everybuy/config/RedisConfig.java index 5afe31a..2264980 100644 --- a/src/main/java/ua/everybuy/config/RedisConfig.java +++ b/src/main/java/ua/everybuy/config/RedisConfig.java @@ -4,22 +4,45 @@ 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.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.time.Duration; +import java.util.Map; @Configuration @EnableCaching public class RedisConfig { + + private static final String SHORT_USER_INFO_CACHE = "shortUserInfo"; + private static final Duration DEFAULT_TTL = Duration.ofDays(10); + private static final Duration SHORT_USER_INFO_TTL = Duration.ofMinutes(2); + @Bean - public RedisCacheConfiguration cacheConfiguration() { - return RedisCacheConfiguration.defaultCacheConfig() - .entryTtl(Duration.ofHours(240)) + public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { + + RedisSerializationContext.SerializationPair keySerializer = + RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()); + RedisSerializationContext.SerializationPair valueSerializer = + RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()); + + RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig() + .entryTtl(DEFAULT_TTL) .disableCachingNullValues() - .serializeKeysWith(RedisSerializationContext - .SerializationPair.fromSerializer(new StringRedisSerializer())) - .serializeValuesWith(RedisSerializationContext - .SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); + .serializeKeysWith(keySerializer) + .serializeValuesWith(valueSerializer); + + RedisCacheConfiguration shortUserInfoConfig = defaultCacheConfig.entryTtl(SHORT_USER_INFO_TTL); + + Map cacheConfigs = Map.of( + SHORT_USER_INFO_CACHE, shortUserInfoConfig + ); + + return RedisCacheManager.builder(redisConnectionFactory) + .cacheDefaults(defaultCacheConfig) + .withInitialCacheConfigurations(cacheConfigs) + .build(); } } diff --git a/src/main/java/ua/everybuy/routing/dto/ShortUserInfoDto.java b/src/main/java/ua/everybuy/routing/dto/ShortUserInfoDto.java index 82f3dde..45c8902 100644 --- a/src/main/java/ua/everybuy/routing/dto/ShortUserInfoDto.java +++ b/src/main/java/ua/everybuy/routing/dto/ShortUserInfoDto.java @@ -1,14 +1,17 @@ package ua.everybuy.routing.dto; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @Getter @NoArgsConstructor @AllArgsConstructor +@Builder public class ShortUserInfoDto{ private long userId; private String fullName; private String photoUrl; + private boolean online; } diff --git a/src/main/java/ua/everybuy/service/integration/UserProfileService.java b/src/main/java/ua/everybuy/service/integration/UserProfileService.java index 528e29d..22fd188 100644 --- a/src/main/java/ua/everybuy/service/integration/UserProfileService.java +++ b/src/main/java/ua/everybuy/service/integration/UserProfileService.java @@ -1,35 +1,53 @@ package ua.everybuy.service.integration; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; +import org.springframework.web.util.UriComponentsBuilder; import ua.everybuy.routing.dto.*; import ua.everybuy.routing.dto.response.UserShortInfoResponse; +@Slf4j @Service @RequiredArgsConstructor public class UserProfileService { - private static final String SHORT_INFO_ENDPOINT = "/short-info?userId="; @Value("${user.service.url}") private String userServiceUrl; @Value("${user.default.avatar.url}") private String defaultAvatarUrl; private final ExchangeService exchangeService; + @Cacheable(value = "shortUserInfo", key = "#userId") public ShortUserInfoDto getShortUserInfo(Long userId) { try { - String shortUserInfoUrl = userServiceUrl + SHORT_INFO_ENDPOINT + userId; + String shortUserInfoUrl = buildShortUserInfoUrl(userId); UserShortInfoResponse response = exchangeService .exchangeGetRequest(shortUserInfoUrl, UserShortInfoResponse.class).getBody(); return response != null ? response.getData() : createDefaultShortUserInfo(userId); } catch (Exception e) { + log.error("Failed to fetch short user info for userId={}, " + + "returning default user info. Error: {}", + userId, e.getMessage(), e); return createDefaultShortUserInfo(userId); } } private ShortUserInfoDto createDefaultShortUserInfo(Long userId) { - return new ShortUserInfoDto(userId, "Unknown User", - defaultAvatarUrl); + return ShortUserInfoDto.builder() + .userId(userId) + .fullName("Unknown User") + .photoUrl(defaultAvatarUrl) + .online(false) + .build(); + } + + private String buildShortUserInfoUrl(Long userId) { + return UriComponentsBuilder.fromHttpUrl(userServiceUrl) + .path("/short-info") + .queryParam("userId", userId) + .toUriString(); } }