Skip to content

Instantly share code, notes, and snippets.

@marttp
Created April 27, 2023 03:39
Show Gist options
  • Save marttp/43e3051768bc29d02c8b72e5010d1de2 to your computer and use it in GitHub Desktop.
Save marttp/43e3051768bc29d02c8b72e5010d1de2 to your computer and use it in GitHub Desktop.
Group of Java Code to represent the Cache-Aside Pattern in Book Service
public record Book(Long id, String title, String isbn) {
}
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/books")
public record BookController(BookService bookService) {
@GetMapping("/{id}")
public Mono<Book> findById(@PathVariable Long id) {
return bookService.findById(id);
}
@GetMapping
public Flux<Book> findAll() {
return bookService.findAll();
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Mono<Book> save(@RequestBody Book payload) {
Book book = new Book(null, payload.title(), payload.isbn());
return bookService.save(book);
}
@DeleteMapping("/{id}")
public Mono<Void> deleteById(@PathVariable Long id) {
return bookService.deleteById(id).then();
}
}
import org.springframework.data.r2dbc.repository.R2dbcRepository;
public interface BookRepository extends R2dbcRepository<Book, Long> {
}
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Duration;
@Service
public class BookService {
private final BookRepository bookRepository;
private final ReactiveRedisTemplate<String, Book> reactiveRedisTemplate;
public BookService(BookRepository bookRepository, ReactiveRedisTemplate<String, Book> reactiveRedisTemplate) {
this.bookRepository = bookRepository;
this.reactiveRedisTemplate = reactiveRedisTemplate;
}
public Mono<Book> findById(Long id) {
String key = "book:" + id;
return reactiveRedisTemplate.opsForValue().get(key)
.switchIfEmpty(bookRepository.findById(id)
.flatMap(book -> reactiveRedisTemplate.opsForValue()
.set(key, book, Duration.ofMinutes(5))
.thenReturn(book))
);
}
public Flux<Book> findAll() {
return reactiveRedisTemplate.keys("book:*")
.flatMap(key -> reactiveRedisTemplate.opsForValue().get(key))
.switchIfEmpty(bookRepository.findAll()
.flatMap(book -> reactiveRedisTemplate.opsForValue()
.set("book:" + book.id(), book, Duration.ofMinutes(5)))
.thenMany(reactiveRedisTemplate.keys("book:*")
.flatMap(key -> reactiveRedisTemplate.opsForValue().get(key)))
);
}
public Mono<Book> save(Book book) {
return bookRepository.save(book)
.flatMap(savedBook -> reactiveRedisTemplate.opsForValue()
.set("book:" + savedBook.id(), savedBook, Duration.ofMinutes(5)).thenReturn(savedBook));
}
public Mono<Boolean> deleteById(Long id) {
return bookRepository.deleteById(id)
.then(reactiveRedisTemplate.opsForValue().delete("book:" + id));
}
}
import dev.tpcoder.reactivedockercompose.book.Book;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
@Configuration
public class RedisConfig {
@Bean
public ReactiveRedisTemplate<String, Book> reactiveRedisTemplate(ReactiveRedisConnectionFactory factory) {
Jackson2JsonRedisSerializer<Book> serializer = new Jackson2JsonRedisSerializer<>(Book.class);
RedisSerializationContext.RedisSerializationContextBuilder<String, Book> builder =
RedisSerializationContext.newSerializationContext(new Jackson2JsonRedisSerializer<>(String.class));
RedisSerializationContext<String, Book> context = builder.value(serializer).build();
return new ReactiveRedisTemplate<>(factory, context);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment