현재 Spring과 Thyemleaf를 활용하여 [QR코드 기반 간편 주문 서비스]를 개발하고 있다.
장바구니 페이지에서 주문페이지까지 넘어가는 로직에 대해서 구현하는 도중 한가지 이슈가 발생하였다.
아래는 간단한 장바구니페이지와 주문페이지의 UI이다.
현재 Order 엔티티에 저장되어야 할 필드는 다음과 같다.
한 마디로 장바구니 페이지에 보여지는 데이터와 사용자가 선택하는 데이터 + 주문페이지에서 사용자가 입력하고 선택하는 데이터가 Order 엔티티에 저장되어야 한다.
Spring MVC에서는 Model을 통해 페이지 이동간에 데이터를 주고 받을 수 있다. 사용자가 입력하거나 선택하는 값에 대해서는 쉽게 Model에 담을 수 있지만, 조회되는 데이터들에 대해서는 input hidden 태그를 통해 Model에 담아 넘겨줄 수 있다. 총 금액의 경우 단순 int 타입이라 손쉽게 넘길 수 있었지만 장바구니 목록의 경우 Dto가 List에 담겨져있기 때문에 input hidden 태그를 이용하여 모델에 저장하려 했으나 해결할 수 없었다. 따라서 다른 방법을 생각해야 했다.
첫번째로 생각한 로직은 다음과 같다.
충분히 다음과 같은 방법으로 주문하기 기능을 구현할 수 있었지만, 엔티티를 2번을 거처서 완성하는 부분과 엔티티를 만들기 위해서 데이터 베이스에 저장,조회,수정 순으로 3번 접근해야하는 것이 마음에 들지 않았다.
첫번째 해결방안은 안정성과 성능적인 측면에 문제가 있다고 생각했다..!
페이지 간의 데이터를 데이터베이스를 거쳐서 전달하는 것이 아닌 다른 방법에 대해서 고민하려는 중 Redis가 떠올랐다. 지금까지 한번도 Redis를 사용해본 경험은 없지만, Redis가 어떤 문제를 해결해주고 무엇을 위해 사용되는지는 조금 알고 있었기 때문에 충분히 해당 이슈를 해결할 수 있다고 생각했다.
따라서, Spring Data Redis를 사용하여 Redis를 임시 저장소 & 캐시역할을 하게끔 구현하여 다음과 같은 문제를 해결하였다.
로직이 단순해지고 안정성적으로도 성능적으도로 개선이 된 것 같다. 생각보다 Spring Data Redis를 프로젝트에 적용하는 것은 어렵지 않았다.
Docker를 통해 Redis 서버를 구동시키고, Spring Data Redis 의존성을 넣은 후
[application.properties]
spring.redis.host=127.0.0.1
spring.redis.port=6379
[RedisConfig.java]
@Configuration
@EnableRedisRepositories
public class RedisConfig {
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisHost, redisPort);
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
return redisTemplate;
}
}
[OrderDao.java]
@Repository
@RequiredArgsConstructor
public class OrderDao {
private final RedisTemplate<String, Object> redisTemplate;
public void addOrderDtoFromCart(OrderDtoFromCart dto, String userNickName) {
String key = keyGenerate(userNickName);
redisTemplate.opsForValue().set(key, dto);
redisTemplate.expire(key, 5, TimeUnit.MINUTES);
}
public OrderDtoFromCart getOrderDtoFromCart(String userNickName) {
String key = keyGenerate(userNickName);
return (OrderDtoFromCart) redisTemplate.opsForValue().get(key);
}
private String keyGenerate(String key) {
return key + " : orderDto";
}
}
코드를 추가하고, Order 컨트롤러에서 위에서 말한 로직을 적용하였다.
Spring Data Redis를 통해 쉽게 OrderDao를 통해 키-벨류로 Redis에 데이터를 저장하고, 조회할 수 있었다.
개발하고 있는 프로젝트에서는 생각보다 각 컨트롤러에서 동일한 값들에 대해서 데이터베이스 조회를 많이 한다. 이런 부분에 대해서 Redis를 활용한다면, 데이터베이스 서버의 부하 분산을 통해 서버의 안정성을 높일 수 있을 것이라고 생각하고, 성능적으로도 많이 개선될 것이라 생각한다. 따라서 핵심 기능들을 모두 구현한 이후 Redis를 활용하여 성능적으로 더 개선해야겠다는 생각이 들었다.