С момента своего самого раннего выпуска Java рекламировала себя как язык программирования ” пиши один раз, запускай везде “. Идея заключалась в том, что программист мог разработать приложение на Java, скомпилировать его до байт-кода и превратить в исполняемый файл, который может запускаться на любой платформе, независимо от операционной системы или платформы. Частично это удалось сделать с помощью среды выполнения, известной как виртуальная машина Java, или JVM .
К чести Java, JVM была (и остается!) невероятно точно настроенная среда выполнения, которая абстрагировалась от базового оборудования компьютера. Хотя Java как язык программирования существует и по сей день, его часто рассматривают как громоздкий, громоздкий и представляющий устаревший подход к внедрению решений.
За последние 10 лет появилось все больше и больше языков, работающих на JVM, но они выглядят и ощущаются совсем не так, как Java. Одним из таких языков является Kotlin . Из-за JVM он не имеет реальных преимуществ в производительности по сравнению с обычной Java. Тем не менее, его сила заключается в том факте, что он уделяет приоритетное внимание удобочитаемости так, как этого не делает Java. Рассмотрим, например, печать подстроки в Java:
// Java String input = "What is the answer to the Ultimate Question of Life, the Universe, and Everything? 42"; String answer = input.substring(input.indexOf("?") + 1); System.out.println(answer);
Сначала вы должны получить индекс символа, который вы хотите поместить в подстроку, добавить единицу (поскольку строки индексируются с нулевым индексом) и вызвать System.out.println
для записи в stdout.
В Котлине это намного короче:
// Kotlin val input = "What is the answer to the Ultimate Question of Life, the Universe, and Everything? 42" val answer = input.substringAfter("?") println(answer)
Котлин вызвал такой большой интерес, что Google даже рекомендует его вместо Java для разработки приложений для Android .
В этом посте мы кратко рассмотрим, как разработать приложение в Kotlin. Мы создадим простой API с базой данных PostgreSQL и развернем его в Heroku, чтобы увидеть его вживую.
Предпосылки
Прежде чем мы начнем, вам нужно убедиться, что на вашем компьютере установлено следующее программное обеспечение:
- Учетная запись на Heroku . Это абсолютно бесплатно и не требует никакой платежной информации.
- Интерфейс Heroku/| . Как только ваше приложение будет размещено на Heroku, это значительно упростит управление им. Вам нужно будет установить
- Kotlin .4). Вам также понадобится
- Gradle installed.0).
Вам также нужно будет немного ознакомиться с Git и установить его на свой компьютер.
Мы собираемся использовать IntelliJ IDEA для этого приложения Kotlin. Их документация содержит некоторые рекомендации о том, как создать новый проект. Убедитесь, что вы выбрали следующие параметры:
- Мы хотим создать приложение Kotlin, которое использует Gradle в качестве системы сборки
- Установите имя проекта на kotlin-api
- Установите версию JDK равной 16. Если у вас не установлена эта версия, вы можете выбрать Загрузить JDK … из выпадающего списка, затем выберите Oracle OpenJDK версия 16
После того, как IDE все настроит, у вас должна быть структура каталогов, которая выглядит примерно так:
kotlin-api ├── build.gradle.kts └── src ├── main │ ├── kotlin
Наши файлы Kotlin будут храниться в src/main/kotlin
, а наша логика сборки будет находиться в build.gradle.kts .
Приступая к работе
Gradle – это инструмент сборки для различных языков. Он также действует как инструмент управления зависимостями, аналогичный Maven. У вас уже будет несколько строк в вашем файле build.gradle.kts , которые IDE автоматически добавила, чтобы быть полезными. Вы можете удалить все это и вставить вместо этого эти строки:
plugins { id("java") id("org.jetbrains.kotlin.jvm") version "1.5.10" id("org.springframework.boot") version "2.4.3" id("io.spring.dependency-management") version "1.0.11.RELEASE" } group "com.example" version "0.0.1" repositories { mavenCentral() } dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter") developmentOnly("org.springframework.boot:spring-boot-devtools") }
В этих строках указаны зависимости вашего проекта и где их найти. Например, мы хотим использовать [org.springframework.boot](https://plugins.gradle.org/plugin/org.springframework.boot )
в версии 2.4.3, поэтому он определен в блоке plugins
. Мы указываем репозитории, в которых можно найти пакеты — по адресу MavenCentral()
— и какие открытые классы мы хотим использовать ( реализация ( "org.springframework.boot:spring-boot-starter-web")
).
Давайте создадим два небольших файла для тестирования нашей настройки. Создайте файл с именем Application.kt
в папке src/main/kotlin и вставьте в него следующее:
package com.example import org.springframework.boot.SpringApplication import org.springframework.boot.autoconfigure.SpringBootApplication @SpringBootApplication open class Application fun main(args: Array) { SpringApplication.run(Application::class.java, *args) }
Это запускает приложение по умолчанию, использующее Spring framework. Настоящая магия происходит в следующем файле, Controller.kt
, который вы должны создать вместе с Application.kt
in src/main/kotlin :
package com.example import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RestController @RestController class GreetingController { @GetMapping("/{name}") fun get(@PathVariable name: String) = "Hello, $name" }
Здесь мы определяем маршрут ( @GetMapping("/{name}")
), где {name}
является динамическим значением. Помещая этот декоратор поверх метода Kotlin ( fun get
или “функция с именем get”), мы можем сопоставить маршрут с любым желаемым поведением — в данном случае возвращая приветствие с именем пути для запроса GET
.
Для того, чтобы IDEA знала, как запустить наше приложение, нам нужно создать конфигурацию запуска . В верхней части меню IDE нажмите кнопку с надписью Добавить конфигурацию… . Выберите Добавьте новую конфигурацию запуска , затем выберите Gradle из списка. Для имени проекта Gradle введите kotlin-api. В поле Задачи введите Запуск загрузки
. boot Run – это задача Gradle, предоставляемая Spring framework, которая скомпилирует наш код и запустит сервер. Нажмите Ok ; теперь у вас должна быть зеленая кнопка воспроизведения в строке меню IDE. Когда вы нажмете на это, IDE выполнит gradle bootRun
для создания этого приложения Kotlin и запуска сервера. Когда это закончится, перейдите к http:
//localhost:8080/world . Вы должны увидеть приятное приветствие.
Взаимодействие с базой данных
Теперь давайте перейдем к (несколько) серьезным вещам. Предположим, мы хотим присоединить базу данных к этому проекту. В мире Maven/Java нам нужно было бы обновить XML-файл и добавить ссылку на JAR-файл. В Gradle мы можем обойтись простым добавлением нескольких строк в наш файл build.gradle.kts
:
dependencies { # ... implementation("com.zaxxer:HikariCP:4.0.3") runtimeOnly("org.postgresql:postgresql") # ... }
Здесь мы включили HikariCP в нашем проекте, который является популярным драйвером подключения к базе данных. Мы также указываем, что хотим “загрузить” библиотеку org.postgresql
во время выполнения. Всего этими двумя строками мы сообщили нашей конфигурации, что хотим взаимодействовать с базой данных PostgreSQL. Если у вас уже есть локальная база данных PostgreSQL, это здорово. Вы сможете продолжить остальную часть этого руководства локально и увидеть результаты при просмотре localhost. Если у вас нет PostgreSQL, не волнуйтесь — мы покажем вам, как легко развернуть это приложение на Heroku, которое позаботится об инфраструктуре за вас.
Возвращайтесь к Возвращайтесь к
package com.example import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RestController import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.http.MediaType import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import java.net.URI import javax.sql.DataSource @RestController class GreetingController { val dataSource = dataSource() val connection = dataSource.connection @GetMapping("/{name}") fun get(@PathVariable name: String) = "Hello, $name" @PostMapping(value = ["/add-name"], consumes = [MediaType.TEXT_PLAIN_VALUE]) fun post(@RequestBody requestBody: String) : String { initDb() val stmt = connection.createStatement() stmt.executeUpdate("INSERT INTO names values('$requestBody')") return "Added $requestBody" } @GetMapping("/everyone") fun getAll() : String { initDb() val stmt = connection.createStatement() val rs = stmt.executeQuery("SELECT name FROM names") val output = ArrayList() while (rs.next()) { output.add(rs.getString("name")) } val names = output.joinToString(", ") return "Here are the names: $names" } internal fun initDb() { val stmt = connection.createStatement() stmt.executeUpdate("CREATE TABLE IF NOT EXISTS names (name text)") } internal fun dataSource(): HikariDataSource { val config = HikariConfig() var dbUri = URI(System.getenv("DATABASE_URL") ?: "postgresql://localhost:5432/") var dbUserInfo = dbUri.getUserInfo() var username: String?; var password: String?; if (dbUserInfo != null) { username = dbUserInfo.split(":").get(0) password = dbUserInfo.split(":").get(1) } else { username = System.getenv("DATABASE_USERNAME") ?: null password = System.getenv("DATABASE_PASSWORD") ?: null } if (username != null) { config.setUsername(username) } if (password != null) { config.setPassword(password) } val dbUrl = "jdbc:postgresql://${dbUri.getHost()}:${dbUri.getPort()}${dbUri.getPath()}" config.setJdbcUrl(dbUrl) return HikariDataSource(config) } }
Здесь довольно много всего происходит! Давайте начнем с самого низа. Мы определяем функцию с именем DataSource
, которая обеспечивает подключение к нашей базе данных. Поскольку мы создаем 12-факторное приложение , наши учетные данные базы данных хранятся в переменной среды с именем DATABASE_URL
. Мы извлекаем этот URL-адрес и извлекаем из него имя пользователя и пароль, если таковые существуют. Если нет, мы проверяем еще две переменные среды на наличие этой информации — DATABASE_USERNAME
и DATABASE_PASSWORD
. Затем мы объединяем всю эту информацию в формат, необходимый соединителю базы данных. Функция initDb
создает таблицу с именем names
с одним текстовым столбцом с именем name
. /каждый
конечная точка имеет @GetMapping
декоратор, как и раньше. Это определяет GET/everyone
маршрут, который получает все имена из базы данных.
Наконец, мы добавили кое-что довольно новое: декоратор @PostMapping
. Здесь нам нужно определить, какие типы контента это POST
маршрут может быть принят. В этом случае он использует
тип носителя TEXT_PLAIN_VALUE
(другими словами, "Content-Type: text/plain"
). Любая строка информации, которую мы поместим в тело запроса, будет добавлена в базу данных. Всего за несколько строк мы создали небольшой API, который мы можем добавлять и запрашивать.
Если вы запустите этот сервер сейчас — и если у вас локально запущен PostgreSQL, — вы сможете взаимодействовать с ним. Попробуйте сделать следующий запрос:
$ curl -H "Content-Type: text/plain" -X POST http://localhost:8080/add-name -d 'Frank'
Если вы перейдете к http://localhost:8080/все
, вы увидите, что Фрэнк
был включен.
Развертывание в Heroku
Пришло время увидеть, насколько легко запустить Kotlin на Heroku. Во-первых, нам нужно создать файл, специфичный для Heroku: файл Proc . Этот текстовый файл определяет, как наше приложение должно загружаться и запускаться.
Создайте файл с именем Procfile в каталоге корневого уровня, прямо рядом с вашим файлом build.gradle.kts . Скопируйте и вставьте в него следующие строки:
web: java -jar build/libs/kotlin-api.jar --server.port=$PORT
Здесь мы говорим, что хотим, чтобы Heroku запускал java -jar build/libs/kotlin-api.jar
. Этот JAR упаковывается и создается в процессе развертывания; Heroku автоматически создаст его для нас, потому что он знает, как выполнить задачу Gradle для этого. Мы также привязываем переменную окружения $PORT
, чтобы Heroku знал, какой порт прослушивает сервер.
Затем выполните следующие команды Git:
$ git init $ git add . $ git commit -m "Preparing my first Kotlin app"
Поскольку у нас установлен интерфейс Heroku CLI, мы можем вызвать heroku create в командной строке для создания приложения :
$ heroku create Creating app... done, ⬢ desolate-plains-67007 Created http://desolate-plains-67007.herokuapp.com/ | git@heroku.com:desolate-plains-67007.git
Вашему приложению будет присвоено случайное имя — в этом примере это desolate-plains-67007
— а также общедоступный URL-адрес.
Чтобы предоставить базу данных, мы используем команду heroku addons . Вызов его без аргументов даст нам знать, существуют ли таковые:
$ heroku addons No add-ons for app desolate-plains-67007.
Для нашего приложения не существует никаких дополнений, что имеет смысл – мы только что создали его! Чтобы добавить базу данных PostgreSQL, мы можем использовать команду addons:create
следующим образом:
$ heroku addons:create heroku-postgresql:hobby-dev
Heroku предлагает несколько уровней баз данных PostgreSQL. hobby-dev
– это бесплатный уровень, так что мы можем поиграть с этим, не заплатив ни копейки.
Ваш код готов, ваше приложение Heroku настроено — вы готовы к развертыванию. Это самая легкая часть! Просто введите следующую команду:
$ git push heroku master
Ваш код будет отправлен в Heroku. С этого момента Хероку возьмет верх. Вы увидите, как ваши журналы сборки прокручиваются в вашем терминале. Это покажет вам, что Heroku устанавливает от вашего имени и где вы находитесь в процессе сборки. После его завершения вы можете перейти по своему специальному URL-адресу в браузере (в данном случае https://desolate-plains-67007.herokuapp.com
) и взаимодействовать с API в Интернете!
Узнавать больше
Производительный дизайн Kotlin и разборчивый синтаксис в сочетании с простотой Gradle делают его идеальным для предприятий, которым необходимо полагаться на проверенные в боях пакеты Java. Благодаря своей совместимости с Java Kotlin идеально подходит в качестве переходного языка; огромные объемы кода Java могут быть преобразованы в Kotlin, сохраняя при этом функциональное приложение. Развертывание в Heroku проходит гладко, и я даже не воспользовался различными способами тонкой настройки приложений на основе Java и JVM для развертывания .
Оригинал: “https://dev.to/heroku/deploying-a-kotlin-app-to-heroku-5d0g”