SpringBoot에서 Redis를 데이터베이스로 사용하기
- SpringBoot 와 Redis를 이용한 디저트가게 예제
- Redis를 사용하기위해서 디저트가게 예제를 만들어보자
스택
-
SpringBoot
- Lombok
- Spring Reactive Web
- Spring Data Reactive Redis
-
Validation
- Gradle
- Java 11 +
- Redis
레디스서버 띄우기
- 레디스 서버를 실행시켜야 함
- 로컬에서 임베드로 생성하거나, 로컬에 Docker로 생성하거나, 클라우드에 설치 된 redis 사용
-
docker-compose를 사용해서 설치 함
-
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
- redis에 비밀번호를 적용하지 않는다면
--requirepass
옵션을 빼고 작성 - redis서버 실행
$ docker-compose -f docker-compose.redis.yml up -d
Configuration 작성하기
- ReactiveRedisConfiguration.java
- 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); }
CRUD API 작성하기
- CRUD를 작성하기 위해 우선 모델 클래스가 필요
Domain 모델 작성
-
도메인 객체 생성하기
-
pk, 제품명, 카테고리, 설명, 가격, 출시일 을 가진 Dessert 도메인객체 생성
Database에 접근하는 Repository 작성
- 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); } }
Service 작성
- 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); } }
Contoller 생성
-
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); } }
댓글남기기