RedisTemplate 과 Json Serializer 설정

2019. 7. 9. 16:28·SpringBoot

RedisTemplate 을 사용하여 json 으로 통신하기 위해 커스터마이징을 해 보도록 하겠습니다.

 

pom.xml 디펜던시 설정

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    <!--자동설정에서 connection pool 관련 설정이 들어가 있어 필요-->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-pool2</artifactId>
    </dependency>

    <!--ObjectMapper 사용-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
    </dependency>

    <dependency>
      <groupId>com.fasterxml.jackson.datatype</groupId>
      <artifactId>jackson-datatype-jsr310</artifactId>
    </dependency>

    <dependency>
      <groupId>com.fasterxml.jackson.datatype</groupId>
      <artifactId>jackson-datatype-jdk8</artifactId>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>

    <!--junit5-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
        <exclusion>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

 

application.properties 서버 설정

jedis 말고, lettuce connection factory 를 이용하기 위해 lettuce 로 기본 설정

spring.redis.database=0
# Connection URL. Overrides host, port, and password. User is ignored. Example: redis://user:password@example.com:6379
spring.redis.url=redis://192.168.99.100:6379
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.shutdown-timeout=100ms
spring.redis.ssl=false
spring.redis.timeout=3s

 

테스트를 위한 User Class 를 생성합니다.

@Data
public class User {
    private String userId;
    private String username;
    private Optional<String> option;
    private Instant createdAt;
}

 

Entity Class 를 Json으로 변환시에 java 날짜, Optional 타입 매핑을 위해 아래와 같이 ObjectMapper 를 @Bean 으로 등록합니다

User Class 매핑을 위한 RedisTemplate @Bean 설정을 추가 합니다.

@Configuration
public class RedisConfig {
  @Bean
  public ObjectMapper objectMapper() {
    var mapper = new ObjectMapper();
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    mapper.registerModules(new JavaTimeModule(), new Jdk8Module());
    return mapper;
  }
  
  @Bean
  public RedisTemplate<String, User> userRedisTemplate(RedisConnectionFactory connectionFactory, ObjectMapper objectMapper) {
    var serializer = new Jackson2JsonRedisSerializer<>(User.class);
    serializer.setObjectMapper(objectMapper);

    var tpl = new RedisTemplate<String, User>();
    tpl.setConnectionFactory(connectionFactory);
    tpl.setKeySerializer(new StringRedisSerializer());
    tpl.setValueSerializer(serializer);
    tpl.setHashKeySerializer(new StringRedisSerializer());
    tpl.setHashValueSerializer(serializer);
    return tpl;
  }
}

 

junit 을 이용하여 hash operation 테스트를 해 봅니다.

@Slf4j
@SpringBootTest
class RedisTemplateTest {
  @Autowired
  private RedisTemplate<String, User> userRedisTemplate;
  
  private User newUser(String id) {
    var user = new User();
    user.setUserId(id);
    user.setUsername("Marcia Rose");
    user.setOption(Optional.empty());
    user.setCreatedAt(Instant.now());
    return user;
  }
  
  @Test
  void set_get_test() {
    userRedisTemplate.opsForHash().put("user", "1", newUser("1"));

    User user = (User) userRedisTemplate.opsForHash().get("user", "1");
    log.info("{}", user);

    assertThat(user).isNotNull();
    assertThat(user.getUserId()).isEqualTo("1");
    assertThat(user.getUsername()).isEqualTo("Marcia Rose");
    assertThat(user.getOption()).isEmpty();
  }
}

 

redis-cli 를 이용하여 직접 저장된 데이터를 조회하여 봅니다.

192.168.99.100:6379> hgetall user
1) "1"
2) "{\"userId\":\"1\",\"username\":\"Marcia Rose\",\"option\":null,\"createdAt\":\"2019-07-09T06:50:48.778837500Z\"}"

 

위와 같이 사용할 경우 Entity Class 가 여러개인 경우 @Bean 설정이 계속 추가 되어야 합니다.

따라서 범용 Jackson Serializer 를 이용하여 redisTemplate @Bean 을 생성해 보겠습니다.

Serializer 를 Jackson2JsonRedisSerializer -> GenericJackson2JsonRedisSerializer 로 변경하였습니다.

