Skip to content

使用 Spring Data CrudRepository 存取資料庫

這是 Getting started with Spring Boot and Kotlin 教學的最後一部分。在繼續之前,請確保您已完成先前的步驟:


First step 使用 Kotlin 建立 Spring Boot 專案
Second step 向 Spring Boot 專案新增資料類別
Third step 為 Spring Boot 專案新增資料庫支援
Fourth step 使用 Spring Data CrudRepository 存取資料庫

在此部分中,您將把服務層遷移為使用 Spring DataCrudRepository 來存取資料庫,而不是 JdbcTemplateCrudRepository 是一個 Spring Data 介面,用於對特定類型的儲存庫執行通用的 CRUD 操作。 它提供了多個開箱即用的方法,用於與資料庫互動。

更新您的應用程式

首先,您需要調整 Message 類別以配合 CrudRepository API:

  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 類別的使用更地道, 您可以將 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 類別。它現在將使用 MessageRepository,而不是執行 SQL 查詢:

    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 不為 nullCrudRepository 會假定物件已存在於資料庫中,並且這是一個 更新 操作,而不是 插入 操作。在插入操作之後,id 將由資料儲存區生成並分配回 Message 實例。這就是為什麼 id 屬性應該使用 var 關鍵字來宣告的原因。

  4. 更新 messages 資料表的定義,以便為插入的物件生成 ID。由於 id 是字串,您可以使用 RANDOM_UUID() 函數預設生成 ID 值:

    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()
}

執行應用程式

恭喜!應用程式已準備好再次執行。 在將 JdbcTemplate 替換為 CrudRepository 之後,功能保持不變,因此應用程式與之前一樣正常運作。

您現在可以從 requests.http 檔案中執行 POST 和 GET HTTP 請求並獲得相同的結果。

下一步

獲取您的個人語言地圖,以幫助您了解 Kotlin 功能並追蹤學習該語言的進度:

Get the Kotlin language map