본문 바로가기
기술/Spring-Boot

[Redis] 초보자도 할 수 있다 DTO 매핑

by Zabee52 2022. 1. 16.

Redis

먼저 결과 코드를 쓰자면 이거다.

public StatDictResponseDto getDto(String key){
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Dto.class));
        ValueOperations<String, Dto> redis = redisDtoTemplate.opsForValue();
        Dto data = redis.get(key);
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
        return data;
    }

 

이틀동안 붙잡고 있던 문제였다. 단순하지 않은 구조의(내부에 List<>를 가지고 있는 형태의) DTO를 Redis로 불러오려고 하니 정상적으로 매핑되지 않고 java.util.LinkedHashMap cannot be cast to ... 오류메세지가 출력되는 문제였다.

나는 DTO로 SET을 했는데, 왜 LinkedHashMap인 줄 아는거냐고. 의문에 의문이 뒤따랐다. 내부 필드 하나하나를 전부 캐싱하고 불러오는 식으로 해야하나? 하는 생각까지 들었다.

근데 Redis key를 직접 확인해보면 데이터는 잘 들어가 있는 상태였다. 그것을 보면서 내가 레디스를 뭔가 잘못 쓰고 있구나 하는 생각이 들었다.

 

프로젝트가 이제는 일주일가량 남았다. 사실 이제 와서 레디스를 공부하기엔 많이 촉박하다. 런칭도 해야하기때문에 이 문제를 해결하기 위해 주어진 시간은 일주일보다도 더 적다. 어차피 속성으로 배운 것, 속성으로 해결해야 했다. 그래서 이것저것 자료를 찾아보기 시작했다.

단서는 아래 블로그에서 얻었다. 감사의 뜻을 전합니다.

 

 

[SpringBoot Redis] Redis에 커스텀 객체 저장 시 오류 - Azderica

[SpringBoot Redis] Redis에 커스텀 객체 저장 시 오류 Posted 4. June 2021. 3 min read. Redis HashValue 에 커스텀 객체 저장 시 오류 발생점. 스프링으로 개발을 진행하던 중, Redis HashValue에 커스텀 데이터 객체를

azderica.github.io

 

가장 먼저 들었던 생각은 '그러면 그동안 다른 DTO는 어떻게 매핑하고 있었던거지?' 였다.

답은 가까이에 있었다. 처음 레디스를 세팅했을 때, 그 형식을 직접 지정해준 것이었다. Jackson으로. 내가 직접. 내 손으로.

 

 

[SpringBoot/Redis/Ubuntu] 우분투 환경에 Redis 설치, SpringBoot에 세팅

Redis Redis. 얼마나 좋길래 이렇게 추천을 받는 것인지. 써보고 싶어졌다. 그래서 세팅해본다. 1. ubuntu 환경에 Redis 설치 $sudo apt-get update $sudo apt-get install -y redis-server 2. Redis configuratio..

dazbee.tistory.com

 

@Bean
    public RedisTemplate<?, ?> redisTemplate() {
        RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        return redisTemplate;
    }

여기서 ValueSerializer를 설정해줬기 때문에 일반 클래스가 레디스에 잘 들어갈 수 있었던 것이다. 이 순간 깨달음을 얻었다. 그러면 이 시리얼라이저를 잘 건드리면 어떻게 잘 해볼 수 있지 않을까?

 

그래서 코드를 바로 건드려봤다.

 

public void setDto(String key, Dto object){
    redisTemplate.delete(key);

    redisDtoTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Dto.class));
    ValueOperations<String, Dto> redis = redisDtoTemplate.opsForValue();
    redis.set(key, object);
    redisTemplate.expire(key, 10, TimeUnit.MINUTES);
}

 

결과는 성공이었다. 해당 Dto 형식으로 값을 세팅 하는 것도, 불러오는 것도 잘 되었다. 자동으로 형식을 지정해주던 것을 명시적으로 정의해주니 잘 되는 것이다. 속성으로 공부하는 것이 이렇게 무섭다. 아마 위의 코드도 임시방편같은 것일 수 있다. 진짜 나중에 제대로 공부해서 다시 만들어봐야겠다.

 

뭐 아무튼 오늘도 문제 해결. 기쁘다.

 

 

 

추가)

문제 해결이 아니었다. template를 변경하면 해당 인스턴스에 대해서만 바뀌는 줄 알았는데 redistemplate 전체에서 바뀌는 것이었다. 야매로 적용된 기술의 한계다. 그래서 해결도 야매로 했다.

public StatDictResponseDto getDto(String key){
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Dto.class));
        ValueOperations<String, Dto> redis = redisDtoTemplate.opsForValue();
        Dto data = redis.get(key);
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
        return data;
    }

set이 아닌 get 쪽에서 값을 받아올 때만 잠깐 바꿔주고 원복하는 형식으로 해주었다.

댓글