[Springboot] '์ตœ๊ทผ ์ฝ์€ ๊ธ€' Dto๋กœ Redis์— ์ €์žฅํ•˜๊ณ  ์กฐํšŒํ•˜๊ธฐ AtoZ

2021. 6. 18. 17:53ใ†๐ŸŒฑ Develop/Server

โ“ redis ๋ฅผ ์„ ํƒํ•œ ์ด์œ 

๋ธ”๋กœ๊ทธ ํ™ˆํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“œ๋Š” ํ”„๋กœ์ ํŠธ์—์„œ, "์ตœ๊ทผ ์ฝ์€ ๊ธ€" ์„ ๊ฐœ๋ฐœํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. velog ๊ฐ™์€ ์„œ๋น„์Šค์—์„œ๋Š” ๊ฝค ์˜ค๋žœ ๊ธฐ๊ฐ„๋™์•ˆ ๋‚ด๊ฐ€ ์ฝ์€ ๊ธ€์„ ์ €์žฅํ•˜๋Š” ๋“ฏ ํ–ˆ๋Š”๋ฐ, ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์˜ ๊ธฐํš์—์„œ๋Š” ์ผ์ฃผ์ผ์ด๋ผ๋Š” ๊ธฐ๊ฐ„์ด ์ง€์ •๋˜์–ด์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” ํ…Œ์ด๋ธ”์„ ํ•˜๋‚˜ ๋” ์ƒ์„ฑํ•ด์•ผํ•˜๋‚˜ ๊ณ ๋ฏผ์ด ๋˜์—ˆ๋Š”๋ฐ, ์ฝ์€ ๊ธ€ ํŠน์„ฑ ์ƒ ๋‹จ๊ธฐ๊ฐ„์— ๋งŽ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์ˆ˜์ง‘๋œ๋‹ค๋Š” ์ ๊ณผ ๋งŒ๋ฃŒ ๊ธฐ๊ฐ„์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์„ฑ๋Šฅ ์ƒ์œผ๋กœ ์ข‹์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ค ์ด์ „ ํ”„๋กœ์ ํŠธ์—์„œ refreshToken์„ ์ €์žฅํ•  ๋•Œ redis๋ฅผ ์‚ฌ์šฉํ–ˆ๋˜ ๊ฒƒ์ด ์ƒ๊ฐ๋‚˜์„œ, redis๋กœ ์กฐํšŒํ•œ ๊ธ€ ๋ฐ์ดํ„ฐ๋ฅผ ์บ์‹ฑํ•˜๊ณ , ์ผ์ • ๊ธฐ๊ฐ„์ด ์ง€๋‚˜๋ฉด ์‚ญ์ œ๋˜๋Š” ๊ธฐ๋Šฅ์„ ์ ์šฉํ•ด๋ณด๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ ๊ตฌํ˜„ํ•ด์•ผํ•˜๋Š” ๊ธฐ๋Šฅ

  1. redis list ์ž๋ฃŒํ˜•์„ ์‚ฌ์šฉํ•˜์—ฌ postDto๋กœ์ €์žฅ
  2. key ๊ฐ’์„ ํ†ตํ•ด postDto๋ฅผ ์ €์žฅํ•œ๋ชฉ๋ก ์กฐํšŒ

1๏ธโƒฃ springboot ์— redis ์„ค์ •

build.gradle์— ์˜์กด์„ฑ ์ถ”๊ฐ€

implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-redis', version: '2.3.12.RELEASE'

application.yaml ์— spring redis ์„ค์ • ์ถ”๊ฐ€ - local

spring:
    redis:
        host: localhost 
        port: 6379

 

๐Ÿ‘‰ ๋ฐฐํฌ ์„œ๋ฒ„์— redis ์„ค์ •

