Как упростить создание сайтов с помощью фреймворка Javalin: разбираем на примере

Зачем использовать простой фреймворк Javalin на языке Java для обработки запросов и формирования ответов, и как работает шаблонизация.
Статью подготовил Сергей Чепурнов, наставник на Хекслете, Java-разработчик с опытом работы более 7 лет в распределенных командах. Профиль Сергея на GitHub
Содержание
- Как устроены веб-приложения
- Как работает маршрутизация в Javalin
- Как работают динамически сформированные запросы
- Какими бывают запросы: GET, DELETE, POST, PUT
- Как работает шаблонизация
- Дополнительные материалы
Как устроены веб-приложения
Все веб-приложения работают по одному принципу. Во-первых, они состоят из двух частей:
- Клиент — зачастую это браузер или приложение на устройстве пользователя
- Сервер — компьютер с серверным ПО, который обрабатывает запросы от клиента.
Во-вторых, в каждом приложении клиент и сервер обмениваются информацией таким образом:
- Клиент отправляет запрос к серверу
- Сервер обрабатывает запрос
- Сервер отправляет сформированный ответ обратно клиенту.
Такая последовательность из трех шагов называется циклом «запрос-обработка-ответ». На схеме она выглядит так:
Обработка запросов и формирование ответов — это рутинная задача в каждом веб-приложении.
При программировании на языке Java есть два способа работы с циклом «запрос-обработка-ответ»:
- Использование Servlet API — это стандартный пакет классов и интерфейсов, то есть встроенный механизм построения клиент-серверного приложения по схеме «запрос-ответ». Главный минус — придется писать много однотипного кода, создавать множество классов и т. п.
- Использование фреймворка для автоматизации повторяющихся задач. Фреймворк — это каркас веб-приложения, определяющий структуру программы. Код веб-приложения в таком случае легче читается, поддерживается и тестируется. Благодаря фреймворкам вы можете сосредоточиться на логике сайта, не отвлекаясь на продумывание базовой архитектуры или кодирование вспомогательных инструментов.
Рассмотрим фреймворк Javalin: он настолько прост, что работающее веб-приложение можно написать буквально в две строчки кода:
Конечно, это еще не все. Также для запуска нужна система сборки — она скачает все указанные зависимости, скомпилирует исходный код и запустит приложение.
Для примера мы будем использовать систему сборки Gradle. В этом случае запуск приложения выполняется командой run
в корне директории проекта:
Откроем в браузере страницу с адресом localhost
и посмотрим, запустилось ли наше двухстрочное приложение.Все прошло успешно:
Запрос /
и ответ Hello World
связаны между собой. Клиент делает запрос по адресу localhost
Hello World
.
Чтобы разобраться подробнее, вернемся к двум строкам выше. Посмотрим, что в них написано:
Первая строка создает объект типа Javalin и устанавливает номер порта, на котором будет работать приложение (порт 7070 в данном случае). Вторая строка добавляет обработчик для запроса /
. Обработчик записывается в виде лямбда-выражения и формирует ответ в виде строки.
Клиент получает ответ от сервера в виде http-ответа, в теле которого содержится строка:
Как работает маршрутизация в Javalin
Поступающие запросы нужно маршрутизировать — то есть обработать на сервере. Когда сервер получает запрос от клиента, он начинает маршрутизацию: обрабатывает запрос и определяет, какой ответ нужно отправить клиенту.
Как это происходит:
- Сервер считывает /about в конце URL и отличает этот запрос от всех остальных
- Затем сервер формирует подходящий ответ — отправляет html-страницу «О блоге».
Рассмотрим пример. Создадим веб-приложение в виде блога: https://java-javalin-blog.hexlet.app. Пользователь переходит по ссылкам внутри блога и получает разную информацию. Например, на https://java-javalin-blog.hexlet.app/articles — увидит список всех статей, а на странице https://java-javalin-blog.hexlet.app/about — узнает больше о блоге и авторах.
Посмотрим, как маршрутизация работает в приложении:
Обратите внимание, что каждому URL соответствует определенный ответ — именно он возвращается в виде html-страницы. Таким образом, пользователь увидит в браузере такую страницу:
Как работают динамически сформированные запросы
До этого мы рассматривали статические адреса такого вида:
Кроме статических адресов, в веб-приложениях используются и динамически сформированные адреса. Например:
- https://java-javalin-blog.hexlet.app/articles/1
- https://java-javalin-blog.hexlet.app/articles/2
- https://java-javalin-blog.hexlet.app/articles/3
Такие URL запрашивают статьи по их уникальному идентификатору (id). По id сервер различает запросы и возвращает соответствующую статью в виде html-страницы.
Если на сайте есть список статей, то его можно выводить на странице в виде списка названий, а ссылки формировать динамически и с разными идентификаторами. Обычно шаблон ссылки выглядит следующим образом: “/articles/{id}”, где вместо "{id}” программным путем подставляется конкретный идентификатор статьи.
Чтобы обрабатывать такие запросы, на сервере создается отдельный класс контроллер, который отвечает за обработку запроса и формирование ответа клиенту.
Рассмотрим, как выглядит обработка запроса https://java-javalin-blog.hexlet.app/articles/1 в коде приложения.
Во-первых, в маршрутизации появляется отсылка к методу контроллера:
Эта настройка маршрутизации сообщает о двух важных аспектах:
- GET-запрос по адресу
/articles
попадает на обработчикArticleController.listArticles
. - GET-запрос по адресу
articles/{id}
с любым целочисленным параметромid
попадает на обработчикArticleController.showArticle
Во-вторых, обработчик запроса вида articles/{id}
— метод контроллера, который извлекает параметр id
из пути запроса, затем извлекает статью из хранилища с этим идентификатором и возвращает html-страницу с текстом найденной статьи:
Извлекать параметры запроса (path param), в данном случае id
, можно с помощью фреймворка Javalin:
Какими бывают запросы: GET, DELETE, POST, PUT
Выше мы рассмотрели, как получить список статей и извлечь одну конкретную статью, — для этого используется метод GET HTTP. Но обычно в блоге можно еще и добавлять и удалять статьи — с этими задачами справляются другие методы HTTP.
Обычно веб-приложение использует четыре метода:
- GET – получение данных
- DELETE – удаление данных
- POST – создание данных
- PUT – обновление данных.
Для примера попробуем добавить статью в блог. Для этого используем метод POST HTTP:
Теперь у нас есть форма создания статьи:
А так выглядит разметка этой формы:
Сосредоточимся на отправке данных. Сначала пользователь вводит название и текст статьи, а потом нажимает кнопку «Создать». Так формируется запрос POST HTTP:
А теперь посмотрим, как обработчик POST запроса выглядит в коде:
Всего одной строчкой кода можно получить доступ к данным формы (form param), которые передаются в теле POST-запроса.
Чтобы получить две переменные из запроса, требуется две строчки кода в методе- обработчике:
В примерах выше мы рассмотрели:
- Как извлекать данные из тела POST запроса (form param)
- Как извлекать идентификатор "id" статьи из пути URL (path param), например “/articles/{id}”.
Перейдем к извлечению переменных запроса (query param) из URL. Для этого рассмотрим пример постраничного вывода статей.
В этом случае GET-запрос для запроса 1-ой страницы со статьями выглядит следующим образом: https://java-javalin-blog.hexlet.app/articles?page=1
В результате данного запроса в браузере можно наблюдать первую страницу со статьями:
Настроить маршрутизацию для такого запроса можно так:
В коде обработчика доступ к переменной запроса (query param) в URL происходит также в одну строчку:
Как работает шаблонизация
Представим, что клиент запрашивает страницу с первой статьей https://java-javalin-blog.hexlet.app/articles/1. Тогда сервер получает GET-запрос и присылает в ответ статью в виде html-страницы. Эта страница формируется программным путем с динамическим контентом.
Для этого используется шаблонизатор — инструмент, который позволяет упрощать генерацию конечных html-страниц за счет использования шаблонов. Здесь для примера мы используем Thymeleaf.
В нашем примере код обработчика будет выглядеть так:
Посмотрим еще раз на две последние строки кода. Здесь вызываются методы контекста приложения:
Первый метод — .attribute()
. Он записывает объект article
как атрибут, к которому можно получить доступ в шаблоне.
Второй метод — .render()
. Он производит рендеринг шаблона — то есть записывает динамический контент в html-странице.
Посмотрим на пример шаблона show.html для вывода одной статьи:
В этом шаблоне программным путем устанавливаются название статьи и текст самой статьи. Это происходит за счет того, что в шаблоне есть доступ к объекту article, у которого вызываются методы getName()
и getDescription()
.
В итоге генерируется такая html-страница:
Фреймворк Javalin прост в использовании и при этом помогает автоматизировать рутинные задачи при написании веб-приложения. Он идеально подходит для обучения, потому что позволяет сосредоточиться на логике сайта, а не на продумывании базовой архитектуры или кодировании вспомогательных инструментов.
Дополнительные материалы
-
Работающая версия блога: https://java-javalin-blog.hexlet.app
-
Исходный код блога: https://github.com/hexlet-components/java-javalin-blog
Читайте также:
Как выбрать свой первый опен-сорс проект: инструкция от Хекслета
Сергей Чепурнов
3 года назад