diff --git a/src/main/java/com/pickyfy/pickyfy/auth/filter/CustomLoginFilter.java b/src/main/java/com/pickyfy/pickyfy/auth/filter/CustomLoginFilter.java index 563a77b..902fcff 100644 --- a/src/main/java/com/pickyfy/pickyfy/auth/filter/CustomLoginFilter.java +++ b/src/main/java/com/pickyfy/pickyfy/auth/filter/CustomLoginFilter.java @@ -59,7 +59,7 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR String accessToken = jwtUtil.createAccessToken(principal, role); String refreshToken = jwtUtil.createRefreshToken(principal, role); - redisUtil.setDataExpire("refresh:" + jwtUtil.getPrincipal(refreshToken), refreshToken, Constant.REFRESH_TOKEN_EXPIRATION_TIME); + redisUtil.setData("refresh:" + jwtUtil.getPrincipal(refreshToken), refreshToken, Constant.REFRESH_TOKEN_EXPIRATION_TIME); setBody(role, response); ResponseCookie accessCookie = createCookie("accessToken", accessToken, Constant.ACCESS_TOKEN_EXPIRATION_TIME, "/"); diff --git a/src/main/java/com/pickyfy/pickyfy/auth/handler/OAuth2SuccessHandler.java b/src/main/java/com/pickyfy/pickyfy/auth/handler/OAuth2SuccessHandler.java index 329dcc4..7c84e9e 100644 --- a/src/main/java/com/pickyfy/pickyfy/auth/handler/OAuth2SuccessHandler.java +++ b/src/main/java/com/pickyfy/pickyfy/auth/handler/OAuth2SuccessHandler.java @@ -35,7 +35,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo String accessToken = jwtUtil.createAccessToken(email, "USER"); String refreshToken = jwtUtil.createRefreshToken(email, "USER"); - redisUtil.setDataExpire("refresh:" + email, refreshToken, Constant.REFRESH_TOKEN_EXPIRATION_TIME); + redisUtil.setData("refresh:" + email, refreshToken, Constant.REFRESH_TOKEN_EXPIRATION_TIME); ResponseCookie accessCookie = createCookie("accessToken", accessToken, Constant.ACCESS_TOKEN_EXPIRATION_TIME, "/"); response.addHeader(HttpHeaders.SET_COOKIE, accessCookie.toString()); diff --git a/src/main/java/com/pickyfy/pickyfy/common/Constant.java b/src/main/java/com/pickyfy/pickyfy/common/Constant.java index af51cfc..6911102 100644 --- a/src/main/java/com/pickyfy/pickyfy/common/Constant.java +++ b/src/main/java/com/pickyfy/pickyfy/common/Constant.java @@ -9,5 +9,10 @@ public class Constant { public static final long ACCESS_TOKEN_EXPIRATION_TIME = 30 * 60 * 1000; public static final long REFRESH_TOKEN_EXPIRATION_TIME = 7 * 24 * 60 * 60 * 1000; + public static final long CATEGORIES_EXPIRATION_TIME = 24 * 60 * 60 * 1000; + public static final long MAGAZINES_EXPIRATION_TIME = 60 * 60 * 1000; + public static final long PLACES_EXPIRATION_TIME = 30 * 60 * 1000; + public static final long PLACE_EXPIRATION_TIME = 30 * 60 * 1000; + public static final String REDIS_KEY_PREFIX = "refresh:"; } diff --git a/src/main/java/com/pickyfy/pickyfy/common/config/RedisConfig.java b/src/main/java/com/pickyfy/pickyfy/common/config/RedisConfig.java index e500363..a6d8369 100644 --- a/src/main/java/com/pickyfy/pickyfy/common/config/RedisConfig.java +++ b/src/main/java/com/pickyfy/pickyfy/common/config/RedisConfig.java @@ -1,12 +1,30 @@ package com.pickyfy.pickyfy.common.config; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.pickyfy.pickyfy.common.Constant; import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.transaction.TransactionAwareCacheManagerProxy; 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.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; @Configuration +@EnableCaching public class RedisConfig { @Value("${spring.data.redis.host}") @@ -19,4 +37,32 @@ public class RedisConfig { public RedisConnectionFactory redisConnectionFactory() { return new LettuceConnectionFactory(host, port); } + + @Bean + public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + + RedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer(objectMapper); + RedisSerializer stringSerializer = new StringRedisSerializer(); + + RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig() + .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringSerializer)) + .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jsonSerializer)); + + Map cacheConfigurations = new HashMap<>(); + cacheConfigurations.put("place", defaultConfig.entryTtl(Duration.ofMillis(Constant.PLACE_EXPIRATION_TIME))); + cacheConfigurations.put("places", defaultConfig.entryTtl(Duration.ofMillis(Constant.PLACES_EXPIRATION_TIME))); + cacheConfigurations.put("magazines", defaultConfig.entryTtl(Duration.ofMillis(Constant.MAGAZINES_EXPIRATION_TIME))); + cacheConfigurations.put("categories", defaultConfig.entryTtl(Duration.ofMillis(Constant.CATEGORIES_EXPIRATION_TIME))); + + RedisCacheManager manager = RedisCacheManager.builder(connectionFactory) + .cacheDefaults(defaultConfig) + .withInitialCacheConfigurations(cacheConfigurations) + .build(); + + return new TransactionAwareCacheManagerProxy(manager); + } } \ No newline at end of file diff --git a/src/main/java/com/pickyfy/pickyfy/common/util/RedisUtil.java b/src/main/java/com/pickyfy/pickyfy/common/util/RedisUtil.java index 39b3c23..c1606de 100644 --- a/src/main/java/com/pickyfy/pickyfy/common/util/RedisUtil.java +++ b/src/main/java/com/pickyfy/pickyfy/common/util/RedisUtil.java @@ -16,26 +16,24 @@ public class RedisUtil { private final StringRedisTemplate stringRedisTemplate; - public void setDataExpire(String key, String value, long duration) { + public String getData(String key) { try { ValueOperations valueOperations = stringRedisTemplate.opsForValue(); - Duration expireDuration = Duration.ofMillis(duration); - valueOperations.set(key, value, expireDuration); - }catch(DataAccessException e){ - throw new ExceptionHandler(ErrorStatus._INTERNAL_SERVER_ERROR); + return valueOperations.get(key); + } catch (DataAccessException e) { + throw new ExceptionHandler(ErrorStatus.KEY_NOT_FOUNT); } } - public String getData(String key){ + public void setData(String key, String value, long duration) { try { ValueOperations valueOperations = stringRedisTemplate.opsForValue(); - return valueOperations.get(key); - } catch(DataAccessException e){ - throw new ExceptionHandler(ErrorStatus.KEY_NOT_FOUNT); + valueOperations.set(key, value, Duration.ofMillis(duration)); + } catch (DataAccessException e) { + throw new ExceptionHandler(ErrorStatus._INTERNAL_SERVER_ERROR); } } - - public void deleteRefreshToken(String redisKey) { + public void deleteData(String redisKey) { try { stringRedisTemplate.delete(redisKey); } catch (DataAccessException e) { diff --git a/src/main/java/com/pickyfy/pickyfy/service/AuthServiceImpl.java b/src/main/java/com/pickyfy/pickyfy/service/AuthServiceImpl.java index af2a802..691b7e2 100644 --- a/src/main/java/com/pickyfy/pickyfy/service/AuthServiceImpl.java +++ b/src/main/java/com/pickyfy/pickyfy/service/AuthServiceImpl.java @@ -18,7 +18,7 @@ public class AuthServiceImpl implements AuthService{ @Override public void logout(String refreshToken){ - redisUtil.deleteRefreshToken(Constant.REDIS_KEY_PREFIX + jwtUtil.getPrincipal(refreshToken)); + redisUtil.deleteData(Constant.REDIS_KEY_PREFIX + jwtUtil.getPrincipal(refreshToken)); } @Override @@ -28,7 +28,7 @@ public AuthResponse reIssue(String token){ String accessToken = jwtUtil.createAccessToken(principal, jwtUtil.getRole(token)); String refreshToken = jwtUtil.createRefreshToken(principal, jwtUtil.getRole(token)); - redisUtil.setDataExpire("refresh:" + jwtUtil.getPrincipal(refreshToken), refreshToken, Constant.REFRESH_TOKEN_EXPIRATION_TIME); + redisUtil.setData("refresh:" + jwtUtil.getPrincipal(refreshToken), refreshToken, Constant.REFRESH_TOKEN_EXPIRATION_TIME); return AuthResponse.from(accessToken, refreshToken); } diff --git a/src/main/java/com/pickyfy/pickyfy/service/CategoryServiceImpl.java b/src/main/java/com/pickyfy/pickyfy/service/CategoryServiceImpl.java index 25db451..cd2ae12 100644 --- a/src/main/java/com/pickyfy/pickyfy/service/CategoryServiceImpl.java +++ b/src/main/java/com/pickyfy/pickyfy/service/CategoryServiceImpl.java @@ -11,6 +11,7 @@ import java.util.List; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -40,12 +41,14 @@ public CategoryResponse getCategory(Long id) { } @Override + @Cacheable(value = "categories", key = "'all'", unless = "#result.isEmpty()") public List getAllCategories() { return categoryRepository.findAll().stream() .map(CategoryResponse::from) .collect(Collectors.toList()); } + @Override @Transactional public void updateCategory(Long id, CategoryTypeRequest request) { diff --git a/src/main/java/com/pickyfy/pickyfy/service/EmailServiceImpl.java b/src/main/java/com/pickyfy/pickyfy/service/EmailServiceImpl.java index 953aba4..aa57758 100644 --- a/src/main/java/com/pickyfy/pickyfy/service/EmailServiceImpl.java +++ b/src/main/java/com/pickyfy/pickyfy/service/EmailServiceImpl.java @@ -68,7 +68,7 @@ private void sendVerificationEmail(String code, String email) { throw new ExceptionHandler(ErrorStatus._INTERNAL_SERVER_ERROR); } - redisUtil.setDataExpire("email:" + email, code, Constant.EMAIL_TOKEN_EXPIRATION_TIME); + redisUtil.setData("email:" + email, code, Constant.EMAIL_TOKEN_EXPIRATION_TIME); } private MimeMessage createMimeMessage(String code, String email) throws MessagingException { diff --git a/src/main/java/com/pickyfy/pickyfy/service/MagazineServiceImpl.java b/src/main/java/com/pickyfy/pickyfy/service/MagazineServiceImpl.java index 086ce00..5cba506 100644 --- a/src/main/java/com/pickyfy/pickyfy/service/MagazineServiceImpl.java +++ b/src/main/java/com/pickyfy/pickyfy/service/MagazineServiceImpl.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -40,6 +41,7 @@ public MagazineResponse getMagazine(Long id) { } @Override + @Cacheable(value = "magazines", key = "'all'", unless = "#result.isEmpty()") public List getAllMagazines() { return magazineRepository.findAll().stream() .map(MagazineResponse::from) diff --git a/src/main/java/com/pickyfy/pickyfy/service/PlaceServiceImpl.java b/src/main/java/com/pickyfy/pickyfy/service/PlaceServiceImpl.java index 076049d..49f19ab 100644 --- a/src/main/java/com/pickyfy/pickyfy/service/PlaceServiceImpl.java +++ b/src/main/java/com/pickyfy/pickyfy/service/PlaceServiceImpl.java @@ -16,6 +16,8 @@ import java.util.*; import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -42,6 +44,7 @@ public class PlaceServiceImpl implements PlaceService { * 특정 유저가 저장한 Place 전체 조회 */ @Override + @Cacheable(value = "place", key = "#email", unless = "#result.isEmpty()") public List getUserSavePlace(String email) { // 유저 조회 User user = findUserByEmail(email); @@ -89,7 +92,9 @@ public PlaceSearchResponse getPlace(Long placeId) { /** * 유저 Place 저장 및 저장취소 (toggle) */ + @Override @Transactional + @CacheEvict(value = "place", key = "#email") public boolean togglePlaceUser(String email, Long placeId) { Place place = findPlaceById(placeId); User user = findUserByEmail(email); @@ -114,6 +119,7 @@ public List searchNearbyPlaces(NearbyPlaceSearchRequest request) { } @Transactional + @CacheEvict(value = "places", key = "'all'") public Long createPlace(PlaceCreateRequest request, List imageList) { if (placeRepository.existsPlaceByName(request.name())) { throw new EntityExistsException(ErrorStatus.PLACE_NAME_DUPLICATED.getMessage()); @@ -150,6 +156,7 @@ public Long createPlace(PlaceCreateRequest request, List imageLis @Override @Transactional + @CacheEvict(value = "places", key = "'all'") public Long updatePlace(Long placeId, PlaceCreateRequest request, List imageList) { Place place = findPlaceById(placeId); @@ -162,6 +169,7 @@ public Long updatePlace(Long placeId, PlaceCreateRequest request, List getAllPlaces() { List allPlaceList = placeRepository.findAll(); return allPlaceList.stream() diff --git a/src/main/java/com/pickyfy/pickyfy/service/UserServiceImpl.java b/src/main/java/com/pickyfy/pickyfy/service/UserServiceImpl.java index c6acbb2..c5843c7 100644 --- a/src/main/java/com/pickyfy/pickyfy/service/UserServiceImpl.java +++ b/src/main/java/com/pickyfy/pickyfy/service/UserServiceImpl.java @@ -84,7 +84,7 @@ public void verifyByEmail(String email){ } private void invalidateTokens(String userEmail){ - redisUtil.deleteRefreshToken(Constant.REDIS_KEY_PREFIX + userEmail); + redisUtil.deleteData(Constant.REDIS_KEY_PREFIX + userEmail); } private void validateEmailToken(String email, String token){