์‹ค์ œ ์„œ๋ฒ„์— ์žˆ๋Š” docker ์ด๋ฏธ์ง€์ธ Redis์™€ ์—ฐ๊ฒฐํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•ด์ค๋‹ˆ๋‹ค. redis๋Š” docker-compose ๋กœ ์‹คํ–‰ํ•  ๋•Œ ์ปจํ…Œ์ด๋„ˆ๋ช…์ž…๋‹ˆ๋‹ค. redis ๋„์ปค ์ด๋ฏธ์ง€์™€ ์—ฐ๊ฒฐํ•˜๋ ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์„œ๋ฒ„ ๋กœ์ปฌ redis์™€ ์—ฐ๊ฒฐํ•˜๋ ค๋ฉด ip ์ฃผ์†Œ๋ฅผ ์ ์–ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

spring:
    redis:
        host: redis(์ปจํ…Œ์ด๋„ˆ ๋ช…)
        port: 6379

EC2 ์„œ๋ฒ„์—์„œ docker pull redis ๋กœ ์ตœ์‹  redis ์ด๋ฏธ์ง€๋ฅผ ๋‹ค์šด๋ฐ›๊ณ  docker-compose.yml ํŒŒ์ผ์— redis ์„ค์ • ์ถ”๊ฐ€๋„ ํ•ด์ค๋‹ˆ๋‹ค.

redis:
    container_name: redis
    hostname: redis
    image: redis
    command: ["redis-server", "--bind", "redis", "--port", "6379"]
    ports:
      - "6379:6379"
    restart: always
    networks: # ์„œ๋ฒ„์™€ ๊ฐ™์€ ๋„คํŠธ์›Œํฌ, ์žŠ์ง€ ๋งˆ์„ธ์š”!
       - backend

 server:
   ....
   depends_on:
             - redis




2๏ธโƒฃ RedisConfiguration ์„ค์ •ํ•˜๊ธฐ

๐Ÿ“‚ config/redisRepositoryConfig

@Configuration
@EnableRedisRepositories(basePackages = "com.yapp18.retrospect.config")
public class RedisRepositoryConfig extends CachingConfigurerSupport {

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

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


    // jackson LocalDateTime mapper
    @Bean public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // timestamp ํ˜•์‹ ์•ˆ๋”ฐ๋ฅด๋„๋ก ์„ค์ •
        mapper.registerModules(new JavaTimeModule(), new Jdk8Module()); // LocalDateTime ๋งคํ•‘์„ ์œ„ํ•ด ๋ชจ๋“ˆ ํ™œ์„ฑํ™”
        return mapper;
    }


    // redisConnectionFactory ๋ฅผ ํ†ตํ•ด ์™ธ๋ถ€ redis ๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
    @Bean
    public RedisConnectionFactory redisConnectionFactory(){
        return new LettuceConnectionFactory(redisHost, redisPort);
    }

    //RedisTemplate์„ ํ†ตํ•ด RedisConnection์—์„œ ๋„˜๊ฒจ์ค€ byte ๊ฐ’์„ ๊ฐ์ฒด ์ง๋ ฌํ™”ํ•ฉ๋‹ˆ๋‹ค.
    @Bean
    public RedisTemplate<?,?> redisTemplate(){
        RedisTemplate<String, RecentLog> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer(objectMapper()));
        return redisTemplate;
    }

}
  • ObjectMapper : redis์—์„œ ๊ฐ’์„ ์ €์žฅํ•˜๊ณ  ๊ฐ€์ ธ์˜ค๋Š” ๊ณผ์ •์—์„œ, LocalDateTime์ด๋‚˜ LocalDateTime ํ˜•์‹์€ ์—ญ์ง๋ ฌํ™”ํ•˜๋Š” ๊ณผ์ •์—์„œ ์—๋Ÿฌ๊ฐ€ ๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋‚ ์งœ ํƒ€์ž… ์ฒ˜๋ฆฌํ•˜๊ธฐspringboot์—์„œ๋Š” ObjectMapper ๊ฐ€ ๋นˆ์œผ๋กœ ์ฃผ์ž…๋˜๊ธฐ ๋•Œ๋ฌธ์— application.yml ํŒŒ์ผ์—์„œ๋„ ์„ค์ •์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • spring: jackson: serialization: WRITE\_DATES\_AS\_TIMESTAMPS: false
  • Object → Json(์ง๋ ฌํ™”) / Json → Object(์—ญ์ง๋ ฌํ™”) / ObejctMapper ์ด ์ด๋Ÿฐ ์—ญํ• ์„ ๋‹ด๋‹นํ•˜๊ณ  ์žˆ๊ณ , Jackson์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ObjectMapper์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Jackson์—์„œ LocalDateTime์„ ๋งคํ•‘ํ•˜๋ ค๋ฉด JavaTimeModule์„ ํ™œ์„ฑํ™”ํ•ด์•ผํ•˜๊ณ , WRITE_DATES_AS_TIMESTAMPS ๋ฅผ ์ ์šฉํ•˜์ง€ ์•Š๊ธฐ๋กœ ์„ค์ •ํ•ด์ฃผ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.
  • RedisConnectionFactory : application.yml ํŒŒ์ผ์—์„œ ์„ค์ •ํ•œ redis์™€ port ๋ฒˆํ˜ธ๋ฅผ ๊ฐ€์ ธ์™€ ์™ธ๋ถ€ redis์™€ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
  • RedisTemplate : RedisTemplate๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ RedisConnection์—์„œ ๋„˜๊ฒจ์ค€ ๋ฐ”์ดํŠธ ๊ฐ’์„ ์ง๋ ฌํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋•Œ, GenericJackson2JsonRedisSerializer์—์„œ ์•„๊นŒ ์„ค์ •ํ•ด๋‘์—ˆ๋˜ objectMapper() ์„ค์ •์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.




