1. 概要

このチュートリアルでは、KotlinとSpringBootを使用してリアクティブマイクロサービスアプリケーションを開発します。

このアプリケーションは、REST APIを公開し、データベースにデータを永続化し、監視用のエンドポイントを備えています。

2. 使用事例

最近、私たちの多くは健康問題に苦しんでいるため、チュートリアルには健康トラッカーアプリケーションを選択しました。 それは人々が彼らの健康プロファイルを作成し、熱、血圧などのような症状を保存することを可能にします。 後で、ユーザーは自分のヘルスログに関するレポートを見ることができます。

安全で健康を保ち、旅を続けましょう。

3. アプリケーションのセットアップ

まず、プロジェクトの依存関係を設定します。 ここではMavenを使用していますが、MavenとGradleの両方が適しています。

このアプリケーションは、spring-boot-starter-parentから継承します。

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.5.RELEASE</version>
    <relativePath/>
</parent>

次に、 pom.xml に基本的な依存関係を追加して、KotlinとJavaを操作できるようにします。

<dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-reflect</artifactId>
    <version>1.3.70</version>
</dependency>
<dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-stdlib-jdk8</artifactId>
    <version>1.3.70</version>
</dependency>

次に、RESTAPIと永続性の依存関係を追加する必要があります。

リアクティブRESTAPIにはSpringReactive Web を使用するため、spring-boot-starter-webfluxjackson-module-kotlin。の依存関係を追加します。

データの永続性のためにリアクティブオプションも利用できます。現時点では、Springマイルストーンリポジトリで利用可能なSpring Data R2DBCの実験バージョンがあります。 それを追加しましょう:

<repositories>
   ...
   <repository>
       <id>spring-milestone</id>
       <name>Spring Milestone Repository</name>
       <url>http://repo.spring.io/milestone</url>
   </repository>
</repositories>

また、spring-boot-bom-r2dbcdependencyManagementセクションにインポートしてから、spring-boot-starter-data-r2dbcを依存関係に追加します。

<dependencyManagement>
    <dependencies>
        ...
        <dependency>
            <groupId>org.springframework.boot.experimental</groupId>
            <artifactId>spring-boot-bom-r2dbc</artifactId>
            <version>0.1.0.M3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

次に、データベースを選択する必要があります。 このチュートリアルでは、インメモリデータベースとしてH2を使用していますが、現時点では、Postgres、MySQL、およびMicrosoft SQLServer用のR2DBCドライバーも利用できます。

ここで、r2dbc-h2依存関係を追加します。

<dependency>
    <groupId>io.r2dbc</groupId>
    <artifactId>r2dbc-h2</artifactId>
</dependency>

最後に、依存関係を終了するために、 spring-boot-starter-actuator を追加して、アプリケーションの監視および管理APIを提供します。

最後に、Applicationクラスを作成しましょう。

@SpringBootApplication
class HealthTrackerApplication

fun main(args: Array<String>) {
    runApplication<HealthTrackerApplication>(*args)
}

私たちは、 runApplication (* args) の短縮形です SpringApplication.run(HealthTrackerApplication :: class.java、* args)。

4. モデル

ユーザープロファイルデータをカプセル化するプロファイルデータクラスをモデル化してみましょう。

@Table 
data class Profile(@Id var id:Long?, var firstName : String, var lastName : String,
  var birthDate: LocalDateTime)

テーブル名なしで@Tableを使用すると、Springは命名規則に従ってクラス名からテーブル名を生成します。 @Idは主キーのマーカーです。

次に、プロファイルの健康症状をカプセル化するHealthRecordデータクラスがあります。

@Table
data class HealthRecord(@Id var id: Long?, var profileId: Long?, var temperature: Double,
  var bloodPressure: Double, var heartRate: Double, var date: LocalDate)

HealthRecordProfileクラスに依存していますが、残念ながら、エンティティの関連付けは現在Spring Data R2DBCでサポートされていないため、代わりにprofileIdを使用しました。 プロファイルインスタンスの。

5. データベース構成

現時点では、SpringDataR2DBCのスキーマ生成は利用できません。 したがって、プログラムで、またはスクリプトファイルを使用して自分で行う必要があります。

ここでは、コードを調べて、DDLを実行するための構成クラスを作成しましょう。

@Configuration
class DBConfiguration(db: DatabaseClient) {
    init {
        val initDb = db.execute {
            """ CREATE TABLE IF NOT EXISTS profile (
                    id SERIAL PRIMARY KEY,
                    //other columns specifications
                );
                CREATE TABLE IF NOT EXISTS health_record(
                    id SERIAL PRIMARY KEY,
                    profile_id LONG NOT NULL,
                    //other columns specifications
                );
            """
        }
        initDb.then().subscribe()
    }
}

これで、永続性を設定する準備が整いました。

6. リポジトリ

このステップでは、必要なリポジトリインターフェースを作成します。 ProfileRepositoryインターフェースをReactiveCrudRepositoryから拡張してみましょう。

