From 08b0b8095a06e0587e95c799bb1b162f32d7e057 Mon Sep 17 00:00:00 2001 From: Andrey Shcherbakov Date: Sat, 14 Jul 2018 21:24:33 +0200 Subject: [PATCH] Create Kotlin Spring WebFlux module --- pom.xml | 1 + spring-reactive-kotlin/pom.xml | 93 +++++++++++++++++++ .../springreactivekotlin/Application.kt | 11 +++ .../springreactivekotlin/Controller.kt | 18 ++++ .../baeldung/springreactivekotlin/Device.kt | 5 + .../HomeSensorsHandler.kt | 36 +++++++ .../HomeSensorsRouters.kt | 32 +++++++ .../baeldung/springreactivekotlin/Routes.kt | 16 ++++ .../src/test/kotlin/RoutesTest.kt | 35 +++++++ 9 files changed, 247 insertions(+) create mode 100644 spring-reactive-kotlin/pom.xml create mode 100644 spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Application.kt create mode 100644 spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Controller.kt create mode 100644 spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Device.kt create mode 100644 spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/HomeSensorsHandler.kt create mode 100644 spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/HomeSensorsRouters.kt create mode 100644 spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Routes.kt create mode 100644 spring-reactive-kotlin/src/test/kotlin/RoutesTest.kt diff --git a/pom.xml b/pom.xml index 51a62d929c..576cfce837 100644 --- a/pom.xml +++ b/pom.xml @@ -194,6 +194,7 @@ spring-mvc-kotlin spring-protobuf spring-quartz + spring-reactive-kotlin spring-rest-angular spring-rest-full spring-rest-query-language diff --git a/spring-reactive-kotlin/pom.xml b/spring-reactive-kotlin/pom.xml new file mode 100644 index 0000000000..1425adc191 --- /dev/null +++ b/spring-reactive-kotlin/pom.xml @@ -0,0 +1,93 @@ + + + 4.0.0 + + com.baeldung + springreactivekotlin + 0.0.1-SNAPSHOT + jar + + springreactivekotlin + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 2.0.3.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + 1.2.41 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-webflux + + + com.fasterxml.jackson.module + jackson-module-kotlin + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + + + org.jetbrains.kotlin + kotlin-reflect + + + + org.springframework.boot + spring-boot-starter-test + test + + + io.projectreactor + reactor-test + test + + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + org.springframework.boot + spring-boot-maven-plugin + + + kotlin-maven-plugin + org.jetbrains.kotlin + + + -Xjsr305=strict + + + spring + + + + + org.jetbrains.kotlin + kotlin-maven-allopen + ${kotlin.version} + + + + + + + + diff --git a/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Application.kt b/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Application.kt new file mode 100644 index 0000000000..87ac7417b7 --- /dev/null +++ b/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Application.kt @@ -0,0 +1,11 @@ +package com.baeldung.springreactivekotlin + +import org.springframework.boot.SpringApplication +import org.springframework.boot.autoconfigure.SpringBootApplication + +@SpringBootApplication +class Application + +fun main(args: Array) { + SpringApplication.run(Application::class.java, *args) +} diff --git a/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Controller.kt b/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Controller.kt new file mode 100644 index 0000000000..76f8a62b85 --- /dev/null +++ b/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Controller.kt @@ -0,0 +1,18 @@ +package com.baeldung.springreactivekotlin + +import org.springframework.http.MediaType +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.ResponseBody +import reactor.core.publisher.Flux + +@Controller +class Controller { + + @GetMapping(path = ["/numbers"], produces = [MediaType.APPLICATION_STREAM_JSON_VALUE]) + @ResponseBody + fun getNumbers(): Flux { + return Flux.range(1, 100) + } + +} diff --git a/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Device.kt b/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Device.kt new file mode 100644 index 0000000000..9eb6eb8488 --- /dev/null +++ b/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Device.kt @@ -0,0 +1,5 @@ +package com.baeldung.springreactivekotlin + +class Device(val name: String, val reading: Double) { + +} diff --git a/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/HomeSensorsHandler.kt b/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/HomeSensorsHandler.kt new file mode 100644 index 0000000000..0ef9f37f1b --- /dev/null +++ b/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/HomeSensorsHandler.kt @@ -0,0 +1,36 @@ +package com.baeldung.springreactivekotlin + +import org.springframework.stereotype.Component +import org.springframework.web.reactive.function.BodyInserters.fromObject +import org.springframework.web.reactive.function.server.ServerRequest +import org.springframework.web.reactive.function.server.ServerResponse +import reactor.core.publisher.Mono + +@Component +class HomeSensorsHandler { + + var data = mapOf("lamp" to arrayOf(0.7, 0.65, 0.67), "fridge" to arrayOf(12.0, 11.9, 12.5)) + + fun setLight(request: ServerRequest): Mono = ServerResponse.ok().build() + + fun getLightReading(request: ServerRequest): Mono = + ServerResponse.ok().body(fromObject(data["lamp"]!!)) + + fun getDeviceReadings(request: ServerRequest): Mono { + val id = request.pathVariable("id") + return ServerResponse.ok().body(fromObject(Device(id, 1.0))) + } + + fun getAllDevices(request: ServerRequest): Mono = + ServerResponse.ok().body(fromObject(arrayOf("lamp", "tv"))) + + fun getAllDeviceApi(request: ServerRequest): Mono = + ServerResponse.ok().body(fromObject(arrayListOf("kettle", "fridge"))) + + fun setDeviceReadingApi(request: ServerRequest): Mono { + return request.bodyToMono(Device::class.java).flatMap { it -> + ServerResponse.ok().body(fromObject(Device(it.name.toUpperCase(), it.reading))) + } + } + +} \ No newline at end of file diff --git a/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/HomeSensorsRouters.kt b/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/HomeSensorsRouters.kt new file mode 100644 index 0000000000..27d87afd89 --- /dev/null +++ b/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/HomeSensorsRouters.kt @@ -0,0 +1,32 @@ +package com.baeldung.springreactivekotlin + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.http.MediaType.APPLICATION_JSON +import org.springframework.http.MediaType.TEXT_HTML +import org.springframework.web.reactive.function.server.router + +@Configuration +class HomeSensorsRouters(private val handler: HomeSensorsHandler) { + + @Bean + fun roomsRouter() = router { + (accept(TEXT_HTML) and "/room").nest { + GET("/light", handler::getLightReading) + POST("/light", handler::setLight) + } + } + + @Bean + fun deviceRouter() = router { + accept(TEXT_HTML).nest { + (GET("/device/") or GET("/devices/")).invoke(handler::getAllDevices) + GET("/device/{id}", handler::getDeviceReadings) + } + (accept(APPLICATION_JSON) and "/api").nest { + (GET("/device/") or GET("/devices/")).invoke(handler::getAllDeviceApi) + POST("/device/", handler::setDeviceReadingApi) + } + } + +} diff --git a/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Routes.kt b/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Routes.kt new file mode 100644 index 0000000000..9015fc5df8 --- /dev/null +++ b/spring-reactive-kotlin/src/main/kotlin/com/baeldung/springreactivekotlin/Routes.kt @@ -0,0 +1,16 @@ +package com.baeldung.springreactivekotlin + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.web.reactive.function.server.ServerResponse +import org.springframework.web.reactive.function.server.router + +import org.springframework.web.reactive.function.BodyInserters.fromObject + +@Configuration +class SimpleRoute { + @Bean + fun route() = router { + GET("/route") { _ -> ServerResponse.ok().body(fromObject(arrayOf(1, 2, 3))) } + } +} \ No newline at end of file diff --git a/spring-reactive-kotlin/src/test/kotlin/RoutesTest.kt b/spring-reactive-kotlin/src/test/kotlin/RoutesTest.kt new file mode 100644 index 0000000000..ba640070e3 --- /dev/null +++ b/spring-reactive-kotlin/src/test/kotlin/RoutesTest.kt @@ -0,0 +1,35 @@ +package veontomo + +import com.baeldung.springreactivekotlin.SimpleRoute +import org.junit.Before +import org.junit.Test +import org.springframework.test.web.reactive.server.WebTestClient + +class RoutesTest { + + lateinit var client: WebTestClient + + @Before + fun init() { + this.client = WebTestClient.bindToRouterFunction(SimpleRoute().route()).build() + } + + + @Test + fun whenRequestToRoute_thenStatusShouldBeOk() { + client.get() + .uri("/route") + .exchange() + .expectStatus().isOk + } + + + @Test + fun whenRequestToRoute_thenBodyShouldContainArray123() { + client.get() + .uri("/route") + .exchange() + .expectBody() + .json("[1, 2, 3]") + } +} \ No newline at end of file