3๏ธโƒฃ redis ์—”ํ‹ฐํ‹ฐ ์„ค์ •

๐Ÿ“‚ domain/RecentLog

@RedisHash("userIdx")
@Getter @ToString @NoArgsConstructor @AllArgsConstructor @Builder
public class RecentLog {

    @Id
    private  Long userIdx;
    private  PostDto.ListResponse postDto;

}
  • RedisHash("value") : jpa์—์„œ RecentLog๊ฐ€ Redis ์—”ํ‹ฐํ‹ฐ์ž„์„ ๋ช…์‹œ, ์• ๋…ธํ…Œ์ด์…˜์— ๋“ค์–ด๊ฐˆ ๊ฐ’์€ @Id ์™€ ๊ฒฐํ•ฉํ•˜์—ฌ key๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. Long , String ๊ฐ’์ด ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ €๋Š” ๊ธ€์„ ์ž‘์„ฑํ•œ ์‚ฌ์šฉ์ž์˜ ์ธ๋ฑ์Šค ๊ฐ’๊ณผ ํ•ด๋‹น post๋ฅผ dto๋กœ ๋ณ€ํ™˜ํ•œ ๊ฐ’์„ ์ €์žฅํ•˜๋„๋ก ํ•ด๋‘์—ˆ์Šต๋‹ˆ๋‹ค.

์ฃผ์˜ํ•  ์ ์€ redis class์— Post์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ์—”ํ‹ฐํ‹ฐ ์ž์ฒด๋ฅผ ์ €์žฅํ•˜๋ฉด stackoverflowError๊ฐ€ ๋‚œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ์ด ์—๋Ÿฌ๋กœ ์‚ฝ์งˆ์„ ๋งŽ์ด ํ–ˆ๋Š”๋ฐ, ๊ฐ’์„ ์ €์žฅํ•  ๋•Œ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ dto๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์ €์žฅํ•˜๋„๋ก ํ•ฉ์‹œ๋‹ค.

๐Ÿ”Ž Redis CRUD ๋ฐฉ์‹

redis์— ๊ฐ’์„ ์ €์žฅํ•˜๊ณ  ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ์‹์€ 2๊ฐœ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ๊ฐ€ ์‚ฌ์šฉํ•œ redisTemplate์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ, CrudRepository๋ฅผ ์ƒ์†๋ฐ›์€ redisRepository๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ตœ๊ทผ ์ฝ์€ ๊ธ€ ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ์ €์žฅ๊ณผ ์กฐํšŒ๋งŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•„์š”ํ•˜๋ฏ€๋กœ, redisTemplate๋ฅผ ์‚ฌ์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.




