├── .gitignore ├── README.md ├── redis-performance ├── .gitignore ├── docker-compose.yaml ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── vinsguru │ │ │ └── redisperformance │ │ │ ├── RedisPerformanceApplication.java │ │ │ ├── controller │ │ │ ├── BusinessMetricsController.java │ │ │ ├── ProductControllerV1.java │ │ │ └── ProductControllerV2.java │ │ │ ├── entity │ │ │ └── Product.java │ │ │ ├── repository │ │ │ └── ProductRepository.java │ │ │ └── service │ │ │ ├── BusinessMetricsService.java │ │ │ ├── DataSetupService.java │ │ │ ├── ProductServiceV1.java │ │ │ ├── ProductServiceV2.java │ │ │ ├── ProductVisitService.java │ │ │ └── util │ │ │ ├── CacheTemplate.java │ │ │ ├── ProductCacheTemplate.java │ │ │ └── ProductLocalCacheTemplate.java │ └── resources │ │ ├── application.properties │ │ └── schema.sql │ └── test │ └── java │ └── com │ └── vinsguru │ └── redisperformance │ └── RedisPerformanceApplicationTests.java ├── redis-spring ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── vinsguru │ │ │ └── redisspring │ │ │ ├── RedisSpringApplication.java │ │ │ ├── chat │ │ │ ├── config │ │ │ │ └── ChatRoomSocketConfig.java │ │ │ └── service │ │ │ │ └── ChatRoomService.java │ │ │ ├── city │ │ │ ├── client │ │ │ │ └── CityClient.java │ │ │ ├── controller │ │ │ │ └── CityController.java │ │ │ ├── dto │ │ │ │ └── City.java │ │ │ └── service │ │ │ │ └── CityService.java │ │ │ ├── fib │ │ │ ├── config │ │ │ │ └── RedissonCacheConfig.java │ │ │ ├── controller │ │ │ │ └── FibController.java │ │ │ └── service │ │ │ │ └── FibService.java │ │ │ ├── geo │ │ │ ├── controller │ │ │ │ └── RestaurantController.java │ │ │ ├── dto │ │ │ │ ├── GeoLocation.java │ │ │ │ └── Restaurant.java │ │ │ ├── service │ │ │ │ ├── DataSetupService.java │ │ │ │ └── RestaurantLocatorService.java │ │ │ └── util │ │ │ │ └── RestaurantUtil.java │ │ │ └── weather │ │ │ ├── controller │ │ │ └── WeatherController.java │ │ │ └── service │ │ │ ├── ExternalServiceClient.java │ │ │ └── WeatherService.java │ └── resources │ │ ├── application.properties │ │ ├── restaurant.json │ │ └── static │ │ ├── geo.html │ │ └── index.html │ └── test │ └── java │ └── com │ └── vinsguru │ └── redisspring │ └── RedisSpringApplicationTests.java └── redisson-playground ├── pom.xml └── src └── test ├── java └── com │ └── vinsguru │ └── redisson │ └── test │ ├── BaseTest.java │ ├── Lec01KeyValueTest.java │ ├── Lec02KeyValueObjectTest.java │ ├── Lec03NumberTest.java │ ├── Lec04BucketAsMapTest.java │ ├── Lec05EventListenerTest.java │ ├── Lec06MapTest.java │ ├── Lec07MapCacheTest.java │ ├── Lec08LocalCachedMapTest.java │ ├── Lec09ListQueueStackTest.java │ ├── Lec10MessageQueueTest.java │ ├── Lec11HyperLogLogTest.java │ ├── Lec12PubSubTest.java │ ├── Lec13BatchTest.java │ ├── Lec14TransactionTest.java │ ├── Lec15SortedSetTest.java │ ├── Lec16PriorityQueueTest.java │ ├── Lec17GeoSpatialTest.java │ ├── assignment │ ├── Category.java │ ├── PriorityQueue.java │ └── UserOrder.java │ ├── config │ └── RedissonConfig.java │ ├── dto │ ├── GeoLocation.java │ ├── Restaurant.java │ └── Student.java │ └── util │ └── RestaurantUtil.java └── resources └── restaurant.json /.gitignore: -------------------------------------------------------------------------------- 1 | ### Java template 2 | # Compiled class file 3 | **/*.class 4 | 5 | # Log file 6 | **/*.log 7 | 8 | # BlueJ files 9 | **/*.ctxt 10 | 11 | # Mobile Tools for Java (J2ME) 12 | **/.mtj.tmp/ 13 | 14 | # Package Files # 15 | **/*.jar 16 | **/*.war 17 | **/*.nar 18 | **/*.ear 19 | **/*.zip 20 | **/*.tar.gz 21 | **/*.rar 22 | 23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 24 | **/hs_err_pid* 25 | 26 | ### Maven template 27 | **/target/ 28 | **/pom.xml.tag 29 | **/pom.xml.releaseBackup 30 | **/pom.xml.versionsBackup 31 | **/pom.xml.next 32 | **/release.properties 33 | **/dependency-reduced-pom.xml 34 | **/buildNumber.properties 35 | **/.mvn/timing.properties 36 | **/.mvn/wrapper/maven-wrapper.jar 37 | 38 | **/*.iml 39 | 40 | **/.idea/ 41 | 42 | 43 | **/HELP.md 44 | **/.mvn/ 45 | **/mvnw 46 | **/mvnw.cmd 47 | **/node_modules/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # redis-webflux 2 | 3 | This repository contains the code samples for my Udemy Course on Redis With Spring WebFlux 4 | -------------------------------------------------------------------------------- /redis-performance/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /redis-performance/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | postgres: 4 | image: postgres 5 | container_name: postgres 6 | environment: 7 | - POSTGRES_USER=postgres 8 | - POSTGRES_PASSWORD=postgres 9 | ports: 10 | - "5432:5432" 11 | pgadmin: 12 | image: dpage/pgadmin4 13 | container_name: pgadmin 14 | environment: 15 | - PGADMIN_DEFAULT_EMAIL=admin@admin.com 16 | - PGADMIN_DEFAULT_PASSWORD=admin 17 | ports: 18 | - "9000:80" 19 | redis: 20 | image: redis 21 | ports: 22 | - "6379:6379" -------------------------------------------------------------------------------- /redis-performance/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.5.0 9 | 10 | 11 | com.vinsguru 12 | redis-performance 13 | 0.0.1-SNAPSHOT 14 | redis-performance 15 | Demo project for Spring Boot 16 | 17 | 21 18 | 3.47.0 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-data-r2dbc 24 | 25 | 26 | org.redisson 27 | redisson-spring-boot-starter 28 | ${redisson.spring.version} 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-web 33 | 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-webflux 39 | 40 | 41 | 42 | org.postgresql 43 | postgresql 44 | runtime 45 | 46 | 47 | org.postgresql 48 | r2dbc-postgresql 49 | runtime 50 | 51 | 52 | org.projectlombok 53 | lombok 54 | true 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-starter-test 59 | test 60 | 61 | 62 | io.projectreactor 63 | reactor-test 64 | test 65 | 66 | 67 | 68 | 69 | 70 | 71 | org.springframework.boot 72 | spring-boot-maven-plugin 73 | 74 | 75 | 76 | org.projectlombok 77 | lombok 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /redis-performance/src/main/java/com/vinsguru/redisperformance/RedisPerformanceApplication.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisperformance; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RedisPerformanceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RedisPerformanceApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /redis-performance/src/main/java/com/vinsguru/redisperformance/controller/BusinessMetricsController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisperformance.controller; 2 | 3 | import com.vinsguru.redisperformance.service.BusinessMetricsService; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.http.MediaType; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import reactor.core.publisher.Flux; 10 | 11 | import java.time.Duration; 12 | import java.util.Map; 13 | 14 | @RestController 15 | @RequestMapping("product/metrics") 16 | public class BusinessMetricsController { 17 | 18 | @Autowired 19 | private BusinessMetricsService metricsService; 20 | 21 | @GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE) 22 | public Flux> getMetrics(){ 23 | return this.metricsService.top3Products() 24 | .repeatWhen(l -> Flux.interval(Duration.ofSeconds(3))); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /redis-performance/src/main/java/com/vinsguru/redisperformance/controller/ProductControllerV1.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisperformance.controller; 2 | 3 | import com.vinsguru.redisperformance.entity.Product; 4 | import com.vinsguru.redisperformance.service.ProductServiceV1; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.springframework.web.bind.annotation.PutMapping; 9 | import org.springframework.web.bind.annotation.RequestBody; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | import reactor.core.publisher.Mono; 13 | 14 | @RestController 15 | @RequestMapping("product/v1") 16 | public class ProductControllerV1 { 17 | 18 | @Autowired 19 | private ProductServiceV1 service; 20 | 21 | @GetMapping("{id}") 22 | public Mono getProduct(@PathVariable int id){ 23 | return this.service.getProduct(id); 24 | } 25 | 26 | @PutMapping("{id}") 27 | public Mono updateProduct(@PathVariable int id, @RequestBody Mono productMono){ 28 | return this.service.updateProduct(id, productMono); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /redis-performance/src/main/java/com/vinsguru/redisperformance/controller/ProductControllerV2.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisperformance.controller; 2 | 3 | import com.vinsguru.redisperformance.entity.Product; 4 | import com.vinsguru.redisperformance.service.ProductServiceV2; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.DeleteMapping; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.PutMapping; 10 | import org.springframework.web.bind.annotation.RequestBody; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | import reactor.core.publisher.Mono; 14 | 15 | @RestController 16 | @RequestMapping("product/v2") 17 | public class ProductControllerV2 { 18 | 19 | @Autowired 20 | private ProductServiceV2 service; 21 | 22 | @GetMapping("{id}") 23 | public Mono getProduct(@PathVariable int id){ 24 | return this.service.getProduct(id); 25 | } 26 | 27 | @PutMapping("{id}") 28 | public Mono updateProduct(@PathVariable int id, @RequestBody Mono productMono){ 29 | return this.service.updateProduct(id, productMono); 30 | } 31 | 32 | @DeleteMapping("{id}") 33 | public Mono deleteProduct(@PathVariable int id){ 34 | return this.service.deleteProduct(id); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /redis-performance/src/main/java/com/vinsguru/redisperformance/entity/Product.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisperformance.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | import org.springframework.data.annotation.Id; 8 | import org.springframework.data.relational.core.mapping.Table; 9 | 10 | @Data 11 | @Table 12 | @ToString 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class Product { 16 | 17 | @Id 18 | private Integer id; 19 | private String description; 20 | private double price; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /redis-performance/src/main/java/com/vinsguru/redisperformance/repository/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisperformance.repository; 2 | 3 | import com.vinsguru.redisperformance.entity.Product; 4 | import org.springframework.data.repository.reactive.ReactiveCrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface ProductRepository extends ReactiveCrudRepository { 9 | } 10 | -------------------------------------------------------------------------------- /redis-performance/src/main/java/com/vinsguru/redisperformance/service/BusinessMetricsService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisperformance.service; 2 | 3 | import org.redisson.api.RScoredSortedSetReactive; 4 | import org.redisson.api.RedissonReactiveClient; 5 | import org.redisson.client.codec.IntegerCodec; 6 | import org.redisson.client.protocol.ScoredEntry; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | import reactor.core.publisher.Mono; 10 | 11 | import java.time.LocalDate; 12 | import java.time.format.DateTimeFormatter; 13 | import java.util.LinkedHashMap; 14 | import java.util.Map; 15 | import java.util.stream.Collectors; 16 | 17 | @Service 18 | public class BusinessMetricsService { 19 | 20 | @Autowired 21 | private RedissonReactiveClient client; 22 | 23 | public Mono> top3Products(){ 24 | String format = DateTimeFormatter.ofPattern("YYYYMMdd").format(LocalDate.now()); 25 | RScoredSortedSetReactive set = client.getScoredSortedSet("product:visit:" + format, IntegerCodec.INSTANCE); 26 | return set.entryRangeReversed(0, 2) // list of scored entry 27 | .map(listSe -> listSe.stream().collect( 28 | Collectors.toMap( 29 | ScoredEntry::getValue, 30 | ScoredEntry::getScore, 31 | (a, b) -> a, 32 | LinkedHashMap::new 33 | ) 34 | )); 35 | } 36 | 37 | /* 38 | { 39 | 189: 423 40 | 165: 324 41 | 213: 108 42 | } 43 | */ 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /redis-performance/src/main/java/com/vinsguru/redisperformance/service/DataSetupService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisperformance.service; 2 | 3 | import com.vinsguru.redisperformance.entity.Product; 4 | import com.vinsguru.redisperformance.repository.ProductRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.boot.CommandLineRunner; 8 | import org.springframework.core.io.Resource; 9 | import org.springframework.data.r2dbc.core.R2dbcEntityTemplate; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.util.StreamUtils; 12 | import reactor.core.publisher.Flux; 13 | import reactor.core.publisher.Mono; 14 | 15 | import java.nio.charset.StandardCharsets; 16 | import java.util.concurrent.ThreadLocalRandom; 17 | 18 | @Service 19 | public class DataSetupService implements CommandLineRunner { 20 | 21 | @Autowired 22 | private ProductRepository repository; 23 | 24 | @Autowired 25 | private R2dbcEntityTemplate entityTemplate; 26 | 27 | @Value("classpath:schema.sql") 28 | private Resource resource; 29 | 30 | @Override 31 | public void run(String... args) throws Exception { 32 | String query = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8); 33 | System.out.println(query); 34 | 35 | Mono insert = Flux.range(1, 1000) 36 | .map(i -> new Product(null, "product" + i, ThreadLocalRandom.current().nextInt(1, 100))) 37 | .collectList() 38 | .flatMapMany(l -> this.repository.saveAll(l)) 39 | .then(); 40 | 41 | this.entityTemplate.getDatabaseClient() 42 | .sql(query) 43 | .then() 44 | .then(insert) 45 | .doFinally(s -> System.out.println("data setup done " + s)) 46 | .subscribe(); 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /redis-performance/src/main/java/com/vinsguru/redisperformance/service/ProductServiceV1.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisperformance.service; 2 | 3 | import com.vinsguru.redisperformance.entity.Product; 4 | import com.vinsguru.redisperformance.repository.ProductRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | import reactor.core.publisher.Mono; 8 | 9 | @Service 10 | public class ProductServiceV1 { 11 | 12 | @Autowired 13 | private ProductRepository repository; 14 | 15 | public Mono getProduct(int id){ 16 | return this.repository.findById(id); 17 | } 18 | 19 | public Mono updateProduct(int id, Mono productMono){ 20 | return this.repository.findById(id) 21 | .flatMap(p -> productMono.doOnNext(pr -> pr.setId(id))) 22 | .flatMap(this.repository::save); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /redis-performance/src/main/java/com/vinsguru/redisperformance/service/ProductServiceV2.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisperformance.service; 2 | 3 | import com.vinsguru.redisperformance.entity.Product; 4 | import com.vinsguru.redisperformance.service.util.CacheTemplate; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | import reactor.core.publisher.Mono; 8 | 9 | @Service 10 | public class ProductServiceV2 { 11 | 12 | @Autowired 13 | private CacheTemplate cacheTemplate; 14 | 15 | @Autowired 16 | private ProductVisitService visitService; 17 | 18 | // GET 19 | public Mono getProduct(int id){ 20 | return this.cacheTemplate.get(id) 21 | .doFirst(() -> this.visitService.addVisit(id)); 22 | } 23 | 24 | // PUT 25 | public Mono updateProduct(int id, Mono productMono){ 26 | return productMono 27 | .flatMap(p -> this.cacheTemplate.update(id, p)); 28 | } 29 | 30 | // DELETE 31 | public Mono deleteProduct(int id){ 32 | return this.cacheTemplate.delete(id); 33 | } 34 | 35 | // INSERT 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /redis-performance/src/main/java/com/vinsguru/redisperformance/service/ProductVisitService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisperformance.service; 2 | 3 | import org.redisson.api.BatchOptions; 4 | import org.redisson.api.RBatchReactive; 5 | import org.redisson.api.RScoredSortedSetReactive; 6 | import org.redisson.api.RedissonReactiveClient; 7 | import org.redisson.client.codec.IntegerCodec; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Service; 10 | import reactor.core.publisher.Flux; 11 | import reactor.core.publisher.Mono; 12 | import reactor.core.publisher.Sinks; 13 | 14 | import jakarta.annotation.PostConstruct; 15 | import java.time.Duration; 16 | import java.time.LocalDate; 17 | import java.time.format.DateTimeFormatter; 18 | import java.util.Map; 19 | import java.util.function.Function; 20 | import java.util.stream.Collectors; 21 | 22 | @Service 23 | public class ProductVisitService { 24 | 25 | @Autowired 26 | private RedissonReactiveClient client; 27 | private Sinks.Many sink; 28 | 29 | public ProductVisitService() { 30 | this.sink = Sinks.many().unicast().onBackpressureBuffer(); 31 | } 32 | 33 | @PostConstruct 34 | private void init(){ 35 | this.sink 36 | .asFlux() 37 | .buffer(Duration.ofSeconds(3)) // list (1,2,1,1,3,5,1...) 38 | .map(l -> l.stream().collect( // 1:4, 5:1, 39 | Collectors.groupingBy( 40 | Function.identity(), 41 | Collectors.counting() 42 | ) 43 | )) 44 | .flatMap(this::updateBatch) 45 | .subscribe(); 46 | } 47 | 48 | public void addVisit(int productId){ 49 | this.sink.tryEmitNext(productId); 50 | } 51 | 52 | private Mono updateBatch(Map map){ 53 | RBatchReactive batch = this.client.createBatch(BatchOptions.defaults()); 54 | String format = DateTimeFormatter.ofPattern("YYYYMMdd").format(LocalDate.now()); 55 | RScoredSortedSetReactive set = batch.getScoredSortedSet("product:visit:" + format, IntegerCodec.INSTANCE); 56 | return Flux.fromIterable(map.entrySet()) 57 | .map(e -> set.addScore(e.getKey(), e.getValue())) 58 | .then(batch.execute()) 59 | .then(); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /redis-performance/src/main/java/com/vinsguru/redisperformance/service/util/CacheTemplate.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisperformance.service.util; 2 | 3 | import reactor.core.publisher.Mono; 4 | 5 | public abstract class CacheTemplate { 6 | 7 | public Mono get(KEY key){ 8 | return getFromCache(key) 9 | .switchIfEmpty( 10 | getFromSource(key) 11 | .flatMap(e -> updateCache(key, e)) 12 | ); 13 | } 14 | 15 | public Mono update(KEY key, ENTITY entity){ 16 | return updateSource(key, entity) 17 | .flatMap(e -> deleteFromCache(key).thenReturn(e)); 18 | } 19 | 20 | public Mono delete(KEY key){ 21 | return deleteFromSource(key) 22 | .then(deleteFromCache(key)); 23 | } 24 | 25 | abstract protected Mono getFromSource(KEY key); 26 | abstract protected Mono getFromCache(KEY key); 27 | abstract protected Mono updateSource(KEY key, ENTITY entity); 28 | abstract protected Mono updateCache(KEY key, ENTITY entity); 29 | abstract protected Mono deleteFromSource(KEY key); 30 | abstract protected Mono deleteFromCache(KEY key); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /redis-performance/src/main/java/com/vinsguru/redisperformance/service/util/ProductCacheTemplate.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisperformance.service.util; 2 | 3 | import com.vinsguru.redisperformance.entity.Product; 4 | import com.vinsguru.redisperformance.repository.ProductRepository; 5 | import org.redisson.api.RMapReactive; 6 | import org.redisson.api.RedissonReactiveClient; 7 | import org.redisson.codec.TypedJsonJacksonCodec; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import reactor.core.publisher.Mono; 10 | 11 | //@Service 12 | public class ProductCacheTemplate extends CacheTemplate { 13 | 14 | @Autowired 15 | private ProductRepository repository; 16 | private RMapReactive map; 17 | 18 | public ProductCacheTemplate(RedissonReactiveClient client) { 19 | this.map = client.getMap("product", new TypedJsonJacksonCodec(Integer.class, Product.class)); 20 | } 21 | 22 | @Override 23 | protected Mono getFromSource(Integer id) { 24 | return this.repository.findById(id); 25 | } 26 | 27 | @Override 28 | protected Mono getFromCache(Integer id) { 29 | return this.map.get(id); 30 | } 31 | 32 | @Override 33 | protected Mono updateSource(Integer id, Product product) { 34 | return this.repository.findById(id) 35 | .doOnNext(p -> product.setId(id)) 36 | .flatMap(p -> this.repository.save(product)); 37 | } 38 | 39 | @Override 40 | protected Mono updateCache(Integer id, Product product) { 41 | return this.map.fastPut(id, product).thenReturn(product); 42 | } 43 | 44 | @Override 45 | protected Mono deleteFromSource(Integer id) { 46 | return this.repository.deleteById(id); 47 | } 48 | 49 | @Override 50 | protected Mono deleteFromCache(Integer id) { 51 | return this.map.fastRemove(id).then(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /redis-performance/src/main/java/com/vinsguru/redisperformance/service/util/ProductLocalCacheTemplate.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisperformance.service.util; 2 | 3 | import com.vinsguru.redisperformance.entity.Product; 4 | import com.vinsguru.redisperformance.repository.ProductRepository; 5 | import org.redisson.api.LocalCachedMapOptions; 6 | import org.redisson.api.RLocalCachedMap; 7 | import org.redisson.api.RedissonClient; 8 | import org.redisson.codec.TypedJsonJacksonCodec; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Service; 11 | import reactor.core.publisher.Mono; 12 | 13 | @Service 14 | public class ProductLocalCacheTemplate extends CacheTemplate { 15 | 16 | @Autowired 17 | private ProductRepository repository; 18 | private RLocalCachedMap map; 19 | 20 | public ProductLocalCacheTemplate(RedissonClient client) { 21 | LocalCachedMapOptions mapOptions = LocalCachedMapOptions.defaults() 22 | .syncStrategy(LocalCachedMapOptions.SyncStrategy.UPDATE) 23 | .reconnectionStrategy(LocalCachedMapOptions.ReconnectionStrategy.CLEAR); 24 | this.map = client.getLocalCachedMap("product", new TypedJsonJacksonCodec(Integer.class, Product.class), mapOptions); 25 | } 26 | 27 | @Override 28 | protected Mono getFromSource(Integer id) { 29 | return this.repository.findById(id); 30 | } 31 | 32 | @Override 33 | protected Mono getFromCache(Integer id) { 34 | return Mono.justOrEmpty(this.map.get(id)); 35 | } 36 | 37 | @Override 38 | protected Mono updateSource(Integer id, Product product) { 39 | return this.repository.findById(id) 40 | .doOnNext(p -> product.setId(id)) 41 | .flatMap(p -> this.repository.save(product)); 42 | } 43 | 44 | @Override 45 | protected Mono updateCache(Integer id, Product product) { 46 | return Mono.create(sink -> 47 | this.map.fastPutAsync(id, product) 48 | .thenAccept(b -> sink.success(product)) 49 | .exceptionally(ex -> { 50 | sink.error(ex); 51 | return null; 52 | }) 53 | ); 54 | } 55 | 56 | @Override 57 | protected Mono deleteFromSource(Integer id) { 58 | return this.repository.deleteById(id); 59 | } 60 | 61 | @Override 62 | protected Mono deleteFromCache(Integer id) { 63 | return Mono.create(sink -> 64 | this.map.fastRemoveAsync(id) 65 | .thenAccept(b -> sink.success()) 66 | .exceptionally(ex -> { 67 | sink.error(ex); 68 | return null; 69 | }) 70 | ); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /redis-performance/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.r2dbc.url=r2dbc:postgresql://localhost:5432/postgres 2 | spring.r2dbc.username=postgres 3 | spring.r2dbc.password=postgres -------------------------------------------------------------------------------- /redis-performance/src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS product; 2 | CREATE TABLE product( 3 | id serial PRIMARY KEY, 4 | description VARCHAR (500), 5 | price numeric (10,2) NOT NULL 6 | ); -------------------------------------------------------------------------------- /redis-performance/src/test/java/com/vinsguru/redisperformance/RedisPerformanceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisperformance; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class RedisPerformanceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /redis-spring/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /redis-spring/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.5.0 9 | 10 | 11 | com.vinsguru 12 | redis-spring 13 | 0.0.1-SNAPSHOT 14 | redis-spring 15 | Demo project for Spring Boot 16 | 17 | 21 18 | 3.47.0 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-webflux 24 | 25 | 26 | org.redisson 27 | redisson-spring-boot-starter 28 | ${redisson.spring.version} 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-web 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-aop 37 | 38 | 39 | 40 | 41 | org.projectlombok 42 | lombok 43 | true 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-test 48 | test 49 | 50 | 51 | io.projectreactor 52 | reactor-test 53 | test 54 | 55 | 56 | 57 | 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-maven-plugin 62 | 63 | 64 | 65 | org.projectlombok 66 | lombok 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/RedisSpringApplication.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cache.annotation.EnableCaching; 6 | import org.springframework.scheduling.annotation.EnableScheduling; 7 | 8 | @EnableCaching 9 | @EnableScheduling 10 | @SpringBootApplication 11 | public class RedisSpringApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(RedisSpringApplication.class, args); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/chat/config/ChatRoomSocketConfig.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.chat.config; 2 | 3 | import com.vinsguru.redisspring.chat.service.ChatRoomService; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.web.reactive.HandlerMapping; 8 | import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping; 9 | import org.springframework.web.reactive.socket.WebSocketHandler; 10 | 11 | import java.util.Map; 12 | 13 | @Configuration 14 | public class ChatRoomSocketConfig { 15 | 16 | @Autowired 17 | private ChatRoomService chatRoomService; 18 | 19 | @Bean 20 | public HandlerMapping handlerMapping(){ 21 | Map map = Map.of( 22 | "/chat", chatRoomService 23 | ); 24 | return new SimpleUrlHandlerMapping(map, -1); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/chat/service/ChatRoomService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.chat.service; 2 | 3 | import org.redisson.api.RListReactive; 4 | import org.redisson.api.RTopicReactive; 5 | import org.redisson.api.RedissonReactiveClient; 6 | import org.redisson.client.codec.StringCodec; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.web.reactive.socket.WebSocketHandler; 10 | import org.springframework.web.reactive.socket.WebSocketMessage; 11 | import org.springframework.web.reactive.socket.WebSocketSession; 12 | import org.springframework.web.util.UriComponentsBuilder; 13 | import reactor.core.publisher.Flux; 14 | import reactor.core.publisher.Mono; 15 | 16 | import java.net.URI; 17 | 18 | @Service 19 | public class ChatRoomService implements WebSocketHandler { 20 | 21 | @Autowired 22 | private RedissonReactiveClient client; 23 | 24 | @Override 25 | public Mono handle(WebSocketSession webSocketSession) { 26 | String room = getChatRoomName(webSocketSession); 27 | RTopicReactive topic = this.client.getTopic(room, StringCodec.INSTANCE); 28 | RListReactive list = this.client.getList("history:" + room, StringCodec.INSTANCE); 29 | // subscribe 30 | webSocketSession.receive() 31 | .map(WebSocketMessage::getPayloadAsText) 32 | .flatMap(msg -> list.add(msg).then(topic.publish(msg))) 33 | .doOnError(System.out::println) 34 | .doFinally(s -> System.out.println("Subscriber finally " + s)) 35 | .subscribe(); 36 | 37 | // publisher 38 | Flux flux = topic.getMessages(String.class) 39 | .startWith(list.iterator()) 40 | .map(webSocketSession::textMessage) 41 | .doOnError(System.out::println) 42 | .doFinally(s -> System.out.println("publisher finally " + s)); 43 | 44 | return webSocketSession.send(flux); 45 | } 46 | 47 | private String getChatRoomName(WebSocketSession socketSession){ 48 | URI uri = socketSession.getHandshakeInfo().getUri(); 49 | return UriComponentsBuilder.fromUri(uri) 50 | .build() 51 | .getQueryParams() 52 | .toSingleValueMap() 53 | .getOrDefault("room", "default"); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/city/client/CityClient.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.city.client; 2 | 3 | import com.vinsguru.redisspring.city.dto.City; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.stereotype.Service; 6 | import org.springframework.web.reactive.function.client.WebClient; 7 | import reactor.core.publisher.Flux; 8 | import reactor.core.publisher.Mono; 9 | 10 | @Service 11 | public class CityClient { 12 | 13 | private final WebClient webClient; 14 | 15 | public CityClient(@Value("${city.service.url}") String url) { 16 | this.webClient = WebClient.builder() 17 | .baseUrl(url) 18 | .build(); 19 | } 20 | 21 | public Mono getCity(final String zipCode){ 22 | return this.webClient 23 | .get() 24 | .uri("{zipcode}", zipCode) 25 | .retrieve() 26 | .bodyToMono(City.class); 27 | } 28 | 29 | public Flux getAll(){ 30 | return this.webClient 31 | .get() 32 | .retrieve() 33 | .bodyToFlux(City.class); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/city/controller/CityController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.city.controller; 2 | 3 | import com.vinsguru.redisspring.city.dto.City; 4 | import com.vinsguru.redisspring.city.service.CityService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | import reactor.core.publisher.Mono; 11 | 12 | @RestController 13 | @RequestMapping("city") 14 | public class CityController { 15 | 16 | @Autowired 17 | private CityService cityService; 18 | 19 | @GetMapping("{zipCode}") 20 | public Mono getCity(@PathVariable String zipCode){ 21 | return this.cityService.getCity(zipCode); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/city/dto/City.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.city.dto; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | 6 | @Data 7 | @ToString 8 | public class City { 9 | 10 | private String zip; 11 | private String city; 12 | private String stateName; 13 | private int temperature; 14 | 15 | } 16 | 17 | /* 18 | 19 | { 20 | "zip":"10001", 21 | "lat":40.75065, 22 | "lng":-73.99718, 23 | "city":"New York", 24 | "stateId":"NY", 25 | "stateName":"New York", 26 | "population":24117, 27 | "density":15153.7, 28 | "temperature":74 29 | } 30 | 31 | */ -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/city/service/CityService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.city.service; 2 | 3 | import com.vinsguru.redisspring.city.client.CityClient; 4 | import com.vinsguru.redisspring.city.dto.City; 5 | import org.redisson.api.RMapReactive; 6 | import org.redisson.api.RedissonReactiveClient; 7 | import org.redisson.codec.TypedJsonJacksonCodec; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Service; 10 | import reactor.core.publisher.Mono; 11 | 12 | import java.util.function.Function; 13 | import java.util.stream.Collectors; 14 | 15 | @Service 16 | public class CityService { 17 | 18 | @Autowired 19 | private CityClient cityClient; 20 | 21 | private RMapReactive cityMap; 22 | 23 | public CityService(RedissonReactiveClient client) { 24 | this.cityMap = client.getMap("city", new TypedJsonJacksonCodec(String.class, City.class)); 25 | } 26 | 27 | public Mono getCity(final String zipCode){ 28 | return this.cityMap.get(zipCode) 29 | .onErrorResume(ex -> this.cityClient.getCity(zipCode)); 30 | } 31 | 32 | //@Scheduled(fixedRate = 10_000) 33 | public void updateCity(){ 34 | this.cityClient.getAll() 35 | .collectList() 36 | .map(list -> list.stream().collect(Collectors.toMap(City::getZip, Function.identity()))) 37 | .flatMap(this.cityMap::putAll) 38 | .subscribe(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/fib/config/RedissonCacheConfig.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.fib.config; 2 | 3 | import org.redisson.api.RedissonClient; 4 | import org.redisson.spring.cache.RedissonSpringCacheManager; 5 | import org.springframework.cache.CacheManager; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | public class RedissonCacheConfig { 11 | 12 | @Bean 13 | public CacheManager cacheManager(RedissonClient redissonClient){ 14 | return new RedissonSpringCacheManager(redissonClient); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/fib/controller/FibController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.fib.controller; 2 | 3 | import com.vinsguru.redisspring.fib.service.FibService; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.PathVariable; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import reactor.core.publisher.Mono; 10 | 11 | @RestController 12 | @RequestMapping("fib") 13 | public class FibController { 14 | 15 | @Autowired 16 | private FibService service; 17 | 18 | @GetMapping("{index}") 19 | public Mono getFib(@PathVariable int index){ 20 | return Mono.fromSupplier(() -> this.service.getFib(index)); 21 | } 22 | 23 | @GetMapping("{index}/clear") 24 | public Mono clearCache(@PathVariable int index){ 25 | return Mono.fromRunnable(() -> this.service.clearCache(index)); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/fib/service/FibService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.fib.service; 2 | 3 | import org.springframework.cache.annotation.CacheEvict; 4 | import org.springframework.cache.annotation.Cacheable; 5 | import org.springframework.stereotype.Service; 6 | 7 | @Service 8 | public class FibService { 9 | 10 | // have a strategy for cache evict 11 | @Cacheable(value = "math:fib", key = "#index") 12 | public int getFib(int index){ 13 | System.out.println("calculating fib for " + index); 14 | return this.fib(index); 15 | } 16 | 17 | // PUT / POST / PATCH / DELETE 18 | @CacheEvict(value = "math:fib", key = "#index") 19 | public void clearCache(int index){ 20 | System.out.println("clearing hash key"); 21 | } 22 | 23 | // @Scheduled(fixedRate = 10_000) 24 | @CacheEvict(value = "math:fib", allEntries = true) 25 | public void clearCache(){ 26 | System.out.println("clearing all fib keys"); 27 | } 28 | 29 | //intentional 2^N 30 | private int fib(int index){ 31 | if(index < 2) 32 | return index; 33 | return fib(index - 1) + fib(index - 2); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/geo/controller/RestaurantController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.geo.controller; 2 | 3 | import com.vinsguru.redisspring.geo.dto.Restaurant; 4 | import com.vinsguru.redisspring.geo.service.RestaurantLocatorService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | import reactor.core.publisher.Flux; 11 | 12 | @RestController 13 | @RequestMapping("geo") 14 | public class RestaurantController { 15 | 16 | @Autowired 17 | private RestaurantLocatorService locatorService; 18 | 19 | @GetMapping("{zip}") 20 | public Flux getRestaurants(@PathVariable String zip){ 21 | return this.locatorService.getRestaurants(zip); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/geo/dto/GeoLocation.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.geo.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @Data 9 | @ToString 10 | @NoArgsConstructor 11 | @AllArgsConstructor(staticName = "of") 12 | public class GeoLocation { 13 | 14 | private double longitude; 15 | private double latitude; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/geo/dto/Restaurant.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.geo.dto; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | 6 | @Data 7 | @ToString 8 | public class Restaurant { 9 | 10 | private String id; 11 | private String city; 12 | private double latitude; 13 | private double longitude; 14 | private String name; 15 | private String zip; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/geo/service/DataSetupService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.geo.service; 2 | 3 | import com.vinsguru.redisspring.geo.dto.GeoLocation; 4 | import com.vinsguru.redisspring.geo.dto.Restaurant; 5 | import com.vinsguru.redisspring.geo.util.RestaurantUtil; 6 | import org.redisson.api.RGeoReactive; 7 | import org.redisson.api.RMapReactive; 8 | import org.redisson.api.RedissonReactiveClient; 9 | import org.redisson.codec.TypedJsonJacksonCodec; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.CommandLineRunner; 12 | import org.springframework.stereotype.Service; 13 | import reactor.core.publisher.Flux; 14 | 15 | @Service 16 | public class DataSetupService implements CommandLineRunner { 17 | 18 | private RGeoReactive geo; 19 | private RMapReactive map; 20 | 21 | @Autowired 22 | private RedissonReactiveClient client; 23 | 24 | @Override 25 | public void run(String... args) throws Exception { 26 | this.geo = this.client.getGeo("restaurants", new TypedJsonJacksonCodec(Restaurant.class)); 27 | this.map = this.client.getMap("usa", new TypedJsonJacksonCodec(String.class, GeoLocation.class)); 28 | 29 | Flux.fromIterable(RestaurantUtil.getRestaurants()) 30 | .flatMap(r -> this.geo.add(r.getLongitude(), r.getLatitude(), r).thenReturn(r)) 31 | .flatMap(r -> this.map.fastPut(r.getZip(), GeoLocation.of(r.getLongitude(), r.getLatitude()))) 32 | .doFinally(s -> System.out.println("restaurants added " + s)) 33 | .subscribe(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/geo/service/RestaurantLocatorService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.geo.service; 2 | 3 | import com.vinsguru.redisspring.geo.dto.GeoLocation; 4 | import com.vinsguru.redisspring.geo.dto.Restaurant; 5 | import org.redisson.api.GeoUnit; 6 | import org.redisson.api.RGeoReactive; 7 | import org.redisson.api.RMapReactive; 8 | import org.redisson.api.RedissonReactiveClient; 9 | import org.redisson.api.geo.GeoSearchArgs; 10 | import org.redisson.codec.TypedJsonJacksonCodec; 11 | import org.springframework.stereotype.Service; 12 | import reactor.core.publisher.Flux; 13 | 14 | import java.util.function.Function; 15 | 16 | @Service 17 | public class RestaurantLocatorService { 18 | 19 | private RGeoReactive geo; 20 | private RMapReactive map; 21 | 22 | public RestaurantLocatorService(RedissonReactiveClient client) { 23 | this.geo = client.getGeo("restaurants", new TypedJsonJacksonCodec(Restaurant.class)); 24 | this.map = client.getMap("usa", new TypedJsonJacksonCodec(String.class, GeoLocation.class)); 25 | } 26 | 27 | public Flux getRestaurants(final String zipcode){ 28 | return this.map.get(zipcode) 29 | .map(gl -> GeoSearchArgs.from(gl.getLongitude(), gl.getLatitude()).radius(5, GeoUnit.MILES)) 30 | .flatMap(gs -> this.geo.search(gs)) 31 | .flatMapIterable(Function.identity()); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/geo/util/RestaurantUtil.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.geo.util; 2 | 3 | import com.fasterxml.jackson.core.type.TypeReference; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.vinsguru.redisspring.geo.dto.Restaurant; 6 | 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | public class RestaurantUtil { 13 | 14 | public static List getRestaurants(){ 15 | ObjectMapper mapper = new ObjectMapper(); 16 | InputStream stream = RestaurantUtil.class.getClassLoader().getResourceAsStream("restaurant.json"); 17 | try { 18 | return mapper.readValue(stream, new TypeReference>() { 19 | }); 20 | } catch (IOException e) { 21 | e.printStackTrace(); 22 | } 23 | return Collections.emptyList(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/weather/controller/WeatherController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.weather.controller; 2 | 3 | import com.vinsguru.redisspring.weather.service.WeatherService; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.PathVariable; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import reactor.core.publisher.Mono; 10 | 11 | @RestController 12 | @RequestMapping("weather") 13 | public class WeatherController { 14 | 15 | @Autowired 16 | private WeatherService service; 17 | 18 | @GetMapping("{zip}") 19 | public Mono getWeather(@PathVariable int zip){ 20 | return Mono.fromSupplier(() -> this.service.getInfo(zip)); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/weather/service/ExternalServiceClient.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.weather.service; 2 | 3 | import org.springframework.cache.annotation.CachePut; 4 | import org.springframework.stereotype.Service; 5 | 6 | import java.util.concurrent.ThreadLocalRandom; 7 | 8 | @Service 9 | public class ExternalServiceClient { 10 | 11 | @CachePut(value = "weather", key = "#zip") 12 | public int getWeatherInfo(int zip){ 13 | return ThreadLocalRandom.current().nextInt(60, 100); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /redis-spring/src/main/java/com/vinsguru/redisspring/weather/service/WeatherService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring.weather.service; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.cache.annotation.Cacheable; 5 | import org.springframework.stereotype.Service; 6 | 7 | import java.util.stream.IntStream; 8 | 9 | @Service 10 | public class WeatherService { 11 | 12 | @Autowired 13 | private ExternalServiceClient client; 14 | 15 | @Cacheable("weather") 16 | public int getInfo(int zip){ 17 | return 0; 18 | } 19 | 20 | // @Scheduled(fixedRate = 10_000) 21 | public void update(){ 22 | System.out.println("updating weather"); 23 | IntStream.rangeClosed(1, 5) 24 | .forEach(this.client::getWeatherInfo); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /redis-spring/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | city.service.url=http://localhost:3030/open-city-api/ 2 | -------------------------------------------------------------------------------- /redis-spring/src/main/resources/static/geo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Restaurant Locator 15 | 16 | 17 | 18 | 19 |
20 |

