Spec-Zone.ru › Kotlin 1.9

Добавление поддержки базы данных для проекта Spring Boot

В этой части учебника вы добавите и настроите базу данных в свой проект, используя JDBC. В JVM-приложениях вы используете JDBC для взаимодействия с базами данных. Для удобства Spring Framework предоставляет класс JdbcTemplate, который упрощает использование JDBC и помогает избежать распространённых ошибок.

Добавление поддержки базы данных

В приложениях на основе Spring Framework общепринятой практикой является реализация логики доступа к базе данных в так называемом слое сервиса — здесь находится бизнес-логика. В Spring вы должны пометить классы аннотацией @Service, чтобы указать, что класс принадлежит к слою сервиса приложения. В этом приложении вы создадите класс MessageService для этой цели.

В файле DemoApplication.kt создайте класс MessageService следующим образом:

import org.springframework.stereotype.Service
import org.springframework.jdbc.core.JdbcTemplate

@Service
class MessageService(val db: JdbcTemplate) {
    fun findMessages(): List<Message> = db.query("select * from messages") { response, _ ->
        Message(response.getString("id"), response.getString("text"))
    }

    fun save(message: Message){
        db.update("insert into messages values ( ?, ? )",
           message.id, message.text)
    }
}
Аргумент конструктора и инъекция зависимостей – (val db: JdbcTemplate)

Класс в Kotlin может иметь первичный конструктор и один или несколько вторичных конструкторов. Первичный конструктор является частью заголовка класса, и он следует за именем класса и необязательными параметрами типа. В нашем случае конструктор — (val db: JdbcTemplate).

Аргумент конструктора — val db: JdbcTemplate:

@Service
class MessageService(val db: JdbcTemplate)
Закрывающая лямбда и преобразование SAM

Функция findMessages() вызывает функцию query() класса JdbcTemplate. Функция query() принимает два аргумента: SQL-запрос в виде объекта String и обратный вызов, который будет отображать по одному объекту на строку:

db.query("...", RowMapper { ... } )


Интерфейс RowMapper объявляет только один метод, поэтому его можно реализовать с помощью лямбда-выражения, опуская имя интерфейса. Компилятор Kotlin знает, к какому интерфейсу нужно преобразовать лямбда-выражение, потому что вы используете его в качестве параметра для вызова функции. Это известно как преобразование SAM в Kotlin:

db.query("...", { ... } )


После преобразования SAM функция запроса получает два аргумента: строку на первом месте и лямбда-выражение на последнем. Согласно соглашению Kotlin, если последний параметр функции — функция, то лямбда-выражение, передаваемое в качестве соответствующего аргумента, может быть помещено за пределами скобок. Такая синтаксическая конструкция также известна как закрывающая лямбда:

db.query("...") { ... }
Подчеркивание для неиспользуемого аргумента лямбды

Для лямбды с несколькими параметрами вы можете использовать символ подчеркивания _ для замены имён параметров, которые вы не используете.

Таким образом, окончательный синтаксис для вызова функции запроса выглядит следующим образом:

db.query("select * from messages") { response, _ ->
Message(response.getString("id"), response.getString("text"))
}

Обновление класса MessageController

Обновите MessageController, чтобы использовать новый класс MessageService:

import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.PostMapping

@RestController
class MessageController(val service: MessageService) {
    @GetMapping("/")
    fun index(): List<Message> = service.findMessages()

    @PostMapping("/")
    fun post(@RequestBody message: Message) {
       service.save(message)
    }
}

@PostMapping аннотация

Метод, отвечающий за обработку запросов HTTP POST, должен быть помечен аннотацией @PostMapping. Чтобы иметь возможность преобразовать JSON, отправленный в качестве содержимого тела HTTP, в объект, вам нужно использовать аннотацию @RequestBody для аргумента метода. Благодаря наличию библиотеки Jackson в пути к классам приложения, преобразование происходит автоматически.

Обновление класса MessageService

Поле id для класса Message было объявлено как необязательная строка:

data class Message(val id: String?, val text: String)

Однако хранение значения null в базе данных как значение id будет неверным: вам нужно корректно обработать эту ситуацию.

Обновите код, чтобы генерировать новое значение, когда id является null при сохранении сообщений в базе данных:

import java.util.UUID

@Service
class MessageService(val db: JdbcTemplate) {
    fun findMessages(): List<Message> = db.query("select * from messages") { response, _ ->
        Message(response.getString("id"), response.getString("text"))
    }

    fun save(message: Message){
        val id = message.id ?: UUID.randomUUID().toString()
        db.update("insert into messages values ( ?, ? )",
                  id, message.text)
    } 
}
Оператор Elvis – ?:

Код message.id ?: UUID.randomUUID().toString() использует оператор Elvis (сокращение для проверки на null) ?:. Если выражение слева от ?: не является null, оператор Elvis возвращает его; в противном случае он возвращает выражение справа. Обратите внимание, что выражение справа оценивается только в том случае, если выражение слева является null.

Код приложения готов к работе с базой данных. Теперь необходимо настроить источник данных.

Настройка базы данных

Настройте базу данных в приложении:

  1. Создайте файл schema.sql в каталоге src/main/resources. Он будет хранить определения объектов базы данных:

    Create database schema
  2. Обновите файл src/main/resources/schema.sql следующим кодом:

    CREATE TABLE IF NOT EXISTS messages (
    id       VARCHAR(60)  PRIMARY KEY,
    text     VARCHAR      NOT NULL
    );
    

    Он создаёт таблицу messages с двумя столбцами: id и text. Структура таблицы соответствует структуре класса Message.

  3. Откройте файл application.properties, расположенный в папке src/main/resources, и добавьте следующие свойства приложения:

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

    Эти настройки позволяют базе данных работать с приложением Spring Boot.
    Полный список общих свойств приложения см. в документации Spring.

