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 |