4๏ธโƒฃ Service ๋งŒ๋“ค๊ธฐ

1) ์ตœ๊ทผ ์ฝ์€ ๊ธ€ ์ €์žฅ

๋จผ์ € postService์—์„œ '์ƒ์„ธ๋ณด๊ธฐ' ์กฐํšŒ๋ฅผ ํ•  ๋•Œ, ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•œ ์ƒํƒœ์ด๋ฉด ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ์„ค์ •ํ•ด๋‘์—ˆ์Šต๋‹ˆ๋‹ค.

private final PostMapper postMapper;
private final PostRepository postRepository;
private final RedisTemplate<String, PostDto.ListResponse> redisTemplate;


// ์ตœ๊ทผ ์ฝ์€ ๊ธ€ ์ €์žฅ
    @Transactional
    public void saveRecentReadPosts(Long userIdx, Long postIdx){
        ListOperations<String, PostDto.ListResponse> listOperations = redisTemplate.opsForList();
        Post post = postRepository.findById(postIdx)
                .orElseThrow(() -> new EntityNullException(ErrorInfo.POST_NULL));
        PostDto.ListResponse postDto = postMapper.postToListResponse(post, userIdx);
        String key = "userIdx::"+ userIdx;
        listOperations.leftPush(key, postDto);
        redisTemplate.expireAt(key, Date.from(ZonedDateTime.now().plusDays(7).toInstant())); // ์œ ํšจ๊ธฐ๊ฐ„ TTL ์ผ์ฃผ์ผ ์„ค์ •
    }
  • RedisTemplate ๋ฅผ Stirng(key ๊ฐ’), PostDto ๋กœ ๋ฐ›๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  • post ์ธ๋ฑ์Šค์— ํ•ด๋‹นํ•˜๋Š” Post ์—”ํ‹ฐํ‹ฐ๋ฅผ mapstruct๋ฅผ ํ†ตํ•ด dto๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. Entity → Dto ๋ณ€ํ™˜ ๋ฐฉ์‹์€ ํŽธํ•œ ๋ฐฉ์‹๋Œ€๋กœ ์‚ฌ์šฉํ•ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  • redisTemplate.opsForList() ๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด key๊ฐ’๊ณผ postDto ๋ฅผ leftPush ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • key๋Š” @RedisHash ์— ์ž…๋ ฅํ•œ value๊ฐ’๊ณผ ์‚ฌ์šฉ์ž ์ธ๋ฑ์Šค ๊ฐ’์„ ํ•ฉ์ณ์„œ string ํƒ€์ž…์˜ key๊ฐ’์œผ๋กœ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
  • ์ตœ๊ทผ ์ฝ์€ ๊ธ€์€ ์ตœ๋Œ€ ์ผ์ฃผ์ผ๊นŒ์ง€๋งŒ ์ €์žฅํ•  ๊ฒƒ์ด๋ฏ€๋กœ, ํ•ด๋‹น key์˜ redisTemplate์˜ ๋งŒ๋ฃŒ ๋‚ ์งœ๋ฅผ ์˜ค๋Š˜๋กœ๋ถ€ํ„ฐ ์ผ์ฃผ์ผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

 

2) ์ตœ๊ทผ ์ฝ์€ ๊ธ€ ์กฐํšŒ

