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() { + } + +}