Spring Boot на Kotlin — первая программа
Spring Boot на Kotlin — первая программа
На JVM Spring Boot — популярный каркас для веб-сервисов, безопасности, работы с БД и облаком. Kotlin в Spring — полноценный язык — те же стартеры, что в Java, плюс data class, null-safety и короче контроллеры.
| Стек | Когда выбирать |
|---|---|
| Ktor | Kotlin-native, явные маршруты, лёгкий старт |
| Spring Boot + Kotlin | Команда на Spring, нужны Security, Data JPA, Spring Cloud |
Java-версия сценария: Первая программа на Spring Framework. Обзор Spring: Spring Framework.
Перед стартом: первая программа на Kotlin.
Словарь терминов
| Термин | Простыми словами |
|---|---|
| Spring | Контейнер, который создаёт объекты (бины) и связывает зависимости. |
| Spring Boot | Spring + автоконфигурация + встроенный Tomcat — быстрый старт. |
| Стартер | Готовый набор зависимостей (spring-boot-starter-web). |
@RestController | Класс с HTTP-методами, ответ — JSON. |
@Service | Слой бизнес-логики. |
| Dependency Injection | Spring передаёт HelloService в конструктор контроллера. |
Что получится
GET http://localhost:8080/api/hello?name=Анна → JSON {"message":"Привет, Анна!"}.
Проект (Gradle Kotlin DSL)
start.spring.io: Kotlin, Gradle, Spring Web, Java 17.
Код ITЗагрузка примера кода…
Разбор:
org.springframework.bootподключает задачи запуска и упаковки Spring-приложения.io.spring.dependency-managementвыравнивает версии зависимостей экосистемы Spring.kotlin("plugin.spring")автоматически открывает нужные классы для прокси/AOP.toolchainфиксирует Java 17 как стандарт сборки для всех разработчиков и CI.spring-boot-starter-webприносит MVC, Jackson и встроенный HTTP-сервер.
kotlin("plugin.spring") делает классы с аннотациями Spring открытыми для прокси — вручную писать open на каждый класс не нужно.
Точка входа
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)
}
| Элемент | Смысл |
|---|---|
@SpringBootApplication | Включить сканирование компонентов и автоконфигурацию. |
runApplication<DemoApplication>(*args) | Kotlin-обёртка над SpringApplication.run. |
*args | Распаковка массива аргументов в vararg. |
Модель и сервис
data class HelloResponse(val message: String)
@Service
class HelloService {
fun greet(name: String?): HelloResponse {
val who = name?.trim().takeUnless { it.isNullOrEmpty() } ?: "мир"
return HelloResponse("Привет, $who!")
}
}
Разбор greet:
name?.trim()— еслиname == null, всё выражениеnull.takeUnless { it.isNullOrEmpty() }— отбросить пустую строку после trim.?: "мир"— значение по умолчанию.data class— Jackson (JSON) сериализует полеmessageавтоматически.
Контроллер
@RestController
@RequestMapping("/api")
class HelloController(private val service: HelloService) {
@GetMapping("/hello")
fun hello(@RequestParam(required = false) name: String?): HelloResponse =
service.greet(name)
}
| Аннотация | Роль |
|---|---|
@RestController | Ответы методов → тело HTTP (JSON). |
@RequestMapping("/api") | Префикс для всех методов класса. |
@GetMapping("/hello") | Обработчик GET /api/hello. |
@RequestParam | Параметр из query: ?name=Анна. |
Конструктор HelloService | Constructor injection — рекомендуемый стиль Spring. |
Сравнение с Ktor: в Ktor — первая программа маршруты в блоке routing { get(...) }; в Spring — аннотации на методах.
Запуск и проверка
./gradlew bootRun
curl -s "http://localhost:8080/api/hello?name=Анна"
Разбор:
./gradlew bootRunзапускает сервис через Gradle Wrapper без ручной сборки артефакта.- Spring Boot по умолчанию поднимает HTTP-сервер на
localhost:8080. curl -sотправляет запрос и печатает только ответ, без лишнего служебного вывода.- Query-параметр
name=Аннапроверяет цепочку от контроллера до бизнес-метода.
В IDEA: Run DemoApplicationKt.
Структура проекта для роста
Даже на первом сервисе полезно сразу разделить код по слоям:
| Пакет | Содержимое |
|---|---|
controller | HTTP-эндпоинты и валидация входа |
service | бизнес-правила |
repository | доступ к БД и внешним системам |
dto | модели запросов и ответов |
config | настройки Spring, фильтры, бины |
Так проще вводить тесты, безопасность и мониторинг без крупного рефакторинга.
HTTP-ошибки и единый формат ответа
Добавьте обработчик исключений, чтобы клиент всегда получал понятный JSON:
data class ErrorResponse(val code: String, val message: String)
@RestControllerAdvice
class GlobalExceptionHandler {
@ExceptionHandler(IllegalArgumentException::class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
fun badRequest(e: IllegalArgumentException): ErrorResponse =
ErrorResponse(code = "BAD_REQUEST", message = e.message ?: "Некорректный запрос")
}
Разбор:
@RestControllerAdviceвключает глобальную обработку исключений для REST-контроллеров.@ExceptionHandler(...)связывает тип ошибки с конкретным обработчиком ответа.@ResponseStatus(HttpStatus.BAD_REQUEST)фиксирует HTTP-код 400 для таких случаев.ErrorResponseзадаёт единый JSON-формат ошибки для всех клиентов API.
Так API становится предсказуемым для frontend и мобильных клиентов.
Конфигурация через application.yml
server:
port: 8080
spring:
application:
name: kotlin-demo
Разбор:
server.portзадаёт порт, на котором слушает встроенный сервер Spring Boot.spring.application.nameопределяет имя сервиса в логах и инфраструктурных инструментах.- YAML-иерархия автоматически маппится на конфигурационные свойства Spring.
- Базовый файл удобно дополнять profile-настройками для dev и prod окружений.
Профили (application-dev.yml, application-prod.yml) помогают держать разные параметры для локальной разработки и продакшена.
Тест контроллера
Код ITЗагрузка примера кода…
Разбор:
@WebMvcTestподнимает только web-слой, поэтому тесты выполняются быстрее полного контекста.@MockBeanподменяет сервис и изолирует проверку поведения контроллера.mockMvc.get(...)имитирует HTTP-вызов без реального сетевого сокета.andExpectфиксирует API-контракт: ожидаемый статус и точное поле в JSON.
Тесты на уровне HTTP особенно полезны, если команда постепенно мигрирует с Java на Kotlin.
Kotlin и Java в одном проекте
- Java-классы вызываются из Kotlin без обёрток.
- Для JPA:
kotlin("plugin.jpa")илиallOpen/noArg. - Nullable Kotlin на границе с Java-кодом без аннотаций — риск NPE: проверяйте вход. Подробнее: Kotlin и Java — совместимость на практике.
Дополнительный сниппет — POST с телом запроса
data class CreateUserRequest(val name: String)
data class UserResponse(val id: Long, val name: String)
@RestController
@RequestMapping("/api/users")
class UserController {
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
fun create(@RequestBody req: CreateUserRequest): UserResponse {
return UserResponse(id = 1L, name = req.name.trim())
}
}
Разбор:
@PostMappingсвязывает метод с HTTP POST-запросом на/api/users.@RequestBodyпросит Spring десериализовать JSON-тело в Kotlindata class.@ResponseStatus(HttpStatus.CREATED)выставляет код201, корректный для создания ресурса.- Возврат
UserResponseавтоматически сериализуется в JSON через Jackson. - Разделение
RequestиResponseмоделей делает API-контракт явным и устойчивым к изменениям.
Частые ошибки
| Симптом | Причина |
|---|---|
Invalid bean definition | Класс final без plugin.spring |
| 404 | Неверный @RequestMapping или порт |
| Кракозябры в JSON | UTF-8: server.servlet.encoding.charset=UTF-8 в application.properties |
Что попробовать
spring-boot-starter-data-jpa— Java JPA.- Spring Security на том же проекте.
- Сравнить объём кода с Ktor на том же API.
Дальше
Kotlin ↔ Java · Ktor · корутины · о разделе
Базовый разбор HTTP и HTTPS находится в отдельной статье — HTTP как основа веб-интеграций.
В подборках
Статья входит в тематические подборки и блок "С чего начать?" на главной. Соседние шаги того же маршрута:
Первые шаги (маршрут подборки) — Compose Multiplatform — первая программа, Первая программа на Gin, Ktor — первая программа, Первая программа на Echo, Первая программа на Symfony, Первая программа на Fiber.