@Configuration
public class RedisConfig {
  @Bean
  public ObjectMapper objectMapper() {
    var mapper = new ObjectMapper();
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    mapper.registerModules(new JavaTimeModule(), new Jdk8Module());
    return mapper;
  }
  
  @Bean
  public RedisTemplate<String, Object> userRedisTemplate(RedisConnectionFactory connectionFactory, ObjectMapper objectMapper) {
    var serializer = new GenericJackson2JsonRedisSerializer(objectMapper);
    
    var tpl = new RedisTemplate<String, Object>();
    tpl.setConnectionFactory(connectionFactory);
    tpl.setKeySerializer(new StringRedisSerializer());
    tpl.setValueSerializer(serializer);
    tpl.setHashKeySerializer(new StringRedisSerializer());
    tpl.setHashValueSerializer(serializer);
    return tpl;
  }
}

 

junit 을 이용하여 다시 테스트 해 보도록 하겠습니다.

@Slf4j
@SpringBootTest
class RedisTemplateTest {
  @Autowired
  private RedisTemplate<String, Object> redisTemplate;
  
  private User newUser(String id) {
    var user = new User();
    user.setUserId(id);
    user.setUsername("Marcia Rose");
    user.setOption(Optional.empty());
    user.setCreatedAt(Instant.now());
    return user;
  }
  
  @Test
  void set_get_by_generic_jackson_serializer() {
    redisTemplate.opsForHash().put("user", "1", newUser("1"));

    Object result = userRedisTemplate.opsForHash().get("user", "1");
    
    // User result = (User) userRedisTemplate.opsForHash().get("user", "1");
    // 위와 같이 형 변환을 통해 바로 이용할 수 없음
    // java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class 에러
    // objectMapper.convertValue 를 이용하여 변환
    
    User user = objectMapper.convertValue(result, User.class);
    log.info("{}", user);

    assertThat(user).isNotNull();
    assertThat(user.getUserId()).isEqualTo("1");
    assertThat(user.getUsername()).isEqualTo("Marcia Rose");
    assertThat(user.getOption()).isEmpty();
  }
}

 

'SpringBoot' 카테고리의 다른 글

Spring 6 의 HTTP Interface  (0) 2023.03.14
Retrying Feign Calls  (0) 2023.03.14
MongoDB _class 필드 제거하기  (0) 2019.07.09
restful json request response 패킷 로깅 필터  (1) 2019.07.04
404 NoHandlerFoundException 설정  (1) 2019.07.04
'SpringBoot' 카테고리의 다른 글
  • Spring 6 의 HTTP Interface
  • Retrying Feign Calls
  • MongoDB _class 필드 제거하기
  • restful json request response 패킷 로깅 필터
somoly
somoly
About me.
  • somoly
    somoly.tistory.com
    somoly
  • 전체
    오늘
    어제
    • 전체 (55)
      • SpringBoot (8)
      • Kotlin (5)
      • Javascript (4)
      • 백엔드 (6)
      • Linux (25)
      • Windows (1)
      • IT (2)
      • FF14 (1)
      • 애니 (1)
      • Figure (1)
      • 회사생활 (1)
  • 블로그 메뉴

    • HOME
    • TAGS
    • MEDIA
    • LOCATION
    • GUESTBOOK
    • ADMIN
    • WRITE
  • 링크

    • [FF14] 5.0 (71-80) 제작 레벨링 매크로
    • [FF14] 갈론드벨
    • [FF14] FFLogs
    • [FF14] Ariyala 장비 시뮬레이터
    • [FF14] 낚시 도우미
    • [FF14] 인테리어 정보
    • [FF14] 의상 코디 정보
  • 공지사항

  • 인기 글

  • 태그

    Spring
    VirtualBox
    우분투
    ubuntu
    accesskey
    설치
    bcmod
    종료
    exchage method
    dynamodb local
    tabulator
    javascript
    interactive table
    동영상
    83인치
    리눅스
    versioncomapre
    최후의 재림
    Kotlin
    77인치
    jvminline
    30일전
    부팅
    utf-8
    피규어
    string methods
    linux
    HTTP
    P2P
    springboot
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
somoly
RedisTemplate 과 Json Serializer 설정
상단으로

티스토리툴바