1. Обзор
Еще в январе в экосистеме Spring было сделано большое объявление: поддержка Kotlin появится в Spring Framework 5 . Это означает, что начиная с Spring Boot 2.x будет первоклассная поддержка Kotlin.
Это, конечно, не является неожиданностью, поскольку команда Pivotal известна тем, что поддерживает такие языки JVM, как Scala и Groovy.
Давайте теперь создадим приложение Kotlin, используя приложение Spring Boot 3.x!
2. Настройка
2.1. Среда
Kotlin поддерживает разработку в IntelliJ , Eclipse и в командной строке . Следуйте инструкциям, чтобы настроить среду в соответствии со своими предпочтениями.
2.2. Настройка
Сначала давайте создадим проект Spring Boot 2 и изменим POM, чтобы он содержал записи, указывающие версии Java и Kotlin с зависимостями:
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jre8</artifactId>
<version>1.2.71</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>1.2.71</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
<version>2.9.9</version>
</dependency>
Обратите внимание, что мы указываем расположение файлов для наших исходных и тестовых файлов Kotlin:
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
Если наши файлы Kotlin находятся в разных местах, вам нужно будет изменить эти записи в POM.
Чтобы скомпилировать модули и исходники Kotlin, нам нужно использовать kotlin-maven-plugin :
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>1.1.2</version>
<configuration>
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
<jvmTarget>1.8</jvmTarget>
</configuration>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
</plugin>
Хорошо, теперь у нас есть все необходимое для создания нашего приложения на Kotlin. Для справки вы можете найти последние версии Maven Central ( spring-boot-starter-web , kotlin-stdlib-jre8 , kotlin-reflect , jackson-module-kotlin , test ).
Далее давайте настроим контекст нашего приложения.
3. Контекст приложения
Давайте перейдем к коду Kotlin и напишем наш знакомый контекст приложения Spring Boot:
@SpringBootApplication
class KotlinDemoApplication
fun main(args: Array<String>) {
SpringApplication.run(KotlinDemoApplication::class.java, *args)
}
Мы видим нашу знакомую аннотацию @SpringBootApplication . Это та же аннотация, которую мы использовали бы в классе Java.
Ниже у нас есть определение класса для нашего класса KotlinDemoApplication . В Kotlin область действия классов по умолчанию является общедоступной, поэтому мы можем ее опустить. Кроме того, если в классе нет переменных и функций, его можно объявить без фигурных скобок. Итак, по сути, мы только что определили класс.
Переходим к методу. Это стандартный метод точки входа в Java: public static void main(String[] args).
Опять же, методы и функции по умолчанию являются общедоступными, поэтому нам не нужно объявлять это здесь. Кроме того, функциям, которые ничего не возвращают, не нужно указывать тип возврата void.
И, наконец, любая функция, определенная вне тела класса, автоматически становится статической . Это делает эту функцию пригодной для выполнения при запуске.
Теперь давайте запустим наше приложение из корневого каталога, используя mvn Spring-boot: run . Приложение должно запуститься, и мы увидим, что наше приложение работает на порту 8080.
Далее давайте создадим контроллер.
4. Контроллер
Давайте посмотрим на добавление контроллера в наш сервис:
@RestController
class HelloController {
@GetMapping("/hello")
fun helloKotlin(): String {
return "hello world"
}
}
Не слишком сильно отличается от стандартного контроллера Spring, но, конечно, меньше кода. Давайте добавим тестовый класс и кейс для этого контроллера, чтобы проверить нашу работу:
@RunWith(SpringRunner::class)
@SpringBootTest(classes = arrayOf(KotlinDemoApplication::class),
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class KotlinDemoApplicationTests {
@Autowired
lateinit var testRestTemplate: TestRestTemplate
@Test
fun whenCalled_shouldReturnHello() {
val result = testRestTemplate
// ...
.getForEntity("/hello", String::class.java)
assertNotNull(result)
assertEquals(result?.statusCode, HttpStatus.OK)
assertEquals(result?.body, "hello world")
}
}
Этот тест демонстрирует одну из очень мощных функций Kotlin — нулевую безопасность! Переменные Kotlin, которые могут иметь значение null, должны быть объявлены с использованием '?'. Тогда компилятор узнает, что перед доступом к этому свойству требуется защитное кодирование.
В нашем тесте TestRestTemplate определен как тип, допускающий значение NULL, и каждый раз, когда мы обращаемся к нему, мы делаем это с помощью оператора объединения NULL «?». – который вернет значение NULL, если вызываемый объект имеет значение NULL.
Это проясняет использование нулей в программе и заставляет разработчиков писать безопасный код при работе с ними.
Далее давайте добавим сервис и интегрируем его в наш контроллер.
5. Сервис
Как вы, наверное, уже догадались, наш сервис будет довольно легко добавить в наш проект. Давайте сделаем это сейчас:
@Service
class HelloService {
fun getHello(): String {
return "hello service"
}
}
Здесь довольно простой сервис с единственной функцией, возвращающей строку. Далее давайте подключим наш сервис к контроллеру и используем его для возврата значения:
@RestController
class HelloController(val helloService: HelloService) {
// ...
@GetMapping("/hello-service")
fun helloKotlinService(): String {
return helloService.getHello()
}
}
Ах, это выглядит красиво! В Котлине главный конструктор может быть определен в соответствии с объявлением класса. Мы опустили аннотацию @Autowired в нашем конструкторе, поскольку в течение некоторого времени она не является обязательной.
Эти параметры автоматически преобразуются в поля класса; в Котлине они называются свойствами. Не определены геттеры или сеттеры; они создаются автоматически. Конечно, вы можете переопределить эти значения по умолчанию, если хотите.
В Kotlin свойства классов и переменные функций можно определить с помощью var или val . Var указывает изменяемое свойство, а val указывает окончательное. Это позволяет компилятору проверять несанкционированный доступ. Поскольку наш HelloService является одноэлементным, мы подключаем его как val , чтобы предотвратить мутацию.
Далее добавим тест для этого метода контроллера:
@Test
fun whenCalled_shouldReturnHelloService() {
var result = testRestTemplate
// ...
.getForEntity("/hello-service", String::class.java)
assertNotNull(result)
assertEquals(result?.statusCode, HttpStatus.OK)
assertEquals(result?.body, "hello service")
}
Наконец, давайте посмотрим, как выглядит POJO в Котлине.
6. Класс данных Котлина
В Java мы представляем объекты данных с помощью старых простых объектов Java, POJO. В Котлине есть что-то, что позволяет более кратко выразить этот тип объекта — класс данных.
Давайте напишем объект данных, который будет возвращаться в наш контроллер:
data class HelloDto(val greeting: String)
Это не было уловкой. Я ничего не пропускаю из нашего урока. С модификатором данных мы получаем массу преимуществ. Это ключевое слово автоматически создает пару равенства/хеш-кода , функцию toString и функцию копирования. И все это из 53-символьной строки!
Теперь давайте добавим метод для возврата нашего нового класса данных:
// ...
@GetMapping("/hello-dto")
fun helloDto(): HelloDto {
return HelloDto("Hello from the dto")
}
Модификатор данных не добавляет конструктор по умолчанию, что важно для некоторых библиотек, таких как Jackson. Для поддержки этого типа класса мы добавили jackson-module-kotlin в наш POM-файл для поддержки маршалинга. Это было сделано во время раздела 2; вы можете увидеть зависимость там.
Наконец, давайте добавим тест для этой функции контроллера:
@Test
fun whenCalled_shoudlReturnJSON() {
val result = testRestTemplate
// ...
.getForEntity("/hello-dto", HelloDto::class.java)
assertNotNull(result)
assertEquals(result?.statusCode, HttpStatus.OK)
assertEquals(result?.body, HelloDto("Hello from the dto"))
}
7. Заключение
В этой статье мы рассмотрели поддержку Kotlin в Spring Boot 3.x. На примерах мы увидели, что Kotlin может упростить и улучшить наши приложения, заставляя нас писать более короткий и безопасный код.
Kotlin также поддерживает некоторые удивительные функции, такие как классы данных и расширения классов, и полностью совместим с существующим кодом Java. Это означает, что вы можете писать код Kotlin и вызывать его из своих классов Java, и наоборот. Кроме того, Kotlin был создан с нуля для обеспечения фантастической поддержки в IDE, и это действительно так.
Оригинал статьи: https://www.baeldung.com/kotlin/spring-boot-kotlin