Добавление сообщений в базу данных через HTTP-запрос

Для работы с ранее созданными конечными точками вы должны использовать HTTP-клиент. В IntelliJ IDEA используйте встроенный HTTP-клиент:

  1. Запустите приложение. После запуска приложения вы можете выполнять запросы POST для хранения сообщений в базе данных. Создайте файл requests.http и добавьте следующие HTTP-запросы:

    ### Post "Hello!"
    POST http://localhost:8080/
    Content-Type: application/json
    
    {
      "text": "Hello!"
    }
    
    ### Post "Bonjour!"
    
    POST http://localhost:8080/
    Content-Type: application/json
    
    {
      "text": "Bonjour!"
    }
    
    ### Post "Privet!"
    
    POST http://localhost:8080/
    Content-Type: application/json
    
    {
      "text": "Privet!"
    }
    
    ### Get all the messages
    GET http://localhost:8080/
    
  2. Выполните все запросы POST. Используйте зелёную иконку Запуск в области слева от объявления запроса. Эти запросы записывают текстовые сообщения в базу данных:

    Execute POST request
  3. Выполните запрос GET и просмотрите результат в окне инструментов Запуск:

    Execute GET requests

Альтернативный способ выполнения запросов

Вы также можете использовать любой другой HTTP-клиент или утилиту командной строки cURL. Например, выполните следующие команды в терминале, чтобы получить тот же результат:

curl -X POST --location "http://localhost:8080" -H "Content-Type: application/json" -d "{ \"text\": \"Hello!\" }"

curl -X POST --location "http://localhost:8080" -H "Content-Type: application/json" -d "{ \"text\": \"Bonjour!\" }"

curl -X POST --location "http://localhost:8080" -H "Content-Type: application/json" -d "{ \"text\": \"Privet!\" }"

curl -X GET --location "http://localhost:8080"
END_OF_DOCUMENT_MARKER

Получение сообщений по идентификатору

Расширьте функциональность приложения для получения отдельных сообщений по идентификатору.

  1. В классе MessageService добавьте новую функцию findMessageById(id: String) для получения отдельных сообщений по идентификатору:

    import org.springframework.jdbc.core.query
    
    @Service
    class MessageService(val db: JdbcTemplate) {
    
        fun findMessages(): List<Message> = db.query("select * from messages") { response, _ ->
            Message(response.getString("id"), response.getString("text"))
        }
    
        fun findMessageById(id: String): List<Message> = db.query("select * from messages where id = ?", id) { response, _ ->
            Message(response.getString("id"), response.getString("text"))
        }
    
        fun save(message: Message) {
            val id = message.id ?: UUID.randomUUID().toString()
            db.update("insert into messages values ( ?, ? )", 
                      id, message.text)
        }
    }
    

    Функция query(), используемая для получения сообщения по его идентификатору, является расширяющей функцией Kotlin, предоставляемой Spring Framework, и требует дополнительного импорта, как показано в коде выше.

  2. Добавьте новую функцию index(...) с параметром id в класс MessageController:

    @RestController
    class 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)
        }
    }
    
    Получение значения из контекстного пути

    Сообщение id извлекается из контекстного пути с помощью Spring Framework, так как вы аннотировали новую функцию с помощью @GetMapping("/{id}"). Аннотируя аргумент функции с помощью @PathVariable, вы сообщаете фреймворку использовать полученное значение в качестве аргумента функции. Новая функция вызывает MessageService для получения отдельного сообщения по его идентификатору.

    Позиция аргумента vararg в списке параметров

    Функция query() принимает три аргумента:

    • Строка SQL-запроса, требующая параметра для выполнения

    • `id`, который является параметром типа String

    • RowMapper-экземпляр реализован с помощью лямбда-выражения

    Второй параметр функции query() объявлен как аргумент переменной длины (vararg). В Kotlin позиция параметра аргументов переменной длины не должна быть обязательно последней в списке параметров.

Запуск приложения

Приложение Spring готово к запуску:

  1. Запустите приложение снова.

  2. Откройте файл requests.http и добавьте новый GET-запрос:

    ### Get the message by its id
    GET http://localhost:8080/id
    
  3. Выполните GET-запрос для получения всех сообщений из базы данных.

  4. В окне инструментов Запуск скопируйте один из идентификаторов и добавьте его в запрос, как показано ниже:

    ### Get the message by its id
    GET http://localhost:8080/f16c1d2e-08dc-455c-abfe-68440229b84f
    

    Замените указанный выше идентификатор сообщения своим.

  5. Выполните GET-запрос и посмотрите результат в окне инструментов Запуск:

    Retrieve message by its id

Следующий шаг

На этом заключительном шаге вы узнаете, как использовать более распространённое подключение к базе данных с помощью Spring Data.

Перейти к следующей главе

Получить карту Kotlin языка

Получите свою личную карту языка Kotlin, чтобы помочь вам в навигации по функциям языка и отслеживании прогресса в изучении. Мы также вышлем вам советы по использованию языка и полезные материалы по использованию Kotlin с Spring.

Get the Kotlin language map

Для получения материалов вам необходимо будет указать адрес электронной почты на следующей странице.

Последнее изменение: 25 июля 2023 г.
Добавить класс данных в проект Spring Boot Использовать Spring Data CrudRepository для доступа к базе данных

© 2010–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/jvm-spring-boot-add-db-support.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API