使用 Spring Data CrudRepository 进行数据库访问
This is the final part of the Getting started with Spring Boot and Kotlin tutorial. Before proceeding, make sure you’ve completed previous steps:
Create a Spring Boot project with Kotlin
Add a data class to the Spring Boot project
Add database support for Spring Boot project
Use Spring Data CrudRepository for database access
In this part, you will migrate the service layer to use the Spring Data CrudRepository instead of JdbcTemplate for database access. CrudRepository is a Spring Data interface for generic CRUD operations on a repository of a specific type. It provides several methods out of the box for interacting with a database.
Update your application
First, you need to adjust the Message class for work with the CrudRepository API:
Add the
@Tableannotation to theMessageclass to declare mapping to a database table.
Add the@Idannotation before theidfield.These annotations also require additional imports.

import org.springframework.data.annotation.Idimport org.springframework.data.relational.core.mapping.Table@Table("MESSAGES")data class Message(@Id var id: String?, val text: String)
Besides adding the annotations, you also need to make the
idmutable (var) for the reasons of howCrudRepositoryworks when inserting the new objects to the database.Declare an interface for the
CrudRepositorythat will work with theMessagedata class:import org.springframework.data.repository.CrudRepositoryinterface MessageRepository : CrudRepository<Message, String>
Update the
MessageServiceclass. It will now call to theMessageRepositoryinstead of executing SQL queries:import java.util.*@Serviceclass MessageService(val db: MessageRepository) {fun findMessages(): List<Message> = db.findAll().toList()fun findMessageById(id: String): List<Message> = db.findById(id).toList()fun save(message: Message) {db.save(message)}fun <T : Any> Optional<out T>.toList(): List<T> =if (isPresent) listOf(get()) else emptyList()}
The return type of the
findById()function in theCrudRepositoryinterface is an instance of theOptionalclass. However, it would be convenient to return aListwith a single message for consistency. For that, you need to unwrap theOptionalvalue if it’s present, and return a list with the value. This can be implemented as an extension function to theOptionaltype.In the code,
Optional<out T>.toList(),.toList()is the extension function forOptional. Extension functions allow you to write additional functions to any classes, which is especially useful when you want to extend functionality of some library class.This function works with an assumption that the new object doesn’t have an id in the database. Hence, the id should be null for insertion.
If the id isn’t null,
CrudRepositoryassumes that the object already exists in the database and this is an update operation as opposed to an insert operation. After the insert operation, theidwill be generated by the data store and assigned back to theMessageinstance. This is why theidproperty should be declared using thevarkeyword.Update the messages table definition to generate the ids for the inserted objects. Since
idis a string, you can use theRANDOM_UUID()function to generate the id value by default:CREATE TABLE IF NOT EXISTS messages (id VARCHAR(60) DEFAULT RANDOM_UUID() PRIMARY KEY,text VARCHAR NOT NULL);
Update the name of the database in the
application.propertiesfile located in thesrc/main/resourcesfolder:spring.datasource.driver-class-name=org.h2.Driverspring.datasource.url=jdbc:h2:file:./data/testdb2spring.datasource.username=namespring.datasource.password=passwordspring.sql.init.schema-locations=classpath:schema.sqlspring.sql.init.mode=always
Here is the complete code for DemoApplication.kt:
package com.example.demoimport org.springframework.boot.autoconfigure.SpringBootApplicationimport org.springframework.boot.runApplicationimport org.springframework.data.annotation.Idimport org.springframework.data.relational.core.mapping.Tableimport org.springframework.data.repository.CrudRepositoryimport org.springframework.stereotype.Serviceimport org.springframework.web.bind.annotation.*import java.util.*@SpringBootApplicationclass DemoApplicationfun main(args: Array<String>) {runApplication<DemoApplication>(*args)}@RestControllerclass MessageController(val service: MessageService) {@GetMapping("/")fun index(): List<Message> = service.findMessages()@GetMapping("/{id}")fun index(@PathVariable id: String): List<Message> =service.findMessageById(id)@PostMapping("/")fun post(@RequestBody message: Message) {service.save(message)}}interface MessageRepository : CrudRepository<Message, String>@Table("MESSAGES")data class Message(@Id var id: String?, val text: String)@Serviceclass MessageService(val db: MessageRepository) {fun findMessages(): List<Message> = db.findAll().toList()fun findMessageById(id: String): List<Message> = db.findById(id).toList()fun save(message: Message) {db.save(message)}fun <T : Any> Optional<out T>.toList(): List<T> =if (isPresent) listOf(get()) else emptyList()}
Run the application
The application is ready to run again. By replacing the JdbcTemplate with CrudRepository, the functionality didn’t change hence the application should work the same way as previously.
Next step
Get your personal language map to help you navigate Kotlin features and track your progress in studying the language. We will also send you language tips and useful materials on using Kotlin with Spring.
You will need to share your email address on the next page to receive the materials.
