Статьи Утилиты Telegram YouTube Отзывы

Spring Data JPA, REST и Kotlin: создание, обновление, удаление

Видеогайд Исходники

16 марта 2023

Тэги: json, Kotlin, PostgreSQL, rest, Spring Boot, Spring Data, SQL, YouTube, руководство.

Содержание

  1. Data Transfer Object
  2. Создание записи
  3. Обновление записи
  4. Удаление записи

В предыдущей статье Spring Data JPA, REST и Kotlin: поиск записей мы научились искать записи по id и по части названия страны. Теперь рассмотрим, как реализовать создание записи, её обновление и удаление. Нам потребуется добавить в наше REST API три новых метода.

Data Transfer Object

Методы создания и обновления будут принимать на вход ранее созданную нами DTO (data transfer object), в которой будут указаны все параметры страны. Однако при создании id страны нам неизвестно, поэтому нужно модифицировать DTO так, чтобы оно допускало null в качестве id:

data class CountryDto(
    val id: Int? = null,
    val name: String,
    val population: Int,
)

После этого перейдём в сервисный слой и добавим 3 новых метода в интерфейс CountryService:

fun create(dto: CountryDto): Int

fun update(id: Int, dto: CountryDto)

fun delete(id: Int)

Метод создания принимает на вход только dto и возвращает id новой записи, т.к. это id устанавливается на стороне базы данных. Метод обновления принимает и dto, и отдельно id страны. Наконец, методу удаления само dto не требуется. Ему нужно указать лишь id страны.

Создание записи

Теперь реализуем метод удаления в CountryServiceImpl:

@Transactional
override fun create(dto: CountryDto): Int {
    val countryEntity = countryRepository.save(dto.toEntity())
    return countryEntity.id
}

Аннотация @Transactional указывает на то, что все операции внутри метода будут выполняться в транзакции. Её следует использовать всегда, когда у вас несколько запросов к БД в одном методе. Далее мы преобразуем полученную DTO в сущность с помощью вспомогательного метода расширения CountryDto.toEntity(). После чего передаём объект в метод save(), который появился в нашем репозитории благодаря наследованию от стандартного CrudRepository.

В качестве результата метод save() возвращает экземпляр сущности, в котором уже будет проставлен актуальный id новой записи, назначенный базой.

Вспомогательный метод расширения, преобразующий dto в сущность, выглядит так:

private fun CountryDto.toEntity(): CountryEntity =
    CountryEntity(
        id = 0,
        name = this.name,
        population = this.population,
    )

Поскольку id нам неизвестно, но сущность не допускает null, поэтому в id указываем 0. Spring Data JPA таким образом поймёт, что это новая сущность.

Добавим в CountryController новый метод, который будет вызывать сервисный слой:

@PostMapping
fun create(@RequestBody dto: CountryDto): Int =
    countryService.create(dto)

Аннотация @PostMapping указывает на то, что данный запрос имеет тип POST. @RequestBody говорит о том, что dto будет передаваться в самом теле запроса в формате json.

Теперь мы можем запустить наш сервис и выполнить POST-запрос на создание новой записи:

curl -X POST http://127.0.0.1:8080/countries \
-H 'Content-Type: application/json' \
-d '{"name":"Япония","population":"123456"}'

Данная консольная команда должна быть записана в одну строку. Если вы разбиваете команду на несколько строк, то в конце каждой не забудьте добавить обратный слеш.

На практике для запросов изменения данных часто используют Postman.

POST-запрос на создание в Postman

В ответ нам приходит id новой записи.

Обновление записи

Перейдём к реализации метода обновления update().

@Transactional
override fun update(id: Int, dto: CountryDto) {
    var existingCountry = countryRepository.findByIdOrNull(id)
        ?: throw RuntimeException("Country not found")

    existingCountry.name = dto.name
    existingCountry.population = dto.population
    countryRepository.save(existingCountry)
}

Он также выполняется в транзакции. На вход поступает id существующей записи и новые значения полей в dto. Сначала мы подгружаем по id существующую запись с помощью стандартного метода findByIdOrNull(). Если запись не найдена, он вернёт null, и тогда мы кидаем исключение.

Затем в найденной записи меняем значения полей на новые, которые пришли к нам в dto. После чего вызываем тот же метод save(), что и при создании.

Обратите внимание, что мы не меняем id у существующей записи. Тогда Spring Data поймёт, что нужно обновить существующую запись. В ответ метод ничего не возвращает.

Добавим обработчик PUT-метода в CountryController:

@PutMapping("/{id}")
fun update(@PathVariable id: Int, @RequestBody dto: CountryDto) {
    countryService.update(id, dto)
}

@PathVariable связывает параметр метода id с частью урла, на который выполняется запрос. А новые значения полей самой сущности, как и в случае с созданием, передаются в dto.

PUT-запрос на обновление в Postman

Как видим, при обновлении в Postman нам ничего не приходит в ответ – значит, запрос выполнен успешно.

Удаление записи

Добавим реализацию метода удаления в сервисный слой. Он также выполняется в транзакции.

@Transactional
override fun delete(id: Int) {
    val existingCountry = countryRepository.findByIdOrNull(id)
        ?: throw RuntimeException("Country not found")
    countryRepository.deleteById(existingCountry.id)
}

В нём мы сначала пытаемся найти существующую запись. Как и в случае с обновлением, если запись не найдена, то кидаем исключение. Затем вызываем стандартный метод deleteById(), который появился в нашем репозитории благодаря наследованию от всё того же CrudRepository.

Наконец, добавим обработчик DELETE-метода в контроллер:

@DeleteMapping("/{id}")
fun delete(@PathVariable id: Int) {
    countryService.delete(id)
}

Как видите, у него единственный параметр id. Он является частью урла, на который выполняется запрос.

DELETE-запрос на удаление в Postman

В Postman в случае успешного удаления мы также ничего не возвращаем в ответе.

В следующей статье Spring Data JPA, REST и Kotlin: обработка ошибок мы научимся создавать собственные обработчики ошибок, а также изменим формат ответа при ошибке.


Облако тэгов

Kotlin, Java, Spring, Spring Boot, Spring Data, SQL, PostgreSQL, Oracle, Linux, Hibernate, Collections, Stream API, многопоточность, файлы, Nginx, Apache, maven, gradle, JUnit, YouTube, новости, руководство, ООП, алгоритмы, головоломки, rest, GraphQL, Excel, XML, json, yaml.

Последние статьи


Комментарии

Добавить комментарий

×

devmark.ru