メインコンテンツまでスキップ

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

備考

これは、Spring BootとKotlinを始めるチュートリアルの最終パートです。先に進む前に、以下の手順を完了していることを確認してください。


First stepKotlinでSpring Bootプロジェクトを作成する
Second stepSpring Bootプロジェクトにデータクラスを追加する
Third stepSpring Bootプロジェクトにデータベースサポートを追加する
Fourth stepデータベースアクセスにSpring Data CrudRepositoryを使用する

このパートでは、サービス層を移行して、データベースアクセスにJdbcTemplateの代わりにSpring DataCrudRepositoryを使用します。 CrudRepositoryは、特定の型のrepositoryに対する汎用的なCRUD操作のためのSpring Dataインターフェースです。 これは、データベースとやり取りするためのいくつかのメソッドをすぐに利用できます。

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

まず、CrudRepository APIで動作するようにMessageクラスを調整する必要があります。

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

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

    // Message.kt
    package 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クラスの使用をより慣用的にするために、 idプロパティのデフォルト値をnullに設定し、データクラスのプロパティの順序を逆にすることができます。

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

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

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

    // MessageRepository.kt
    package demo

    import org.springframework.data.repository.CrudRepository

    interface MessageRepository : CrudRepository<Message, String>
  3. MessageServiceクラスを更新します。SQLクエリの実行の代わりに、MessageRepositoryを使用するようになります。

    // MessageService.kt
    package 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)
    }

拡張関数(Extension functions)

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

CrudRepository save() 関数

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

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

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

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

    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

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

// DemoApplication.kt
package demo

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

@SpringBootApplication
class DemoApplication

fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}
// Message.kt
package 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)
// MessageRepository.kt
package demo

import org.springframework.data.repository.CrudRepository

interface MessageRepository : CrudRepository<Message, String>
// MessageService.kt
package 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)
}
// MessageController.kt
package 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に置き換えても機能は変わらないため、アプリケーションは以前と同じように動作するはずです。

次のステップ

Kotlinの機能をナビゲートし、言語の学習の進捗状況を追跡するのに役立つ、パーソナル言語マップを入手してください。

Get the Kotlin language map