KotlinによるSpring Webflux

Kotlinを使用したSpring Webflux

1. 概要

このチュートリアルでは、Kotlinプログラミング言語を使用してSpring WebFluxモジュールを使用する方法を示します。

エンドポイントを定義する際に、注釈ベースおよびラムダベースのスタイルアプローチを使用する方法を示します。

2. Spring WebFluxとKotlin

Spring 5のリリースでは、リアクティブプログラミングのパラダイムのネイティブサポートとKotlinプログラミング言語を使用する可能性の2つの新しい大きな機能が導入されました。

このチュートリアル全体を通して、環境がすでに構成されており(この問題についてはone of our tutorialsに相談)、Kotlin言語の構文(トピックについてはanother tutorial)を理解していることを前提としています。

3. 注釈ベースのアプローチ

WebFluxを使用すると、@RequestMapping@PathVariableなどのSpringMVCフレームワークアノテーションまたは@RestController@GetMappingなどの便利なアノテーションを使用して、よく知られた方法で着信リクエストを処理するエンドポイントを定義できます。 s。

アノテーション名が同じであるにもかかわらず、WebFlux’sは、メソッドをnon-blockingにします。

たとえば、このエンドポイント:

@GetMapping(path = ["/numbers"],
  produces = [MediaType.APPLICATION_STREAM_JSON_VALUE])
@ResponseBody
fun getNumbers() = Flux.range(1, 100)

いくつかの最初の整数のストリームを生成します。 サーバーがlocalhost:8080で実行されている場合は、次のコマンドを使用してサーバーに接続します。

curl localhost:8080/stream

要求された番号を印刷します。

4. ラムダベースのアプローチ

エンドポイントを定義する新しいアプローチは、バージョン1.8以降のJavaに存在するラムダ式によるものです。 Kotlinを使用すると、以前のJavaバージョンでもラムダ式を使用できます。

WebFluxでは、ルーター関数は、RequestPredicate(つまり、誰がリクエストを管理する必要があるか)とHandlerFunction(つまり、リクエストをどのように作成するか)によって決定される関数です。

ハンドラー関数は、ServerRequestインスタンスを受け入れ、Mono<ServerResponse>インスタンスを生成します。

Kotlinでは、 if the last function argument is a lambda expression, it can be placed outside the parentheses

このような構文により、要求述語とハンドラー関数の間の分割を強調表示できます。

router {
    GET("/route") { _ -> ServerResponse.ok().body(fromObject(arrayOf(1, 2, 3))) }
}

ルーター機能用。

この関数は、人間が読むことのできる明確な形式を持っています。GETタイプのリクエストが/ routeに到着すると、HTTPステータスOKと、与えられたオブジェクト。

次に、WebFluxで機能させるために、ルーター関数をクラスに配置する必要があります。

@Configuration
class SimpleRoute {

    @Bean
    fun route() = router {
        GET("/route") { _ -> ServerResponse.ok().body(fromObject(arrayOf(1, 2, 3))) }
    }
}

多くの場合、アプリケーションのロジックでは、より洗練されたルーター機能を構築する必要があります。

WebFluxでは、Kotlinのルーター関数DSLは、acceptandornestinvokeGET、%などのさまざまな関数を定義します。 (t6)sとextension functionsを使用すると、複合ルーター関数を作成できます。

router {
    accept(TEXT_HTML).nest {
        (GET("/device/") or GET("/devices/")).invoke(handler::getAllDevices)
    }
}

handler変数は、標準のHandlerFunctionシグネチャを持つメソッドgetAllDevices()を実装するクラスのインスタンスである必要があります。

fun getAllDevices(request: ServerRequest): Mono

上で述べたように。

問題の適切な分離を維持するために、無関係なルーター機能の定義を別々のクラスに配置する場合があります。

@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)
        }
    }
    // eventual other router function definitions
}

String値のメソッドpathVariable()を使用して、パス変数にアクセスできます。

val id = request.pathVariable("id")

一方、ServerRequestの本体へのアクセスは、メソッドbodyToMonoおよびbodyToFluxを使用して実現されます。

val device: Mono = request
  .bodyToMono(Device::class.java)

5. テスト

ルーターの機能をテストするには、テストするルーターSimpleRoute().route()WebTestClientインスタンスを作成する必要があります。

var client = WebTestClient.bindToRouterFunction(SimpleRoute().route()).build()

これで、ルーターのハンドラー関数がステータスOKを返すかどうかをテストする準備が整いました。

client.get()
  .uri("/route")
  .exchange()
  .expectStatus()
  .isOk

WebTestClientインターフェイスは、サーバーを実行しなくても、GETPOSTPUTなどのすべてのHTTP要求メソッドをテストできるようにするメソッドを定義します。

応答本文のコンテンツをテストするために、json()メソッドを使用することをお勧めします。

client.get()
  .uri("/route")
  .exchange()
  .expectBody()
  .json("[1, 2, 3]")

6. 結論

この記事では、Kotlinを使用してWebFluxフレームワークの基本機能を使用する方法を示しました。

エンドポイントを定義する際によく知られている注釈ベースのアプローチを簡単に説明し、ラムダベースのスタイルのアプローチでルーター関数を使用してエンドポイントを定義する方法を説明するためにより多くの時間を費やしました。

すべてのコードスニペットは、リポジトリover on GitHubにあります。