1. 概要

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

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

2. SpringWebFluxとKotlin

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

このチュートリアル全体を通して、環境がすでに構成されており(この問題に関するチュートリアルの1つを参照)、Kotlin言語の構文を理解していることを前提としています(このトピックに関する別のチュートリアル)。

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

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

アノテーション名が同じであるにもかかわらず、 WebFluxののものは、メソッドをノンブロッキングにします。

たとえば、このエンドポイントは次のとおりです。

@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 インスタンスを生成し、 単核症 1。

Kotlinでは、最後の関数の引数がラムダ式の場合、括弧の外側に配置できます。

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

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は、 accept and または nest invoke[などのさまざまな関数を定義します。 X146X]、 GET POST 拡張機能を使用して、複合ルーター機能を構築できます。

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

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

fun getAllDevices(request: ServerRequest): Mono<ServerResponse>

上で述べたように。

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

@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<Device> = request
  .bodyToMono(Device::class.java)

5. テスト

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

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

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

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

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

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

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

6. 結論

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

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

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