Restaurant Locator

21 | 22 |
23 | 24 |
25 |
26 | 27 |
28 |
29 | 30 |
31 |
32 |
33 | 34 | 35 |
36 | 37 | 38 | 39 |
40 | 41 | 42 | 87 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /redis-spring/src/main/resources/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Redis Chat Demo 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 |
21 | Name 22 | 23 |
24 | 25 | 26 |
27 | Room 28 | 29 |
30 | 31 | 35 |
36 | 37 |
38 | 39 | 42 | 43 | 62 | 63 |
64 | 65 | 66 | 67 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /redis-spring/src/test/java/com/vinsguru/redisspring/RedisSpringApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisspring; 2 | 3 | import org.junit.jupiter.api.RepeatedTest; 4 | import org.redisson.api.RAtomicLongReactive; 5 | import org.redisson.api.RedissonReactiveClient; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.data.redis.core.ReactiveStringRedisTemplate; 9 | import org.springframework.data.redis.core.ReactiveValueOperations; 10 | import reactor.core.publisher.Flux; 11 | import reactor.core.publisher.Mono; 12 | import reactor.test.StepVerifier; 13 | 14 | @SpringBootTest 15 | class RedisSpringApplicationTests { 16 | 17 | @Autowired 18 | private ReactiveStringRedisTemplate template; 19 | 20 | @Autowired 21 | private RedissonReactiveClient client; 22 | 23 | @RepeatedTest(3) 24 | void springDataRedisTest() { 25 | ReactiveValueOperations valueOperations = this.template.opsForValue(); 26 | long before = System.currentTimeMillis(); 27 | Mono mono = Flux.range(1, 500_000) 28 | .flatMap(i -> valueOperations.increment("user:1:visit")) // incr 29 | .then(); 30 | StepVerifier.create(mono) 31 | .verifyComplete(); 32 | long after = System.currentTimeMillis(); 33 | System.out.println((after - before) + " ms"); 34 | } 35 | 36 | @RepeatedTest(3) 37 | void redissonTest() { 38 | RAtomicLongReactive atomicLong = this.client.getAtomicLong("user:2:visit"); 39 | long before = System.currentTimeMillis(); 40 | Mono mono = Flux.range(1, 500_000) 41 | .flatMap(i -> atomicLong.incrementAndGet()) // incr 42 | .then(); 43 | StepVerifier.create(mono) 44 | .verifyComplete(); 45 | long after = System.currentTimeMillis(); 46 | System.out.println((after - before) + " ms"); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /redisson-playground/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.vinsguru 8 | redisson-playground 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 3.47.0 13 | 1.18.36 14 | 5.11.3 15 | 16 | 17 | 18 | 19 | org.redisson 20 | redisson 21 | ${redisson.version} 22 | 23 | 24 | org.projectlombok 25 | lombok 26 | ${lombok.version} 27 | provided 28 | 29 | 30 | io.projectreactor 31 | reactor-test 32 | test 33 | 34 | 35 | org.junit.jupiter 36 | junit-jupiter-engine 37 | ${junit.version} 38 | test 39 | 40 | 41 | 42 | 43 | 44 | io.projectreactor 45 | reactor-bom 46 | 2024.0.6 47 | pom 48 | import 49 | 50 | 51 | 52 | 53 | 54 | 55 | org.apache.maven.plugins 56 | maven-compiler-plugin 57 | 3.8.0 58 | 59 | 21 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/BaseTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import com.vinsguru.redisson.test.config.RedissonConfig; 4 | import org.junit.jupiter.api.AfterAll; 5 | import org.junit.jupiter.api.BeforeAll; 6 | import org.junit.jupiter.api.TestInstance; 7 | import org.redisson.api.RedissonReactiveClient; 8 | 9 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 10 | public abstract class BaseTest { 11 | 12 | private final RedissonConfig redissonConfig = new RedissonConfig(); 13 | protected RedissonReactiveClient client; 14 | 15 | @BeforeAll 16 | public void setClient(){ 17 | this.client = this.redissonConfig.getReactiveClient(); 18 | } 19 | 20 | @AfterAll 21 | public void shutdown(){ 22 | this.redissonConfig.getClient().shutdown(); 23 | } 24 | 25 | protected void sleep(long millis){ 26 | try { 27 | Thread.sleep(millis); 28 | } catch (InterruptedException e) { 29 | e.printStackTrace(); 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec01KeyValueTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.redisson.api.RBucketReactive; 5 | import org.redisson.client.codec.StringCodec; 6 | import reactor.core.publisher.Mono; 7 | import reactor.test.StepVerifier; 8 | 9 | import java.time.Duration; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | public class Lec01KeyValueTest extends BaseTest{ 13 | 14 | @Test 15 | public void keyValueAccessTest(){ 16 | RBucketReactive bucket = this.client.getBucket("user:1:name", StringCodec.INSTANCE); 17 | Mono set = bucket.set("sam"); 18 | Mono get = bucket.get() 19 | .doOnNext(System.out::println) 20 | .then(); 21 | StepVerifier.create(set.concatWith(get)) 22 | .verifyComplete(); 23 | } 24 | 25 | @Test 26 | public void keyValueExpiryTest(){ 27 | RBucketReactive bucket = this.client.getBucket("user:1:name", StringCodec.INSTANCE); 28 | Mono set = bucket.set("sam", Duration.ofSeconds(10)); 29 | Mono get = bucket.get() 30 | .doOnNext(System.out::println) 31 | .then(); 32 | StepVerifier.create(set.concatWith(get)) 33 | .verifyComplete(); 34 | } 35 | 36 | @Test 37 | public void keyValueExtendExpiryTest(){ 38 | RBucketReactive bucket = this.client.getBucket("user:1:name", StringCodec.INSTANCE); 39 | Mono set = bucket.set("sam", Duration.ofSeconds(10)); 40 | Mono get = bucket.get() 41 | .doOnNext(System.out::println) 42 | .then(); 43 | StepVerifier.create(set.concatWith(get)) 44 | .verifyComplete(); 45 | //extend 46 | sleep(5000); 47 | Mono mono = bucket.expire(Duration.ofSeconds(60)); 48 | StepVerifier.create(mono) 49 | .expectNext(true) 50 | .verifyComplete(); 51 | // access expiration time 52 | Mono ttl = bucket.remainTimeToLive() 53 | .doOnNext(System.out::println) 54 | .then(); 55 | StepVerifier.create(ttl) 56 | .verifyComplete(); 57 | } 58 | 59 | 60 | } 61 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec02KeyValueObjectTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import com.vinsguru.redisson.test.dto.Student; 4 | import org.junit.jupiter.api.Test; 5 | import org.redisson.api.RBucketReactive; 6 | import org.redisson.codec.TypedJsonJacksonCodec; 7 | import reactor.core.publisher.Mono; 8 | import reactor.test.StepVerifier; 9 | 10 | import java.util.Arrays; 11 | 12 | public class Lec02KeyValueObjectTest extends BaseTest { 13 | 14 | @Test 15 | public void keyValueObjectTest(){ 16 | Student student = new Student("marshal", 10, "atlanta", Arrays.asList(1,2, 3)); 17 | RBucketReactive bucket = this.client.getBucket("student:1", new TypedJsonJacksonCodec(Student.class)); 18 | Mono set = bucket.set(student); 19 | Mono get = bucket.get() 20 | .doOnNext(System.out::println) 21 | .then(); 22 | StepVerifier.create(set.concatWith(get)) 23 | .verifyComplete(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec03NumberTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.redisson.api.RAtomicLongReactive; 5 | import reactor.core.publisher.Flux; 6 | import reactor.core.publisher.Mono; 7 | import reactor.test.StepVerifier; 8 | 9 | import java.time.Duration; 10 | 11 | public class Lec03NumberTest extends BaseTest { 12 | 13 | @Test 14 | public void keyValueIncreaseTest(){ 15 | // set k v -- incr , decr 16 | RAtomicLongReactive atomicLong = this.client.getAtomicLong("user:1:visit"); 17 | Mono mono = Flux.range(1, 30) 18 | .delayElements(Duration.ofSeconds(1)) 19 | .flatMap(i -> atomicLong.incrementAndGet()) 20 | .then(); 21 | StepVerifier.create(mono) 22 | .verifyComplete(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec04BucketAsMapTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.redisson.client.codec.StringCodec; 5 | import reactor.core.publisher.Mono; 6 | import reactor.test.StepVerifier; 7 | 8 | public class Lec04BucketAsMapTest extends BaseTest { 9 | // user:1:name 10 | // user:2:name 11 | // user:3:name 12 | @Test 13 | public void bucketsAsMap(){ 14 | 15 | Mono mono = this.client.getBuckets(StringCodec.INSTANCE) 16 | .get("user:1:name", "user:2:name", "user:3:name", "user:4:name") 17 | .doOnNext(System.out::println) 18 | .then(); 19 | 20 | StepVerifier.create(mono) 21 | .verifyComplete(); 22 | 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec05EventListenerTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.redisson.api.DeletedObjectListener; 5 | import org.redisson.api.ExpiredObjectListener; 6 | import org.redisson.api.RBucketReactive; 7 | import org.redisson.client.codec.StringCodec; 8 | import reactor.core.publisher.Mono; 9 | import reactor.test.StepVerifier; 10 | 11 | import java.time.Duration; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | public class Lec05EventListenerTest extends BaseTest { 15 | 16 | @Test 17 | public void expiredEventTest(){ 18 | RBucketReactive bucket = this.client.getBucket("user:1:name", StringCodec.INSTANCE); 19 | Mono set = bucket.set("sam", Duration.ofSeconds(10)); 20 | Mono get = bucket.get() 21 | .doOnNext(System.out::println) 22 | .then(); 23 | Mono event = bucket.addListener(new ExpiredObjectListener() { 24 | @Override 25 | public void onExpired(String s) { 26 | System.out.println("Expired : " + s); 27 | } 28 | }).then(); 29 | 30 | StepVerifier.create(set.concatWith(get).concatWith(event)) 31 | .verifyComplete(); 32 | //extend 33 | sleep(11000); 34 | } 35 | 36 | @Test 37 | public void deletedEventTest(){ 38 | RBucketReactive bucket = this.client.getBucket("user:1:name", StringCodec.INSTANCE); 39 | Mono set = bucket.set("sam"); 40 | Mono get = bucket.get() 41 | .doOnNext(System.out::println) 42 | .then(); 43 | Mono event = bucket.addListener(new DeletedObjectListener() { 44 | @Override 45 | public void onDeleted(String s) { 46 | System.out.println("Deleted : " + s); 47 | } 48 | }).then(); 49 | 50 | StepVerifier.create(set.concatWith(get).concatWith(event)) 51 | .verifyComplete(); 52 | //extend 53 | sleep(60000); 54 | } 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec06MapTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import com.vinsguru.redisson.test.dto.Student; 4 | import org.junit.jupiter.api.Test; 5 | import org.redisson.api.RMapReactive; 6 | import org.redisson.client.codec.StringCodec; 7 | import org.redisson.codec.TypedJsonJacksonCodec; 8 | import reactor.core.publisher.Mono; 9 | import reactor.test.StepVerifier; 10 | 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | public class Lec06MapTest extends BaseTest { 15 | 16 | @Test 17 | public void mapTest1(){ 18 | RMapReactive map = this.client.getMap("user:1", StringCodec.INSTANCE); 19 | Mono name = map.put("name", "sam"); 20 | Mono age = map.put("age", "10"); 21 | Mono city = map.put("city", "atlanta"); 22 | StepVerifier.create(name.concatWith(age).concatWith(city).then()) 23 | .verifyComplete(); 24 | } 25 | 26 | @Test 27 | public void mapTest2(){ 28 | RMapReactive map = this.client.getMap("user:2", StringCodec.INSTANCE); 29 | Map javaMap = Map.of( 30 | "name", "jake", 31 | "age", "30", 32 | "city", "miami" 33 | ); 34 | StepVerifier.create(map.putAll(javaMap).then()) 35 | .verifyComplete(); 36 | } 37 | 38 | @Test 39 | public void mapTest3(){ 40 | // Map 41 | TypedJsonJacksonCodec codec = new TypedJsonJacksonCodec(Integer.class, Student.class); 42 | RMapReactive map = this.client.getMap("users", codec); 43 | 44 | Student student1 = new Student("sam", 10, "atlanta", List.of(1, 2, 3)); 45 | Student student2 = new Student("jake", 30, "miami", List.of(10, 20, 30)); 46 | 47 | Mono mono1 = map.put(1, student1); 48 | Mono mono2 = map.put(2, student2); 49 | 50 | StepVerifier.create(mono1.concatWith(mono2).then()) 51 | .verifyComplete(); 52 | 53 | } 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec07MapCacheTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import com.vinsguru.redisson.test.dto.Student; 4 | import org.junit.jupiter.api.Test; 5 | import org.redisson.api.RMapCacheReactive; 6 | import org.redisson.codec.TypedJsonJacksonCodec; 7 | import reactor.core.publisher.Mono; 8 | import reactor.test.StepVerifier; 9 | 10 | import java.util.List; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | public class Lec07MapCacheTest extends BaseTest { 14 | 15 | @Test 16 | public void mapCacheTest(){ 17 | // Map 18 | TypedJsonJacksonCodec codec = new TypedJsonJacksonCodec(Integer.class, Student.class); 19 | RMapCacheReactive mapCache = this.client.getMapCache("users:cache", codec); 20 | 21 | Student student1 = new Student("sam", 10, "atlanta", List.of(1, 2, 3)); 22 | Student student2 = new Student("jake", 30, "miami", List.of(10, 20, 30)); 23 | 24 | Mono st1 = mapCache.put(1, student1, 5, TimeUnit.SECONDS); 25 | Mono st2 = mapCache.put(2, student2, 10, TimeUnit.SECONDS); 26 | 27 | StepVerifier.create(st1.then(st2).then()) 28 | .verifyComplete(); 29 | 30 | sleep(3000); 31 | 32 | // access students 33 | mapCache.get(1).doOnNext(System.out::println).subscribe(); 34 | mapCache.get(2).doOnNext(System.out::println).subscribe(); 35 | 36 | sleep(3000); 37 | 38 | // access students 39 | mapCache.get(1).doOnNext(System.out::println).subscribe(); 40 | mapCache.get(2).doOnNext(System.out::println).subscribe(); 41 | 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec08LocalCachedMapTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import com.vinsguru.redisson.test.config.RedissonConfig; 4 | import com.vinsguru.redisson.test.dto.Student; 5 | import org.junit.jupiter.api.BeforeAll; 6 | import org.junit.jupiter.api.Test; 7 | import org.redisson.api.RLocalCachedMap; 8 | import org.redisson.api.RedissonClient; 9 | import org.redisson.api.options.LocalCachedMapOptions; 10 | import reactor.core.publisher.Flux; 11 | 12 | import java.time.Duration; 13 | import java.util.List; 14 | 15 | public class Lec08LocalCachedMapTest extends BaseTest { 16 | 17 | private RLocalCachedMap studentsMap; 18 | 19 | @BeforeAll 20 | public void setupClient(){ 21 | RedissonConfig config = new RedissonConfig(); 22 | RedissonClient redissonClient = config.getClient(); 23 | 24 | LocalCachedMapOptions mapOptions = LocalCachedMapOptions.name("students") 25 | .syncStrategy(LocalCachedMapOptions.SyncStrategy.UPDATE) 26 | .reconnectionStrategy(LocalCachedMapOptions.ReconnectionStrategy.CLEAR); 27 | 28 | this.studentsMap = redissonClient.getLocalCachedMap(mapOptions); 29 | } 30 | 31 | @Test 32 | public void appServer1(){ 33 | Student student1 = new Student("sam", 10, "atlanta", List.of(1, 2, 3)); 34 | Student student2 = new Student("jake", 30, "miami", List.of(10, 20, 30)); 35 | 36 | this.studentsMap.put(1, student1); 37 | this.studentsMap.put(2, student2); 38 | 39 | Flux.interval(Duration.ofSeconds(1)) 40 | .doOnNext(i -> System.out.println(i + " ==> " + studentsMap.get(1))) 41 | .subscribe(); 42 | 43 | sleep(600000); 44 | } 45 | 46 | @Test 47 | public void appServer2(){ 48 | Student student1 = new Student("sam-updated", 10, "atlanta", List.of(1, 2, 3)); 49 | this.studentsMap.put(1, student1); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec09ListQueueStackTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.redisson.api.RDequeReactive; 5 | import org.redisson.api.RListReactive; 6 | import org.redisson.api.RQueueReactive; 7 | import org.redisson.client.codec.LongCodec; 8 | import reactor.core.publisher.Mono; 9 | import reactor.test.StepVerifier; 10 | 11 | import java.util.List; 12 | import java.util.stream.Collectors; 13 | import java.util.stream.LongStream; 14 | 15 | public class Lec09ListQueueStackTest extends BaseTest { 16 | 17 | @Test 18 | public void listTest(){ 19 | // lrange number-input 0 -1 20 | RListReactive list = this.client.getList("number-input", LongCodec.INSTANCE); 21 | 22 | List longList = LongStream.rangeClosed(1, 10) 23 | .boxed() 24 | .collect(Collectors.toList()); 25 | 26 | StepVerifier.create(list.addAll(longList).then()) 27 | .verifyComplete(); 28 | StepVerifier.create(list.size()) 29 | .expectNext(10) 30 | .verifyComplete(); 31 | } 32 | 33 | @Test 34 | public void queueTest(){ 35 | RQueueReactive queue = this.client.getQueue("number-input", LongCodec.INSTANCE); 36 | Mono queuePoll = queue.poll() 37 | .repeat(3) 38 | .doOnNext(System.out::println) 39 | .then(); 40 | StepVerifier.create(queuePoll) 41 | .verifyComplete(); 42 | StepVerifier.create(queue.size()) 43 | .expectNext(6) 44 | .verifyComplete(); 45 | } 46 | 47 | @Test 48 | public void stackTest(){ // Deque 49 | RDequeReactive deque = this.client.getDeque("number-input", LongCodec.INSTANCE); 50 | Mono stackPoll = deque.pollLast() 51 | .repeat(3) 52 | .doOnNext(System.out::println) 53 | .then(); 54 | StepVerifier.create(stackPoll) 55 | .verifyComplete(); 56 | StepVerifier.create(deque.size()) 57 | .expectNext(2) 58 | .verifyComplete(); 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec10MessageQueueTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import org.junit.jupiter.api.BeforeAll; 4 | import org.junit.jupiter.api.Test; 5 | import org.redisson.api.RBlockingDequeReactive; 6 | import org.redisson.client.codec.LongCodec; 7 | import reactor.core.publisher.Flux; 8 | import reactor.core.publisher.Mono; 9 | import reactor.test.StepVerifier; 10 | 11 | import java.time.Duration; 12 | 13 | public class Lec10MessageQueueTest extends BaseTest { 14 | 15 | private RBlockingDequeReactive msgQueue; 16 | 17 | @BeforeAll 18 | public void setupQueue(){ 19 | this.msgQueue = this.client.getBlockingDeque("message-queue", LongCodec.INSTANCE); 20 | } 21 | 22 | @Test 23 | public void consumer1(){ 24 | this.msgQueue.takeElements() 25 | .doOnNext(i -> System.out.println("Consumer 1 : " + i)) 26 | .doOnError(System.out::println) 27 | .subscribe(); 28 | sleep(600_000); 29 | } 30 | 31 | @Test 32 | public void consumer2(){ 33 | this.msgQueue.takeElements() 34 | .doOnNext(i -> System.out.println("Consumer 2 : " + i)) 35 | .doOnError(System.out::println) 36 | .subscribe(); 37 | sleep(600_000); 38 | } 39 | 40 | @Test 41 | public void producer(){ 42 | Mono mono = Flux.range(1, 100) 43 | .delayElements(Duration.ofMillis(500)) 44 | .doOnNext(i -> System.out.println("going to add " + i)) 45 | .flatMap(i -> this.msgQueue.add(Long.valueOf(i))) 46 | .then(); 47 | StepVerifier.create(mono) 48 | .verifyComplete(); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec11HyperLogLogTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.redisson.api.RHyperLogLogReactive; 5 | import org.redisson.client.codec.LongCodec; 6 | import reactor.core.publisher.Flux; 7 | import reactor.core.publisher.Mono; 8 | import reactor.test.StepVerifier; 9 | 10 | import java.util.List; 11 | import java.util.stream.Collectors; 12 | import java.util.stream.LongStream; 13 | 14 | public class Lec11HyperLogLogTest extends BaseTest { 15 | 16 | @Test // 12.5 kb 17 | public void count(){ 18 | RHyperLogLogReactive counter = this.client.getHyperLogLog("user:visits", LongCodec.INSTANCE); 19 | 20 | List list1 = LongStream.rangeClosed(1, 25000) 21 | .boxed() 22 | .collect(Collectors.toList()); 23 | 24 | List list2 = LongStream.rangeClosed(25001, 50000) 25 | .boxed() 26 | .collect(Collectors.toList()); 27 | 28 | List list3 = LongStream.rangeClosed(1, 75000) 29 | .boxed() 30 | .collect(Collectors.toList()); 31 | 32 | List list4 = LongStream.rangeClosed(50000, 100_000) 33 | .boxed() 34 | .collect(Collectors.toList()); 35 | 36 | Mono mono = Flux.just(list1, list2, list3, list4) 37 | .flatMap(counter::addAll) 38 | .then(); 39 | 40 | StepVerifier.create(mono) 41 | .verifyComplete(); 42 | 43 | counter.count() 44 | .doOnNext(System.out::println) 45 | .subscribe(); 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec12PubSubTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.redisson.api.RPatternTopicReactive; 5 | import org.redisson.api.RTopicReactive; 6 | import org.redisson.api.listener.PatternMessageListener; 7 | import org.redisson.client.codec.StringCodec; 8 | 9 | public class Lec12PubSubTest extends BaseTest { 10 | 11 | @Test 12 | public void subscriber1(){ 13 | RTopicReactive topic = this.client.getTopic("slack-room1", StringCodec.INSTANCE); 14 | topic.getMessages(String.class) 15 | .doOnError(System.out::println) 16 | .doOnNext(System.out::println) 17 | .subscribe(); 18 | sleep(600_000); 19 | } 20 | 21 | @Test 22 | public void subscriber2(){ 23 | RPatternTopicReactive patternTopic = this.client.getPatternTopic("slack-room*", StringCodec.INSTANCE); 24 | patternTopic.addListener(String.class, new PatternMessageListener() { 25 | @Override 26 | public void onMessage(CharSequence pattern, CharSequence topic, String msg) { 27 | System.out.println(pattern + " : " + topic + " : " + msg); 28 | } 29 | }).subscribe(); 30 | sleep(600_000); 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec13BatchTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.redisson.api.BatchOptions; 5 | import org.redisson.api.RBatchReactive; 6 | import org.redisson.api.RListReactive; 7 | import org.redisson.api.RSetReactive; 8 | import org.redisson.client.codec.LongCodec; 9 | import reactor.core.publisher.Flux; 10 | import reactor.core.publisher.Mono; 11 | import reactor.test.StepVerifier; 12 | 13 | public class Lec13BatchTest extends BaseTest { 14 | 15 | @Test // 7.6 16 | public void batchTest(){ 17 | RBatchReactive batch = this.client.createBatch(BatchOptions.defaults()); 18 | RListReactive list = batch.getList("numbers-list", LongCodec.INSTANCE); 19 | RSetReactive set = batch.getSet("numbers-set", LongCodec.INSTANCE); 20 | for (long i = 0; i < 500_000; i++) { 21 | list.add(i); 22 | set.add(i); 23 | } 24 | StepVerifier.create(batch.execute().then()) 25 | .verifyComplete(); 26 | } 27 | 28 | @Test 29 | public void regularTest(){ 30 | RListReactive list = this.client.getList("numbers-list", LongCodec.INSTANCE); 31 | RSetReactive set = this.client.getSet("numbers-set", LongCodec.INSTANCE); 32 | Mono mono = Flux.range(1, 500_000) 33 | .map(Long::valueOf) 34 | .flatMap(i -> list.add(i).then(set.add(i))) 35 | .then(); 36 | StepVerifier.create(mono) 37 | .verifyComplete(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec14TransactionTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import org.junit.jupiter.api.AfterAll; 4 | import org.junit.jupiter.api.BeforeAll; 5 | import org.junit.jupiter.api.Test; 6 | import org.redisson.api.RBucketReactive; 7 | import org.redisson.api.RTransactionReactive; 8 | import org.redisson.api.TransactionOptions; 9 | import org.redisson.client.codec.LongCodec; 10 | import reactor.core.publisher.Flux; 11 | import reactor.core.publisher.Mono; 12 | import reactor.test.StepVerifier; 13 | 14 | public class Lec14TransactionTest extends BaseTest { 15 | 16 | private RBucketReactive user1Balance; 17 | private RBucketReactive user2Balance; 18 | 19 | @BeforeAll 20 | public void accountSetup(){ 21 | this.user1Balance = this.client.getBucket("user:1:balance", LongCodec.INSTANCE); 22 | this.user2Balance = this.client.getBucket("user:2:balance", LongCodec.INSTANCE); 23 | Mono mono = user1Balance.set(100L) 24 | .then(user2Balance.set(0L)) 25 | .then(); 26 | StepVerifier.create(mono) 27 | .verifyComplete(); 28 | } 29 | 30 | @AfterAll 31 | public void accountBalanceStatus(){ 32 | Mono mono = Flux.zip(this.user1Balance.get(), this.user2Balance.get()) 33 | .doOnNext(System.out::println) 34 | .then(); 35 | StepVerifier.create(mono) 36 | .verifyComplete(); 37 | } 38 | 39 | @Test 40 | public void nonTransactionTest(){ 41 | this.transfer(user1Balance, user2Balance, 50) 42 | .thenReturn(0) 43 | .map(i -> (5 / i)) // some error 44 | .doOnError(System.out::println) 45 | .subscribe(); 46 | sleep(1000); 47 | } 48 | 49 | @Test 50 | public void transactionTest(){ 51 | RTransactionReactive transaction = this.client.createTransaction(TransactionOptions.defaults()); 52 | RBucketReactive user1Balance = transaction.getBucket("user:1:balance", LongCodec.INSTANCE); 53 | RBucketReactive user2Balance = transaction.getBucket("user:2:balance", LongCodec.INSTANCE); 54 | this.transfer(user1Balance, user2Balance, 50) 55 | .thenReturn(0) 56 | .map(i -> (5 / i)) // some error 57 | .then(transaction.commit()) 58 | .doOnError(System.out::println) 59 | .onErrorResume(ex -> transaction.rollback()) 60 | .subscribe(); 61 | sleep(1000); 62 | } 63 | 64 | private Mono transfer(RBucketReactive fromAccount, RBucketReactive toAccount, int amount){ 65 | return Flux.zip(fromAccount.get(), toAccount.get()) // [b1, b2] 66 | .filter(t -> t.getT1() >= amount) 67 | .flatMap(t -> fromAccount.set(t.getT1() - amount).thenReturn(t)) 68 | .flatMap(t -> toAccount.set(t.getT2() + amount)) 69 | .then(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec15SortedSetTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.redisson.api.BatchOptions; 5 | import org.redisson.api.RBatchReactive; 6 | import org.redisson.api.RScoredSortedSetReactive; 7 | import org.redisson.client.codec.StringCodec; 8 | import reactor.core.publisher.Flux; 9 | import reactor.core.publisher.Mono; 10 | import reactor.test.StepVerifier; 11 | 12 | import java.time.Duration; 13 | import java.util.Map; 14 | import java.util.function.Function; 15 | 16 | public class Lec15SortedSetTest extends BaseTest { 17 | 18 | @Test 19 | public void sortedSet(){ 20 | RScoredSortedSetReactive sortedSet = this.client.getScoredSortedSet("student:score", StringCodec.INSTANCE); 21 | 22 | Mono mono = sortedSet.addScore("sam", 12.25) 23 | .then(sortedSet.add(23.25, "mike")) 24 | .then(sortedSet.addScore("jake", 7)) 25 | .then(); 26 | 27 | StepVerifier.create(mono) 28 | .verifyComplete(); 29 | 30 | sortedSet.entryRange(0, 1) 31 | .flatMapIterable(Function.identity()) // flux 32 | .map(se -> se.getScore() + " : " + se.getValue()) 33 | .doOnNext(System.out::println) 34 | .subscribe(); 35 | 36 | sleep(1000); 37 | 38 | 39 | } 40 | 41 | @Test 42 | public void test(){ 43 | RScoredSortedSetReactive sortedSet = this.client.getScoredSortedSet("prod:score", StringCodec.INSTANCE); 44 | Map a = Map.of( 45 | "a", 10L, 46 | "b", 15L 47 | ); 48 | RBatchReactive batch = this.client.createBatch(BatchOptions.defaults()); 49 | RScoredSortedSetReactive set = batch.getScoredSortedSet("prod:score", StringCodec.INSTANCE); 50 | 51 | Flux.fromIterable(a.entrySet()) 52 | .doFinally(s -> System.out.println("done1")) 53 | .doOnNext(System.out::println) 54 | .map(e -> set.addScore(e.getKey(), e.getValue())) 55 | .then(batch.execute()) 56 | .doOnNext(r -> System.out.println(r.getResponses())) 57 | .subscribe(); 58 | 59 | Flux.interval(Duration.ofSeconds(3)) 60 | .buffer(Duration.ofSeconds(1)) 61 | .subscribe(System.out::println); 62 | sleep(10_000); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec16PriorityQueueTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import com.vinsguru.redisson.test.assignment.Category; 4 | import com.vinsguru.redisson.test.assignment.PriorityQueue; 5 | import com.vinsguru.redisson.test.assignment.UserOrder; 6 | import org.junit.jupiter.api.BeforeAll; 7 | import org.junit.jupiter.api.Test; 8 | import org.redisson.api.RScoredSortedSetReactive; 9 | import org.redisson.codec.TypedJsonJacksonCodec; 10 | import reactor.core.publisher.Flux; 11 | import reactor.core.publisher.Mono; 12 | import reactor.test.StepVerifier; 13 | 14 | import java.time.Duration; 15 | 16 | public class Lec16PriorityQueueTest extends BaseTest { 17 | 18 | private PriorityQueue priorityQueue; 19 | 20 | @BeforeAll 21 | public void setupQueue(){ 22 | RScoredSortedSetReactive sortedSet = this.client.getScoredSortedSet("user:order:queue", new TypedJsonJacksonCodec(UserOrder.class)); 23 | this.priorityQueue = new PriorityQueue(sortedSet); 24 | } 25 | 26 | @Test 27 | public void producer(){ 28 | Flux.interval(Duration.ofSeconds(1)) 29 | .map(l -> (l.intValue() * 5)) 30 | .doOnNext(i -> { 31 | UserOrder u1 = new UserOrder(i + 1, Category.GUEST); 32 | UserOrder u2 = new UserOrder(i + 2, Category.STD); 33 | UserOrder u3 = new UserOrder(i + 3, Category.PRIME); 34 | UserOrder u4 = new UserOrder(i + 4, Category.STD); 35 | UserOrder u5 = new UserOrder(i + 5, Category.GUEST); 36 | Mono mono = Flux.just(u1, u2, u3, u4, u5) 37 | .flatMap(this.priorityQueue::add) 38 | .then(); 39 | StepVerifier.create(mono) 40 | .verifyComplete(); 41 | }).subscribe(); 42 | sleep(60_000); 43 | } 44 | 45 | @Test 46 | public void consumer(){ 47 | this.priorityQueue.takeItems() 48 | .delayElements(Duration.ofMillis(500)) 49 | .doOnNext(System.out::println) 50 | .subscribe(); 51 | sleep(600_000); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/Lec17GeoSpatialTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test; 2 | 3 | import com.vinsguru.redisson.test.dto.GeoLocation; 4 | import com.vinsguru.redisson.test.dto.Restaurant; 5 | import com.vinsguru.redisson.test.util.RestaurantUtil; 6 | import org.junit.jupiter.api.BeforeAll; 7 | import org.junit.jupiter.api.Test; 8 | import org.redisson.api.GeoUnit; 9 | import org.redisson.api.RGeoReactive; 10 | import org.redisson.api.RMapReactive; 11 | import org.redisson.api.geo.GeoSearchArgs; 12 | import org.redisson.codec.TypedJsonJacksonCodec; 13 | import reactor.core.publisher.Flux; 14 | import reactor.core.publisher.Mono; 15 | import reactor.test.StepVerifier; 16 | 17 | import java.util.function.Function; 18 | 19 | public class Lec17GeoSpatialTest extends BaseTest { 20 | 21 | private RGeoReactive geo; 22 | private RMapReactive map; 23 | 24 | @BeforeAll 25 | public void setGeo(){ 26 | this.geo = this.client.getGeo("restaurants", new TypedJsonJacksonCodec(Restaurant.class)); 27 | this.map = this.client.getMap("us:texas", new TypedJsonJacksonCodec(String.class, GeoLocation.class)); 28 | } 29 | 30 | @Test 31 | public void add(){ 32 | Mono mono = Flux.fromIterable(RestaurantUtil.getRestaurants()) 33 | .flatMap(r -> this.geo.add(r.getLongitude(), r.getLatitude(), r).thenReturn(r)) 34 | .flatMap(r -> this.map.fastPut(r.getZip(), GeoLocation.of(r.getLongitude(), r.getLatitude()))) 35 | .then(); 36 | StepVerifier.create(mono) 37 | .verifyComplete(); 38 | } 39 | 40 | @Test 41 | public void search(){ 42 | Mono mono = this.map.get("75224") 43 | .map(gl -> GeoSearchArgs.from(gl.getLongitude(), gl.getLatitude()).radius(5, GeoUnit.MILES)) 44 | .flatMap(r -> this.geo.search(r)) 45 | .flatMapIterable(Function.identity()) 46 | .doOnNext(System.out::println) 47 | .then(); 48 | 49 | StepVerifier.create(mono) 50 | .verifyComplete(); 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/assignment/Category.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test.assignment; 2 | 3 | public enum Category { 4 | 5 | PRIME, 6 | STD, 7 | GUEST; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/assignment/PriorityQueue.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test.assignment; 2 | 3 | import org.redisson.api.RScoredSortedSetReactive; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.publisher.Mono; 6 | 7 | public class PriorityQueue { 8 | 9 | private RScoredSortedSetReactive queue; 10 | 11 | public PriorityQueue(RScoredSortedSetReactive queue) { 12 | this.queue = queue; 13 | } 14 | 15 | public Mono add(UserOrder userOrder){ 16 | return this.queue.add( 17 | getScore(userOrder.getCategory()), 18 | userOrder 19 | ).then(); 20 | } 21 | 22 | public Flux takeItems(){ 23 | return this.queue.takeFirstElements() 24 | .limitRate(1); 25 | } 26 | 27 | private double getScore(Category category){ 28 | return category.ordinal() + Double.parseDouble("0." + System.nanoTime()); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/assignment/UserOrder.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test.assignment; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @Data 9 | @ToString 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class UserOrder { 13 | private int id; 14 | private Category category; 15 | } 16 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/config/RedissonConfig.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test.config; 2 | 3 | import org.redisson.Redisson; 4 | import org.redisson.api.RedissonClient; 5 | import org.redisson.api.RedissonReactiveClient; 6 | import org.redisson.config.Config; 7 | 8 | import java.util.Objects; 9 | 10 | public class RedissonConfig { 11 | 12 | private RedissonClient redissonClient; 13 | 14 | public RedissonClient getClient(){ 15 | if(Objects.isNull(this.redissonClient)){ 16 | Config config = new Config(); 17 | config.useSingleServer() 18 | .setAddress("redis://127.0.0.1:6379"); 19 | redissonClient = Redisson.create(config); 20 | } 21 | return redissonClient; 22 | } 23 | 24 | public RedissonReactiveClient getReactiveClient(){ 25 | return getClient().reactive(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/dto/GeoLocation.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @Data 9 | @ToString 10 | @NoArgsConstructor 11 | @AllArgsConstructor(staticName = "of") 12 | public class GeoLocation { 13 | 14 | private double longitude; 15 | private double latitude; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/dto/Restaurant.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test.dto; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | 6 | @Data 7 | @ToString 8 | public class Restaurant { 9 | 10 | private String id; 11 | private String city; 12 | private double latitude; 13 | private double longitude; 14 | private String name; 15 | private String zip; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/dto/Student.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | import java.util.List; 9 | 10 | @Data 11 | @ToString 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class Student { 15 | 16 | private String name; 17 | private int age; 18 | private String city; 19 | private List marks; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /redisson-playground/src/test/java/com/vinsguru/redisson/test/util/RestaurantUtil.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.redisson.test.util; 2 | 3 | import com.fasterxml.jackson.core.type.TypeReference; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.vinsguru.redisson.test.dto.Restaurant; 6 | 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | public class RestaurantUtil { 13 | 14 | public static List getRestaurants(){ 15 | ObjectMapper mapper = new ObjectMapper(); 16 | InputStream stream = RestaurantUtil.class.getClassLoader().getResourceAsStream("restaurant.json"); 17 | try { 18 | return mapper.readValue(stream, new TypeReference>() { 19 | }); 20 | } catch (IOException e) { 21 | e.printStackTrace(); 22 | } 23 | return Collections.emptyList(); 24 | } 25 | 26 | } 27 | --------------------------------------------------------------------------------