跳至主要内容

使用 Spring Data CrudRepository 進行資料庫存取

資訊

這是 Spring Boot 與 Kotlin 入門教學的最後一部分。在繼續之前,請確保您已完成之前的步驟:


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

在本部分中,您將遷移服務層以使用 Spring DataCrudRepository (通用資料庫儲存庫) 而不是 JdbcTemplate 進行資料庫存取。 CrudRepository 是一個 Spring Data 介面,用於對特定類型的儲存庫執行通用 CRUD (建立、讀取、更新和刪除) 操作。 它提供了幾個現成的方法來與資料庫互動。

更新您的應用程式

首先,您需要調整 Message 類別以使用 CrudRepository API:

  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 類別。它現在將使用 MessageRepository 而不是執行 SQL 查詢:

    // 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 介面的 擴充函式

CrudRepository save() 函式

此函式運作時假設新物件在資料庫中沒有 id。因此,對於插入操作,id 應該為 null

如果 id 不是nullCrudRepository 會假定該物件已存在於資料庫中,並且這是一個更新操作,而不是插入操作。在插入操作之後,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()
}

執行應用程式

應用程式已準備好再次執行。 透過用 CrudRepository 替換 JdbcTemplate,功能沒有改變,因此應用程式應該以與先前相同的方式運作。

接下來是什麼

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

Get the Kotlin language map