@Repository
interface ProfileRepository: ReactiveCrudRepository<Profile, Long>

ReactionCrudRepository は、savefindByIdなどのメソッドを提供します。

次に、プロファイルのヘルスレコードのリストを返す追加のメソッドを備えたHealthRecordRepositoryがあります。

繰り返しになりますが、現時点では、Spring Data R2DBCではクエリの派生はサポートされていないため、クエリを手動で作成する必要があります。

@Repository
interface HealthRecordRepository: ReactiveCrudRepository<HealthRecord, Long> {
    @Query("select p.* from health_record p where p.profile_id = :profileId ")
    fun findByProfileId(profileId: Long): Flux<HealthRecord>
}

7. コントローラー

次に、新しいプロファイルを登録するためにRESTAPIを公開する必要があります。 また、ヘルスレコードを保存および取得するためのエンドポイントも必要です。 簡単にするために、エンティティをデータ転送オブジェクトとして再利用します。

プロファイル登録用のAPIを公開するProfileControllerから始めましょう。 ProfileControllerのコンストラクターを介してProfileRepositoryのインスタンスを挿入します。

@RestController
class ProfileController(val repository: ProfileRepository) {
    
    @PostMapping("/profile")
    fun save(@RequestBody profile: Profile): Mono<Profile> = repository.save(profile)
}

次に、ヘルスレコードのエンドポイントを調べます。1つはデータを保存し、もう1つは平均を返します。

さらに、プロファイルの平均健康記録をカプセル化するAverageHealthStatusデータクラスを作成しましょう。

class AverageHealthStatus(var cnt: Int, var temperature: Double, 
  var bloodPressure: Double, var heartRate: Double)

そして、これがHealthRecordControllerです。

@RestController
class HealthRecordController(val repository: HealthRecordRepository) {

    @PostMapping("/health/{profileId}/record")
    fun storeHealthRecord(@PathVariable("profileId") profileId: Long, @RequestBody record: HealthRecord):
      Mono<HealthRecord> =
        repository.save(record)

    @GetMapping("/health/{profileId}/avg")
    fun fetchHealthRecordAverage(@PathVariable("profileId") profileId: Long): Mono<AverageHealthStatus> =
        repository.findByProfileId(profileId)
            .reduce( /* logic to calculate total */)
            .map { s ->
                /* logic to calculate average from count and total */
            }

}

8. エンドポイントの監視

Spring Boot Actuator は、アプリケーションを監視および管理するためのエンドポイントを公開します。 spring-boot-starter-actuator を依存関係に追加すると、デフォルトで /healthおよび/infoエンドポイントが有効になります。 application.ymlmanagement.endpoints.web.exposure.includeプロパティの値を設定することで、より多くのエンドポイントを有効にできます。

アプリケーションで/health/metricsを有効にしましょう:

management.endpoints.web.exposure.include: health,metrics

値を*に設定することで、すべてのエンドポイントを有効にすることもできます。 すべてのエンドポイントを公開するとセキュリティリスクが発生する可能性があるため、追加のセキュリティ構成が必要になることに注意してください。

/ actuator を呼び出すと、有効になっているすべてのアクチュエータエンドポイントのリストを確認できます。

アプリケーションのヘルスステータスを確認するには、 http:// localhost:8080 / actuator/health。 応答は次のようになります。

{
    "status": "UP"
}

これは、アプリケーションが正しく実行されていることを意味します。

9. テスト

WebTestClientを使用してエンドポイントをテストできます。 実用的なサンプルとして、プロファイルAPIをテストしてみましょう。

まず、 ProfileControllerTest クラスを作成し、@SpringBootTestで注釈を付けます。

@SpringBootTest
class ProfileControllerTest {}

クラスに@SpringBootTestの注釈が付けられている場合、 Springはクラスパッケージを検索し、それ以上に注釈の付いたクラスを検索します。 @SpringBootConfiguration。

次に、 WebTestClient のインスタンスを作成し、それに ProfileController にバインドしてみましょう。

@Autowired
lateinit var controller: ProfileController

@BeforeEach
fun setup() {
    client = WebTestClient.bindToController(controller).build()
}

これで、 /profileエンドポイントをテストする準備が整いました。

@Test
fun whenRequestProfile_thenStatusShouldBeOk() {
    client.post()
      .uri("/profile")
      .contentType(MediaType.APPLICATION_JSON)
      .bodyValue(profile)
      .exchange()
      .expectStatus().isOk
}

10. 結論

KotlinとSpringBootを使用してマイクロサービスアプリケーションを作成するための旅は終わりました。 その過程で、REST APIを公開し、エンドポイントを監視し、永続性を管理する方法を学びました。

セキュリティ、サービス呼び出し、APIゲートウェイなどの高度なトピックは別の日になります。

いつものように、このチュートリアルのコードはGitHubから入手できます。