Skip to content

Commit

Permalink
refactor: 메인페이지 로드시 발생되는 중복되는 유저쿼리 캐시적용
Browse files Browse the repository at this point in the history
  • Loading branch information
SangWoon123 committed Sep 28, 2024
1 parent 84844a3 commit d24eaf9
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@
import com.tukorea.planding.global.oauth.details.Role;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@Builder
public class UserInfo {
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo{
private Long id;

private String username;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
package com.tukorea.planding.domain.user.service;

import com.tukorea.planding.domain.schedule.entity.Schedule;
import com.tukorea.planding.domain.user.dto.UserInfo;
import com.tukorea.planding.domain.user.entity.User;
import com.tukorea.planding.domain.user.repository.UserRepository;
import com.tukorea.planding.global.error.BusinessException;
import com.tukorea.planding.global.error.ErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.transaction.annotation.Transactional;

@Service
@Slf4j
@Transactional
@RequiredArgsConstructor
public class UserQueryService {
private final UserRepository userRepository;
Expand All @@ -24,20 +22,38 @@ public User save(User user) {
return userRepository.save(user);
}

@Transactional(readOnly = true)
public User getUserByUserCode(String userCode) {
return userRepository.findByUserCode(userCode)
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));
}

// 유저 정보를 조회하는 메서드에 캐싱을 적용
@Cacheable(value = "userInfoCache", key = "#userCode")
public UserInfo getUserInfo(String userCode) {
User user = getUserByUserCode(userCode);
return UserInfo.builder()
.id(user.getId())
.username(user.getUsername())
.email(user.getEmail())
.profileImage(user.getProfileImage())
.role(user.getRole())
.userCode(user.getUserCode())
.build();
}

@Transactional(readOnly = true)
public User getUserProfile(Long userId) {
return userRepository.getUserById(userId)
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));
}

@Transactional(readOnly = true)
public User findByEmail(String email) {
return userRepository.findByEmail(email).orElse(null);
}

@Transactional(readOnly = true)
public boolean existsByUserCode(String userCode) {
return userRepository.existsByUserCode(userCode);
}
Expand Down
48 changes: 48 additions & 0 deletions src/main/java/com/tukorea/planding/global/config/CacheConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.tukorea.planding.global.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator;
import com.tukorea.planding.domain.user.dto.UserInfo;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.CacheManager;
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.util.LinkedHashMap;

@Configuration
@RequiredArgsConstructor
public class CacheConfig {
private final RedisConnectionFactory redisConnectionFactory;

@Bean
public CacheManager redisCacheManager() {

// 다형성 타입 검증 설정 (UserInfo 같은 복잡한 타입 처리)
PolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder()
.allowIfSubType(Object.class)
.build();

// ObjectMapper에 다형성 처리 활성화
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.NON_FINAL); // 기본 다형성 처리

// RedisCacheConfiguration 설정
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer(objectMapper)));

// RedisCacheManager 생성
return RedisCacheManager.RedisCacheManagerBuilder
.fromConnectionFactory(redisConnectionFactory)
.cacheDefaults(redisCacheConfiguration)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.tukorea.planding.domain.user.dto.UserInfo;
import com.tukorea.planding.domain.user.entity.User;
import com.tukorea.planding.domain.user.repository.UserRepository;
import com.tukorea.planding.domain.user.service.UserQueryService;
import com.tukorea.planding.global.error.BusinessException;
import com.tukorea.planding.global.error.ErrorCode;
import jakarta.servlet.FilterChain;
Expand All @@ -19,11 +20,11 @@
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.nio.file.PathMatcher;
import java.util.Arrays;
import java.util.List;

Expand All @@ -44,18 +45,18 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenHandler jwtTokenHandler;
private final JwtUtil jwtUtil;
private final TokenService tokenService;
private final UserRepository userRepository;
private final TokenInfoCacheRepository tokenInfoCacheRepository;
private final UserQueryService userQueryService;


@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String refreshToken = jwtTokenHandler.extractRefreshToken(request)
.filter(jwtTokenHandler::validateToken)
.orElse(null);
log.info("refresh: {}",refreshToken);

if (refreshToken != null) {
log.info("refresh: {}",refreshToken);
checkRefreshTokenAndReIssueAccessToken(refreshToken, response);
return;
}
Expand Down Expand Up @@ -84,14 +85,11 @@ private void checkAccessTokenAndAuthentication(HttpServletRequest request, HttpS
.filter(jwtTokenHandler::validateToken)
.orElse(null);

log.info("access: {}",accessToken);


String userCode = jwtTokenHandler.extractClaim(accessToken, claims -> claims.get("code", String.class));

//TODO: 영속성 컨텍스트 1차 캐시, 2차 캐시가 적용되지않는이유
saveAuthentication(userQueryService.getUserInfo(userCode));

saveAuthentication(userRepository.findByUserCode(userCode)
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)));

filterChain.doFilter(request, response);
}
Expand Down Expand Up @@ -120,15 +118,7 @@ private void checkRefreshTokenAndReIssueAccessToken(
jwtUtil.sendAccessAndRefreshToken(response, newAccessToken, refreshToken);
}

private void saveAuthentication(User user) {
UserInfo userInfo = UserInfo.builder()
.id(user.getId())
.email(user.getEmail())
.username(user.getUsername())
.profileImage(user.getProfileImage())
.role(user.getRole())
.userCode(user.getUserCode())
.build();
private void saveAuthentication(UserInfo userInfo) {
Authentication authentication = getAuthentication(userInfo);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,25 @@

import com.tukorea.planding.domain.user.repository.UserRepository;
import com.tukorea.planding.domain.user.entity.User;
import com.tukorea.planding.domain.user.service.UserQueryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
@RequiredArgsConstructor
@Slf4j
public class CustomUserDetailsService implements UserDetailsService {

private final UserRepository userRepository;
private final UserQueryService userQueryService;

@Override
public UserDetails loadUserByUsername(String userCode) throws UsernameNotFoundException {
User user = userRepository.findByUserCode(userCode)
.orElseThrow(() -> new RuntimeException("존재하지않는 유저입니다."));
User user = userQueryService.getUserByUserCode(userCode);
return new CustomUser(user.getUsername(), user.getEmail() ,user.getRole());
}
}

0 comments on commit d24eaf9

Please sign in to comment.