version: "3" services: redis-docker: image: redis:latest command: redis-server --requirepass qwerqwer123 --port 6379 container_name: "docker-redis" labels: - "name=redis" - "mode=standalone" volumes: - /Users/wool/Database-docker/data/redis:/data ports: - 6379:6379
--requirepass
옵션을 빼고 작성$ docker-compose -f docker-compose.redis.yml up -d
Redis와 Spring을 연결하기 위해 설정 파일을 작성
reactRedisConnectionFactory
빈을 생성하여 레디스 연결 팩토리를 생성
@Bean public ReactiveRedisConnectionFactory reactiveRedisConnectionFactory() { return new LettuceConnectionFactory( Objects.requireNonNull(env.getProperty("spring.redis.host")), Integer.parseInt(Objects.requireNonNull((env.getProperty("spring.redis.port")))) ); }
혹은 @Value
어노테이션을 사용해서 아래와 같이 데이터를 깔끔하게 정리 할 수 있음
@Value("${spring.redis.host}") private String redisHost; @Value("${spring.redis.port}") private int redisPort; @Bean public ReactiveRedisConnectionFactory reactiveRedisConnectionFactory() { return new LettuceConnectionFactory(redisHost, redisPort); }
Redis의 데이터를 주고받아야 하기 때문에 JSON형식을 지원하는 Jackson 라이브러리를 사용한 Operation Bean을 세팅한다.
@Bean public ReactiveRedisOperations<String, Object> redisOperations(ReactiveRedisConnectionFactory reactiveRedisConnectionFactory) { Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class); RedisSerializationContext.RedisSerializationContextBuilder<String, Object> builder = RedisSerializationContext.newSerializationContext(new StringRedisSerializer()); RedisSerializationContext<String, Object> context = builder.value(serializer).hashValue(serializer) .hashKey(serializer).build(); return new ReactiveRedisTemplate<>(reactiveRedisConnectionFactory, context); }
Redis 데이터베이스와 연결 할 Repository를 작성한다
Interface를 사용해서 CRUD 기능을 명시하고, 구현체를 사용해 각 내부 로직을 구현
JSON 파싱을 위해서 ObjectMapperUtils 클래스 생성
Redis와 연결을 위해서 ReactiveRedisComponent 클래스 생성
public interface DessertRepository { Mono<Dessert> save(Dessert dessert); Mono<Dessert> get(String key); Flux<Dessert> getAll(); Mono<Long> delete(String id); }
public class RedisDessertRepository implements DessertRepository { private ReactiveRedisOperations<String, Object> redisOperations; public RedisDessertRepository(ReactiveRedisOperations<String, Object> redisOperations) { this.redisOperations = redisOperations; } @Override public Mono<Dessert> save(Dessert dessert) { return redisOperations.opsForValue().set(dessert.getId(), dessert); } @Override public Mono<Dessert> get(String key) { return redisOperations.opsForValue().get(key); } @Override public Flux<Dessert> getAll() { return redisOperations.keys("*") .flatMap(redisOperations::opsForValue::get) .cast(Dessert.class); } @Override public Mono<Long> delete(String id) { return redisOperations.delete(id); } }
Interface를 먼저 명시 해 준 후에 구현체로 구현
DessertService
public interface DessertService { Mono<Dessert> create(Dessert dessert); Flux<Dessert> getAll(); Mono<Dessert> getOne(String id); Mono<Long> deleteById(String id); }
@RequiredArgsConstructor @Service public class DessertServiceImpl implements DessertService { private final RedisDessertRepository redisDessertRepository; @Override public Mono<Dessert> create(Dessert dessert) { return redisDessertRepository.save(dessert); } @Override public Flux<Dessert> getAll() { return redisDessertRepository.getAll(); } @Override public Mono<Dessert> getOne(String id) { return redisDessertRepository.get(id); } @Override public Mono<Long> deleteById(String id) { return redisDessertRepository.delete(id); } }
DessertController를 생성하여 API Call을 Response 할 수 있도록 작성
@RestController @RequestMapping("/v1") @RequiredArgsConstructor public class DessertController { private final DessertServiceImpl dessertService; @PostMapping("/dessert") @ResponseStatus(HttpStatus.CREATED) public Mono<Dessert> addDessert(@RequestBody @Valid Dessert dessert) { return dessertService.create(dessert); } @GetMapping("/dessert") public Flux<Dessert> getAllDessert() { return dessertService.getAll(); } @GetMapping("/dessert/{id}") public Mono<Dessert> getDessert(@PathVariable String id) { return dessertService.getOne(id); } @DeleteMapping("/dessert/{id}") public Mono<Long> deleteDessert(@PathVariable String id) { return dessertService.deleteById(id); } }