์—ฌ๊ธฐ์„œ ๊ฐ€์žฅ ๋งŽ์€ ์‚ฝ์งˆ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ redisConfig์—์„œ objectMapper() ์„ค์ •์„ ํ•˜์ง€ ์•Š์œผ๋ฉด, Could not read JSON: Cannot construct instance of java.time.LocalDateTime (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator) ์—๋Ÿฌ๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค. Redis์— ์ €์žฅํ•  ๋•Œ๋Š” Serialize ํ•˜๊ณ , ์กฐํšŒํ•  ๋•Œ๋Š” ๋‹ค์‹œ Deserialize ํ•ด์„œ ๊ฐ–๊ณ ์˜จ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•˜๊ฒŒ dto์— @JsonDeserialize(using = LocalDateTimeDeserializer.class), @JsonSerialize(using = LocalDateTimeSerializer.class) ๋ฅผ ๋ถ™์—ฌ์„œ ์จ๋„ ๋˜์ง€๋งŒ, dto๋งˆ๋‹ค ๋ถ™์ด๋ฉด ๋ฒˆ๊ฑฐ๋กญ๊ธฐ ๋•Œ๋ฌธ์— ์•„๊นŒ์ฒ˜๋Ÿผ custom ์„ค์ •์„ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ํŽธํ•ฉ๋‹ˆ๋‹ค.

// ์ตœ๊ทผ ์ฝ์€ ๊ธ€ ์กฐํšŒ
    @Transactional
    public List<PostDto.ListResponse> findRecentPosts(Long userIdx) {
        ListOperations<String, PostDto.ListResponse> listOperations = redisTemplate.opsForList();
        String key = "userIdx::" + userIdx;
        long size = listOperations.size(key) == null ? 0 : listOperations.size(key); // NPE ์ฒดํฌํ•ด์•ผํ•จ.

        return listOperations.range(key, 0, size);

    }
  • key ๊ฐ’์— ํ•ด๋‹นํ•˜๋Š” ๋ชฉ๋ก ์‚ฌ์ด์ฆˆ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  • listOperations.range๋กœ 0๋ถ€ํ„ฐ ๋ชฉ๋ก ์‚ฌ์ด์ฆˆ๊นŒ์ง€์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.




5๏ธโƒฃ Controller

์ตœ๊ทผ ์ฝ์€ ๊ธ€ ์ €์žฅ์€ ์ƒ์„ธ๋ณด๊ธฐ์—์„œ service๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๋Š” ๊ฒƒ์ด๊ณ , ์กฐํšŒํ•  ๋•Œ controller๋งŒ ๋งŒ๋“ค์–ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

@ApiOperation(value = "mypage", notes = "[๋งˆ์ดํŽ˜์ด์ง€] ์ตœ๊ทผ ์ฝ์€ ๊ธ€ ์กฐํšŒ ")
    @GetMapping("/recent")
    public ResponseEntity<Object> findRecentPosts(HttpServletRequest request){
        Long userIdx = tokenService.getUserIdx(tokenService.getTokenFromRequest(request));
        return new ResponseEntity<>(ApiDefaultResponse.res(200, "",
                listService.findRecentPosts(userIdx)), HttpStatus.OK);
    }
  • accessToken์—์„œ userIdx ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์™€์„œ
  • ์•„๊นŒ ๋งŒ๋“ค์–ด ๋‘” service์— userIdx ๊ฐ’์„ ๋„˜๊ฒจ์ฃผ๋ฉด ๋จ.

 

 

 

๐Ÿ“š ์ฐธ๊ณ  ๋ธ”๋กœ๊ทธ

[spring] redis๋กœ cachingํ•ด์„œ dbms์˜ ๋ถ€ํ•˜ ์ค„์ด๊ธฐ - 1

[Java + Redis] Spring Data Redis๋กœ Redis์™€ ์—ฐ๋™ํ•˜๊ธฐ - RedisRepository ํŽธ

[Spring Boot] Redis (Lettuce)๋ฅผ ์ด์šฉํ•œ ๊ฐ„๋‹จํ•œ API ์ œ์ž‘

[ Redis ] Redis ํ™˜๊ฒฝ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌ์ถ•ํ•˜๊ธฐ

[spring] redis๋กœ cachingํ•ด์„œ dbms์˜ ๋ถ€ํ•˜ ์ค„์ด๊ธฐ - 2

RedisTemplate ๊ณผ Json Serializer ์„ค์ •