로그인 없는 장바구니 기능을 만들어보자. => Spring Security 없이 간단하게 실습
spring:
data:
redis:
host: localhost
port: 설정한 port 번호
username: 설정한 username
password: 설정한 password
package com.example.redis;
import lombok.*;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CartDto {
private Set<CartItemDto> items;
private Date expireAt;
public static CartDto fromHashPairs(
Map<String, Integer> entries,
Date expireAt
) {
return CartDto.builder()
.items(entries.entrySet().stream()
.map(entry -> CartItemDto.builder()
.item(entry.getKey())
.count(entry.getValue())
.build())
.collect(Collectors.toUnmodifiableSet()))
.expireAt(expireAt)
.build();
}
}
package com.example.redis;
import lombok.*;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CartItemDto {
private String item;
private Integer count;
}
package com.example.redis;
import jakarta.servlet.http.HttpSession;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@Slf4j
@RestController
@RequestMapping("cart")
public class CartController {
private final CartService cartService;
public CartController(CartService cartService) {
this.cartService = cartService;
}
@PostMapping
public CartDto modifyCart(
@RequestBody
CartItemDto itemDto,
HttpSession session
) {
cartService.modifyCart(session.getId(), itemDto);
return cartService.getCart(session.getId());
}
@GetMapping
public CartDto getCart(
HttpSession session
) {
log.info(session.getId());
return cartService.getCart(session.getId());
}
}
package com.example.redis;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Optional;
@Slf4j
@Service
public class CartService {
private final String keyString = "cart:%s";
private final RedisTemplate<String, String> cartTemplate;
private final HashOperations<String, String, Integer> hashOps;
public CartService(RedisTemplate<String, String> cartTemplate) {
this.cartTemplate = cartTemplate;
this.hashOps = this.cartTemplate.opsForHash();
}
public void modifyCart(String sessionId, CartItemDto dto) {
hashOps.increment(
keyString.formatted(sessionId),
dto.getItem(),
dto.getCount()
);
int count = Optional.ofNullable(hashOps.get(keyString.formatted(sessionId), dto.getItem()))
.orElse(0);
if (count <= 0) {
hashOps.delete(keyString.formatted(sessionId), dto.getItem());
}
}
public CartDto getCart(String sessionId) {
boolean exists = Optional.ofNullable(cartTemplate.hasKey(keyString.formatted(sessionId)))
.orElse(false);
if (!exists)
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
Date expireAt = Date.from(Instant.now().plus(30, ChronoUnit.SECONDS));
cartTemplate.expireAt(
keyString.formatted(sessionId),
expireAt
);
return CartDto.fromHashPairs(
hashOps.entries(keyString.formatted(sessionId)),
expireAt
);
}
}
package com.example.redis.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, String> cartTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
redisTemplate.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));
return redisTemplate;
}
}