Как упростить создание сайтов с помощью фреймворка Javalin: разбираем на примере
2026-02-26 23:13 Diff

Зачем использовать простой фреймворк Javalin на языке Java для обработки запросов и формирования ответов, и как работает шаблонизация.

Статью подготовил Сергей Чепурнов, наставник на Хекслете, Java-разработчик с опытом работы более 7 лет в распределенных командах. Профиль Сергея на GitHub

Содержание

Как устроены веб-приложения

Все веб-приложения работают по одному принципу. Во-первых, они состоят из двух частей:

  • Клиент — зачастую это браузер или приложение на устройстве пользователя
  • Сервер — компьютер с серверным ПО, который обрабатывает запросы от клиента.

Во-вторых, в каждом приложении клиент и сервер обмениваются информацией таким образом:

  • Клиент отправляет запрос к серверу
  • Сервер обрабатывает запрос
  • Сервер отправляет сформированный ответ обратно клиенту.

Такая последовательность из трех шагов называется циклом «запрос-обработка-ответ». На схеме она выглядит так:

Обработка запросов и формирование ответов — это рутинная задача в каждом веб-приложении.

При программировании на языке Java есть два способа работы с циклом «запрос-обработка-ответ»:

  1. Использование Servlet API — это стандартный пакет классов и интерфейсов, то есть встроенный механизм построения клиент-серверного приложения по схеме «запрос-ответ». Главный минус — придется писать много однотипного кода, создавать множество классов и т. п.
  2. Использование фреймворка для автоматизации повторяющихся задач. Фреймворк — это каркас веб-приложения, определяющий структуру программы. Код веб-приложения в таком случае легче читается, поддерживается и тестируется. Благодаря фреймворкам вы можете сосредоточиться на логике сайта, не отвлекаясь на продумывание базовой архитектуры или кодирование вспомогательных инструментов.

Рассмотрим фреймворк Javalin: он настолько прост, что работающее веб-приложение можно написать буквально в две строчки кода:

Конечно, это еще не все. Также для запуска нужна система сборки — она скачает все указанные зависимости, скомпилирует исходный код и запустит приложение.

Для примера мы будем использовать систему сборки Gradle. В этом случае запуск приложения выполняется командой run в корне директории проекта:

Откроем в браузере страницу с адресом localhost

и посмотрим, запустилось ли наше двухстрочное приложение.

Все прошло успешно:

Запрос /  и ответ Hello World связаны между собой. Клиент делает запрос по адресу localhost

. При этом сервер понимает, что к нему обратились с запросом «/», и в качестве ответа возвращает строку Hello World.

Чтобы разобраться подробнее, вернемся к двум строкам выше. Посмотрим, что в них написано:

Первая строка создает объект типа Javalin и устанавливает номер порта, на котором будет работать приложение (порт 7070 в данном случае). Вторая строка добавляет обработчик для запроса /.  Обработчик записывается в виде лямбда-выражения и формирует ответ в виде строки.

Клиент получает ответ от сервера в виде http-ответа, в теле которого содержится строка:

Как работает маршрутизация в Javalin

Поступающие запросы нужно маршрутизировать — то есть обработать на сервере.  Когда сервер получает запрос от клиента, он начинает маршрутизацию: обрабатывает запрос и определяет, какой ответ нужно отправить клиенту.

Как это происходит:

  1. Сервер считывает /about в конце URL и отличает этот запрос от всех остальных
  2. Затем сервер формирует подходящий ответ — отправляет html-страницу «О блоге».

Рассмотрим пример. Создадим веб-приложение в виде блога: https://java-javalin-blog.hexlet.app. Пользователь переходит по ссылкам внутри блога и получает разную информацию. Например, на https://java-javalin-blog.hexlet.app/articles — увидит список всех статей, а на странице https://java-javalin-blog.hexlet.app/about — узнает больше о блоге и авторах.

Посмотрим, как маршрутизация работает в приложении:

Обратите внимание, что каждому URL соответствует определенный ответ — именно он возвращается в виде html-страницы. Таким образом, пользователь увидит в браузере такую страницу:

Как работают динамически сформированные запросы

До этого мы рассматривали статические адреса такого вида:

Кроме статических адресов, в веб-приложениях используются и динамически сформированные адреса. Например:

Такие URL запрашивают статьи по их уникальному идентификатору (id). По id сервер различает запросы и возвращает соответствующую статью в виде html-страницы.

Если на сайте есть список статей, то его можно выводить на странице в виде списка названий, а ссылки формировать динамически и с разными идентификаторами. Обычно шаблон ссылки выглядит следующим образом: “/articles/{id}”, где вместо "{id}” программным путем подставляется конкретный идентификатор статьи.

Чтобы обрабатывать такие запросы, на сервере создается отдельный класс контроллер, который отвечает за обработку запроса и формирование ответа клиенту.

Рассмотрим, как выглядит обработка запроса https://java-javalin-blog.hexlet.app/articles/1 в коде приложения.

Во-первых, в маршрутизации появляется отсылка к методу контроллера:

Эта настройка маршрутизации сообщает о двух важных аспектах:

  1. GET-запрос по адресу /articles попадает на обработчик ArticleController.listArticles.
  2. GET-запрос по адресу articles/{id} с любым целочисленным параметром id попадает на обработчик ArticleController.showArticle

Во-вторых, обработчик запроса вида articles/{id} — метод контроллера, который извлекает параметр id из пути запроса, затем извлекает статью из хранилища с этим идентификатором и возвращает html-страницу с текстом найденной статьи:

Извлекать параметры запроса (path param), в данном случае id, можно с помощью фреймворка Javalin:

Какими бывают запросы: GET, DELETE, POST, PUT

Выше мы рассмотрели, как получить список статей и извлечь одну конкретную статью, —  для этого используется метод GET HTTP. Но обычно в блоге можно еще и добавлять и удалять статьи — с этими задачами справляются другие методы HTTP.

Обычно веб-приложение использует четыре метода:

  1. GET – получение данных
  2. DELETE – удаление данных
  3. POST – создание данных
  4. 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 прост в использовании и при этом помогает автоматизировать рутинные задачи при написании веб-приложения. Он идеально подходит для обучения, потому что позволяет сосредоточиться на логике сайта, а не на продумывании базовой архитектуры или кодировании вспомогательных инструментов.

Дополнительные материалы