본문 바로가기
코딩 공부/web & Java

[Spring / Redis] Spring에서 Redis 사용

by 현장 2024. 10. 10.

Spring에서 Redis 사용

레디스 관련 설명은 여기를 참고해 주세요!

🏷️ Redis 의존성

// redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

🏷️ Redis 설정

@RequiredArgsConstructor
@EnableRedisRepositories
@Configuration
public class RedisConfig {

    @Value("${spring.data.redis.host}")
    private String redisHost;

    @Value("${spring.data.redis.port}")
    private int redisPort;

    @Value("${spring.data.redis.password}")  // 패스워드 추가
    private String redisPassword;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        // Redis 명령이 2초 안에 완료되지 않으면 타임아웃을 발생시키기 위한 설정
        LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
                .commandTimeout(Duration.ofSeconds(2))
                .build();

        // RedisStandaloneConfiguration에 호스트, 포트, 패스워드 설정
        RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration();
        redisConfig.setHostName(redisHost); // 호스트 서정
        redisConfig.setPort(redisPort); // 포트 설정
        redisConfig.setPassword(redisPassword);  // 패스워드 설정

        return new LettuceConnectionFactory(redisConfig, clientConfig);
    }

    @Bean
    public RedisTemplate<String, UserAccount> userAccountRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // 템플릿의 레디스의 키 벨류를 설정
        RedisTemplate<String, UserAccount> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory); // 레디스 템플릿과 연결할 펙토리 셋팅
        redisTemplate.setKeySerializer(new StringRedisSerializer()); // 키 직렬화시 키를 문자열로 변환해 저장
        // 직렬화할 타입 명시 -> UserAccount를 JSON형식으로 변환해 저장
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(UserAccount.class));

        return redisTemplate;
    }
}

🏷️ Redis에서 저장, 조회를 위해 레포지토리 작성

userId를 기준으로 관리를 할 것이기 때문에 아래와 같이 작성했습니다.

@Slf4j
@RequiredArgsConstructor
@Repository
public class UserAccountCacheRepository {
    // redis에 저장, 가져오기 위한 레포지토리
    private final RedisTemplate<String, UserAccount> userAccountRedisTemplate;
    // redis에 저장되어 있는 일수 지정
    private final static Duration USER_CACHE_TTL = Duration.ofDays(3);

    public void setUserAccount(UserAccount userAccount) {
        String key = getKey(userAccount.getUserId());
        log.info("Redis에 UserAccount를 셋팅 {} , {}", userAccount, key);

        userAccountRedisTemplate.opsForValue().set(key, userAccount, USER_CACHE_TTL);
    }

    public Optional<UserAccount> getUserAccount(String userId){
        String key = getKey(userId);
        UserAccount userAccount = userAccountRedisTemplate.opsForValue().get(key);

        return Optional.ofNullable(userAccount);
    }

    public void deleteUserAccount(String userId) {
        String key = getKey(userId);
        log.info("Redis에서 UserAccount를 삭제합니다. 키: {}", key);

        userAccountRedisTemplate.delete(key);
    }

    private String getKey(String userId) {
        return "USER:" + userId;
    }
}

위와 같이 userId를 가지고 UserAccount 객체를 저장하는 레포지토리를 작성했습니다.

🏷️ Redis를 사용한 조회 메소드

public UserAccount getUserAccountOrException(String userId) {
    // redis에서 먼처 찾고 없는 경우 userAccount 저장소에서 찾도록 함
    return userAccountCacheRepository.getUserAccount(userId).orElseGet(() ->
            userAccountRepository.findById(userId).orElseThrow(
                    () -> new DoubleSApplicationException(
                            ErrorCode.USER_NOT_FOUND, String.format("%s를 찾지 못했습니다", userId))
            )
    );
}

아래와 같이 사용했습니다.

// 로그인
public String login(String userId, String password) {
    // 회원 가입 체크
    UserAccount userAccount = serviceUtils.getUserAccountOrException(userId);

    // 비밀 번호 체크
    if (!encoder.matches(password, userAccount.getPassword())) {
        throw new DoubleSApplicationException(ErrorCode.INVALID_PASSWORD);
    }

    userAccountCacheRepository.setUserAccount(userAccount);

    // 토큰 생성
    return JwtTokenUtils.createJwtToken(userId, secretKey, expiredTimeMs);
}