diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..81a33ed
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,25 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..1cdc19f
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,95 @@
+
+
+ 4.0.0
+
+ com.example
+ webflux-demo
+ 0.0.1-SNAPSHOT
+ jar
+
+ webflux-demo
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.0.0.RELEASE
+
+
+
+
+ UTF-8
+ UTF-8
+ 9
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ spring-boot-starter-logging
+ org.springframework.boot
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-mongodb-reactive
+
+
+ spring-boot-starter-logging
+ org.springframework.boot
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis-reactive
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+ org.springframework.boot
+ spring-boot-starter-log4j2
+
+
+ com.google.guava
+ guava
+ 23.3-jre
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ io.projectreactor
+ reactor-test
+ test
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
diff --git a/src/main/java/com/example/webfluxdemo/WebfluxDemoApplication.java b/src/main/java/com/example/webfluxdemo/WebfluxDemoApplication.java
new file mode 100644
index 0000000..5377dbf
--- /dev/null
+++ b/src/main/java/com/example/webfluxdemo/WebfluxDemoApplication.java
@@ -0,0 +1,77 @@
+package com.example.webfluxdemo;
+
+import com.example.webfluxdemo.model.Person;
+import com.example.webfluxdemo.repository.MongoRepository;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
+import org.springframework.data.redis.core.ReactiveRedisTemplate;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+import reactor.core.publisher.Mono;
+
+import java.util.Map;
+import java.util.Set;
+
+@SpringBootApplication
+@Slf4j
+public class WebfluxDemoApplication
+{
+ public static void main(String[] args)
+ {
+ SpringApplication.run(WebfluxDemoApplication.class, args);
+ }
+
+ @Bean
+ public ReactiveRedisTemplate reactiveRedisTemplate(ReactiveRedisConnectionFactory connectionFactory)
+ {
+ return new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext.string());
+ }
+
+ @Bean
+ public CommandLineRunner initRedis(ReactiveRedisTemplate reactiveRedisTemplate)
+ {
+ return args ->
+ {
+ reactiveRedisTemplate.keys("*")
+ .doOnNext(key -> log.info("Found key in DB: " + key))
+ .flatMap(reactiveRedisTemplate::delete)
+ .doOnComplete(() -> log.info("Removed found keys."))
+ .then(insertIntoRedis(reactiveRedisTemplate))
+ .subscribe(ignored -> log.info("Thread checking message."));
+ };
+ }
+
+ @Bean
+ public CommandLineRunner savePeopleToMongo(MongoRepository mongoRepository)
+ {
+ return args ->
+ {
+ mongoRepository.deleteAll().thenMany(mongoRepository.saveAll(Set.of(
+ new Person(1, "Jack", 45, "Oklahoma"),
+ new Person(2, "John", 24, "Chicago"),
+ new Person(6, "Smith", 11, "London"),
+ new Person(5, "Rose", 39, "Kuala Lumpur"),
+ new Person(7, "Alexander", 44, "Amsterdam"),
+ new Person(3, "Jane", 32, "Brian"),
+ new Person(4, "Brian", 48, "New York"))))
+ .subscribe(person -> log.info("Saved person: " + person));
+ };
+ }
+
+ private Mono insertIntoRedis(ReactiveRedisTemplate reactiveRedisTemplate)
+ {
+ return reactiveRedisTemplate.opsForValue()
+ .multiSet(Map.of(
+ "one", "1",
+ "two", "2",
+ "three", "3",
+ "four", "4",
+ "six", "6",
+ "seven", "7",
+ "five", "5"))
+ .doOnNext(isSuccess -> log.info("Redis insert success: " + isSuccess));
+ }
+}
diff --git a/src/main/java/com/example/webfluxdemo/controller/PersonController.java b/src/main/java/com/example/webfluxdemo/controller/PersonController.java
new file mode 100644
index 0000000..d381bd5
--- /dev/null
+++ b/src/main/java/com/example/webfluxdemo/controller/PersonController.java
@@ -0,0 +1,52 @@
+package com.example.webfluxdemo.controller;
+
+import com.example.webfluxdemo.model.Person;
+import com.example.webfluxdemo.repository.MongoRepository;
+import org.springframework.data.redis.core.ReactiveRedisTemplate;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.time.Duration;
+import java.util.Objects;
+import java.util.Set;
+
+@RestController
+public class PersonController
+{
+ private final ReactiveRedisTemplate reactiveRedisTemplate;
+ private final MongoRepository mongoRepository;
+
+ public PersonController(ReactiveRedisTemplate reactiveRedisTemplate, MongoRepository mongoRepository)
+ {
+ this.reactiveRedisTemplate = reactiveRedisTemplate;
+ this.mongoRepository = mongoRepository;
+ }
+
+ @GetMapping("/people")
+ public Flux getPersonsByStringNumber(@RequestParam Set numbers)
+ {
+ return Flux.fromIterable(numbers)
+ .flatMap(number -> reactiveRedisTemplate.opsForValue().get(number))
+ .filter(Objects::nonNull)
+ .map(Integer::valueOf)
+ .flatMap(id -> mongoRepository.findById(id))
+ .switchIfEmpty(Mono.error(new IllegalArgumentException("Not found person.")));
+ }
+
+ @GetMapping(value = "/people-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
+ public Flux getAllAsStream()
+ {
+ return mongoRepository.findAll().delayElements(Duration.ofMillis(1000));
+ }
+
+ @ResponseBody
+ @ExceptionHandler(IllegalArgumentException.class)
+ public ResponseEntity> response()
+ {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Not Found");
+ }
+}
diff --git a/src/main/java/com/example/webfluxdemo/model/Person.java b/src/main/java/com/example/webfluxdemo/model/Person.java
new file mode 100644
index 0000000..512afaa
--- /dev/null
+++ b/src/main/java/com/example/webfluxdemo/model/Person.java
@@ -0,0 +1,16 @@
+package com.example.webfluxdemo.model;
+
+import lombok.Data;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Data
+@Document
+public class Person
+{
+ @Id
+ private final int id;
+ private final String name;
+ private final int age;
+ private final String city;
+}
diff --git a/src/main/java/com/example/webfluxdemo/repository/MongoRepository.java b/src/main/java/com/example/webfluxdemo/repository/MongoRepository.java
new file mode 100644
index 0000000..5bbc5d8
--- /dev/null
+++ b/src/main/java/com/example/webfluxdemo/repository/MongoRepository.java
@@ -0,0 +1,10 @@
+package com.example.webfluxdemo.repository;
+
+import com.example.webfluxdemo.model.Person;
+import org.springframework.data.repository.reactive.ReactiveCrudRepository;
+import reactor.core.publisher.Mono;
+
+public interface MongoRepository extends ReactiveCrudRepository
+{
+ Mono findById(int id);
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..25a0604
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,2 @@
+spring.data.mongodb.host=192.168.99.100
+spring.redis.host=192.168.99.100
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..9537c72
--- /dev/null
+++ b/src/main/resources/log4j2.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%30.30t] %-40.40c{1.} : %m%n%ex
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/com/example/webfluxdemo/WebfluxDemoApplicationTests.java b/src/test/java/com/example/webfluxdemo/WebfluxDemoApplicationTests.java
new file mode 100644
index 0000000..12bcf41
--- /dev/null
+++ b/src/test/java/com/example/webfluxdemo/WebfluxDemoApplicationTests.java
@@ -0,0 +1,16 @@
+package com.example.webfluxdemo;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class WebfluxDemoApplicationTests {
+
+ @Test
+ public void contextLoads() {
+ }
+
+}