Skip to content

Spring Data CrudRepositoryを使用したデータベースアクセス

これは、Spring BootとKotlin入門チュートリアルの最終パートです。先に進む前に、前のステップが完了していることを確認してください。


最初のステップ KotlinでSpring Bootプロジェクトを作成する
2番目のステップ Spring Bootプロジェクトにデータクラスを追加する
3番目のステップ Spring Bootプロジェクトにデータベースサポートを追加する
4番目のステップ Spring Data CrudRepositoryを使用したデータベースアクセス

このパートでは、データベースアクセスにJdbcTemplateの代わりにSpring DataCrudRepositoryを使用するようにサービス層を移行します。 _CrudRepository_は、特定の型のリポジトリに対する汎用的なCRUD操作のためのSpring Dataインターフェースです。 データベースとのやり取りに必要なメソッドがいくつか最初から提供されています。

アプリケーションを更新する

まず、CrudRepository APIを使用するためにMessageクラスを調整する必要があります。

  1. データベーステーブルへのマッピングを宣言するために、Messageクラスに@Tableアノテーションを追加します。 idフィールドの前に@Idアノテーションを追加します。

    これらのアノテーションには追加のインポートも必要です。

    kotlin
    // Message.kt
    package com.example.demo
    
    import org.springframework.data.annotation.Id
    import org.springframework.data.relational.core.mapping.Table
    
    @Table("MESSAGES")
    data class Message(@Id val id: String?, val text: String)

    さらに、Messageクラスの使用をよりKotlinらしい書き方にするために、 idプロパティのデフォルト値をnullに設定し、データクラスのプロパティの順序を入れ替えることができます。

    kotlin
    @Table("MESSAGES")
    data class Message(val text: String, @Id val id: String? = null)

    これで、Messageクラスの新しいインスタンスを作成する必要がある場合、textプロパティのみをパラメータとして指定できます。

    kotlin
    val message = Message("Hello") // id is null
  2. Messageデータクラスを操作するCrudRepositoryのインターフェースを宣言します。MessageRepository.ktファイルを作成し、以下のコードを追加します。

    kotlin
    // MessageRepository.kt
    package com.example.demo
    
    import org.springframework.data.repository.CrudRepository
    
    interface MessageRepository : CrudRepository<Message, String>
  3. MessageServiceクラスを更新します。これにより、SQLクエリを実行する代わりにMessageRepositoryを使用するようになります。

    kotlin
    // MessageService.kt
    package com.example.demo
    
    import org.springframework.data.repository.findByIdOrNull
    import org.springframework.stereotype.Service
    
    @Service
    class MessageService(private val db: MessageRepository) {
        fun findMessages(): List<Message> = db.findAll().toList()
    
        fun findMessageById(id: String): Message? = db.findByIdOrNull(id)
    
        fun save(message: Message): Message = db.save(message)
    }
    拡張関数

    findByIdOrNull()関数は、Spring Data JDBCにおけるCrudRepositoryインターフェースの拡張関数です。

    CrudRepository save()関数

    この関数は、新しいオブジェクトがデータベースにIDを持たないという前提で動作します。したがって、挿入の場合、IDはnullであるべきです。

    IDがnullでない場合、CrudRepositoryはオブジェクトがすでにデータベースに存在し、これは挿入操作ではなく更新操作であると仮定します。挿入操作後、idはデータストアによって生成され、Messageインスタンスに割り当てられます。これが、idプロパティがvarキーワードを使用して宣言されるべき理由です。

  4. 挿入されたオブジェクトのIDを生成するようにメッセージテーブルの定義を更新します。idは文字列であるため、デフォルトでID値を生成するためにRANDOM_UUID()関数を使用できます。

    sql
    -- schema.sql 
    CREATE TABLE IF NOT EXISTS messages (
        id      VARCHAR(60)  DEFAULT RANDOM_UUID() PRIMARY KEY,
        text    VARCHAR      NOT NULL
    );
  5. src/main/resourcesフォルダにあるapplication.propertiesファイルのデータベース名を更新します。

none
spring.application.name=demo
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:file:./data/testdb2
spring.datasource.username=name
spring.datasource.password=password
spring.sql.init.schema-locations=classpath:schema.sql
spring.sql.init.mode=always

以下に、アプリケーションの完全なコードを示します。

kotlin
// DemoApplication.kt
package com.example.demo

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class DemoApplication

fun main(args: Array<String>) {
    runApplication<DemoApplication>(*args)
}
kotlin
// Message.kt
package com.example.demo

import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table

@Table("MESSAGES")
data class Message(val text: String, @Id val id: String? = null)
kotlin
// MessageRepository.kt
package com.example.demo

import org.springframework.data.repository.CrudRepository

interface MessageRepository : CrudRepository<Message, String>
kotlin
// MessageService.kt
package com.example.demo

import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service

@Service
class MessageService(private val db: MessageRepository) {
    fun findMessages(): List<Message> = db.findAll().toList()

    fun findMessageById(id: String): Message? = db.findByIdOrNull(id)

    fun save(message: Message): Message = db.save(message)
}
kotlin
// MessageController.kt
package com.example.demo

import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import java.net.URI

@RestController
@RequestMapping("/")
class MessageController(private val service: MessageService) {
    @GetMapping
    fun listMessages() = ResponseEntity.ok(service.findMessages())

    @PostMapping
    fun post(@RequestBody message: Message): ResponseEntity<Message> {
        val savedMessage = service.save(message)
        return ResponseEntity.created(URI("/${savedMessage.id}")).body(savedMessage)
    }

    @GetMapping("/{id}")
    fun getMessage(@PathVariable id: String): ResponseEntity<Message> =
        service.findMessageById(id).toResponseEntity()

    private fun Message?.toResponseEntity(): ResponseEntity<Message> =
        // If the message is null (not found), set response code to 404
        this?.let { ResponseEntity.ok(it) } ?: ResponseEntity.notFound().build()
}

アプリケーションを実行する

おめでとうございます!アプリケーションを再度実行する準備ができました。 JdbcTemplateCrudRepositoryに置き換えても、機能は同じままで、アプリケーションは以前と同じように動作します。

これで、requests.httpファイルからPOSTおよびGET HTTPリクエストを実行して、同じ結果を得ることができます。

次のステップ

Kotlinの機能を知り、学習の進捗を追跡するのに役立つパーソナル言語マップを入手しましょう。

Kotlin言語マップを入手