Статьи

Начало работы с Dropwizard

Dropwizard — это фреймворк для создания веб-сервисов RESTful на Java. В этом уроке мы рассмотрим, как начать разработку приложения Dropwizard, создав новый сервис с нуля. Эта статья собирается охватить самые основы. Цель состоит в том, чтобы реализовать и запустить приложение Dropwizard, способное ответить на запрос HTTP GET.

После небольшого знакомства с Dropwizard и нашим доменом приложений, мы увидим, как создать новый проект, поговорим о его структуре и настройке. Позже мы реализуем простой RESTful API перед окончательной сборкой и запуском вашего приложения.

Пример проекта доступен на GitHub . Ключевые коммиты помечены тегами, и я буду ссылаться на них в этом посте после каждого серьезного изменения. Если вы чувствуете, что что-то неясно, и хотите увидеть снимок всего проекта, смело проверяйте тег , на который ссылаются.

Единственные предварительные условия, которые вам необходимо установить, — это Maven, JDK и текстовый редактор или IDE на ваш выбор.

Что такое Dropwizard?

Как уже говорилось, Dropwizard — это фреймворк для создания веб-сервисов RESTful на Java. По сути, это связующий фреймворк, который объединяет популярные и проверенные на практике библиотеки Java и фреймворки, чтобы упростить начало создания новых веб-сервисов RESTful.

Вот неполный список некоторых библиотек, которые использует Dropwizard.

  • Jersey — эталонная реализация JAX-RS , API для веб-сервисов RESTful на платформе Java
  • Jackson — библиотека для обработки данных JSON
  • Jetty — HTTP-сервер и контейнер сервлетов Java
  • Metrics — библиотека для сбора метрик JVM и приложений для мониторинга
  • Гуава — утилита библиотека
  • Logback — библиотека журналов

Представляем наш демонстрационный домен приложений

Чтобы лучше понять Dropwizard, мы собираемся создать веб-сервис RESTful с нуля. Это будет бэк-энд для приложения гипотетических событий. Представьте, что вы переехали в новый город и хотели бы спланировать свой вечер. Это приложение будет перечислять события на основе ваших критериев поиска и местоположения. Серверная часть должна быть в состоянии предоставить список событий. Также должна быть возможность добавлять новые события и обновлять существующие события. Для простоты мы пока исключим аутентификацию и авторизацию пользователей.

Структура проекта

Я собираюсь использовать Maven в качестве инструмента для сборки. На мой взгляд, самый простой способ начать работу с новым приложением — создать проект с использованием dropwizard-archetype . Archetype — это инструмент для начальной загрузки проекта Maven из шаблона.

Запустите следующую команду в своем терминале, чтобы начать работу с новым проектом Dropwizard.

 mvn archetype:generate \ -DarchetypeGroupId=io.dropwizard.archetypes \ -DarchetypeArtifactId=java-simple \ -DarchetypeVersion=1.0.2 

По состоянию на октябрь 2016 года последняя версия Dropwizard: 1.0.2. Обязательно проверьте самую последнюю версию и соответственно обновите archetypeVersion . Запуск команды archetype:generate предлагает вам ввести некоторые поля, специфичные для проекта (например, groupId, artifactId). При вводе имени проекта имейте в виду, что это поле используется для генерации классов приложения и конфигурации. Используйте CamelCase и не вставляйте пробелы, чтобы убедиться, что сгенерированные имена классов будут действительными.

Например, я назвал приложение Events . Поэтому сгенерированные классы будут называться EventsApplication и EventsConfiguration . Если бы я использовал events-app в качестве имени, было бы сгенерировано event-appApplication и event-appConfiguration . К сожалению, это недопустимые имена классов, и компилятор укажет вам это.

При успешном завершении, это то, как выглядит сгенерированная структура папок.

 . ├── config.yml ├── pom.xml ├── README.md └── src ├── main │ ├── java │ │ └── com │ │ └── mydomain │ │ ├── api │ │ ├── cli │ │ ├── client │ │ ├── core │ │ ├── db │ │ ├── EventsApplication.java │ │ ├── EventsConfiguration.java │ │ ├── health │ │ └── resources │ └── resources │ ├── assets │ └── banner.txt └── test ├── java │ └── com │ └── mydomain │ ├── api │ ├── client │ ├── core │ ├── db │ └── resources └── resources └── fixtures 

Конфигурация приложения хранится в config.yml . Мы рассмотрим это более подробно в следующем абзаце. Большая часть мяса находится в src/main/java включая два вышеупомянутых класса — EventsApplication и EventsConfiguration .

Ниже приведен обзор того, какие файлы должны идти в какую папку:

  • api — Здесь представлены представления вашего приложения, которые по сути являются сущностями вашего API. Они сериализуются и десериализуются в JSON.
  • cli — Содержит команды, которые могут быть выполнены из командной строки. Они не рассматриваются в этом уроке.
  • client — HTTP-реализация клиента вашего API. Для удобства использования вашего API вы можете реализовать клиент и разместить его здесь. Мы не собираемся делать это в этом уроке.
  • core — здесь вы реализуете свою доменную логику.
  • db — классы, связанные с доступом к базе данных.
  • health — Содержит проверки здоровья. Это тесты во время выполнения, которые проверяют, правильно ли работает ваше приложение.
  • resources — ресурсы Джерси.

Мы не собираемся использовать все эти пакеты, так как я бы хотел, чтобы учебник был проще. Dropwizard не строго придерживается схемы именования пакетов. При желании вы можете переименовать и реструктурировать иерархию пакетов в соответствии с вашими потребностями.

Начальную структуру проекта можно увидеть, проверив starting-point тега.

Конфигурация приложения

Хранение переменных, которые могут варьироваться в зависимости от среды выполнения в файле конфигурации, считается хорошей практикой. При запуске приложения Dropwizard ожидает получить файл конфигурации в качестве аргумента командной строки. По умолчанию файлы конфигурации должны быть написаны на YAML . Проанализированные поля конфигурации используются для создания нового экземпляра класса конфигурации.

А пока давайте сохраним конфигурационный файл настолько простым, насколько это возможно. Я хотел бы добавить две вещи. Во-первых, давайте изменим корневой путь нашего приложения, чтобы все конечные точки REST обслуживались из /api/* . Параметр rootPath является одним из многих встроенных параметров конфигурации, предлагаемых Dropwizard, поэтому нам не нужно изменять какой-либо код, чтобы он был доступен.

Во-вторых, поскольку мы имеем дело с событиями, мы заботимся о времени начала, которое можно представить разными способами . Давайте добавим параметр конфигурации формата даты, который позволяет нам управлять выходным форматом даты из файла конфигурации.

Сначала измените config.yml и добавьте следующую конфигурацию.

 server: rootPath: /api/* dateFormat: yyyy-MM-dd'T'HH:mmZ 

Конечно, нам нужно получить доступ к пользовательскому параметру конфигурации dateFormat из запущенного приложения. При запуске Dropwizard поля конфигурации сопоставляются с полями-членами класса конфигурации.

Итак, давайте отредактируем наш класс конфигурации и dateFormat поле dateFormat . Откройте EventsConfiguration и добавьте следующие строки:

 @NotEmpty private String dateFormat; public String getDateFormat() { return dateFormat; } 

Приложение не должно доверять внешнему файлу конфигурации, чтобы быть правильным. Чтобы подтвердить правильность, мы можем использовать Hibernate Validator . Аннотация @NotEmpty гарантирует, что строка не пуста. В противном случае Dropwizard не запустится.

Имейте в виду, что это не проверяет, является ли шаблон формата даты действительным. Он только проверяет, определен ли он в файле конфигурации. Вы можете создать свой собственный валидатор, который будет выводить хорошее сообщение об ошибке при запуске, если шаблон неверен. Чтобы было проще, я не буду сейчас заниматься этим вопросом.

Проверьте тег app-configuration чтобы увидеть проект после изменений конфигурации.

Класс приложения

Вот как выглядит сгенерированный класс приложения.

 public class EventsApplication extends Application<EventsConfiguration> { public static void main(final String[] args) throws Exception { new EventsApplication().run(args); } @Override public void run(EventsConfiguration configuration, Environment environment) { } @Override public void initialize(Bootstrap<EventsConfiguration> bootstrap) { } } 

При запуске службы вызывается метод main внутри класса EventsApplication . Это точка входа для приложения Dropwizard. Создается новый объект EventsApplication вызывается его метод run . Метод run используется для настройки среды Dropwizard.

Это место для применения шаблона даты, используемого в нашем приложении. Для этого мы настраиваем ObjectMapper Джексона, который позднее (де) сериализует параметры запроса и ответа из классов Java в JSON и наоборот. Давайте изменим его формат даты, явно создав новый экземпляр SimpleDateFormat и передав ему шаблон из объекта конфигурации.

 @Override public void run(EventsConfiguration configuration, Environment environment) { DateFormat eventDateFormat = new SimpleDateFormat(configuration.getDateFormat()) environment.getObjectMapper().setDateFormat(eventDateFormat); } 

Позже мы собираемся изменить метод run для регистрации новых ресурсов .

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

Оформить заказ тег date-format-configuration чтобы увидеть проект после изменений, внесенных в класс приложения.

Создание представления доменных объектов

Представления являются сущностями вашего API. Они представляют текущее или желаемое состояние ресурса. Например, когда клиент делает HTTP-запрос GET к ресурсу событий , сервер отправляет обратно представление текущего состояния событий. Представления могут быть сериализованы в любой формат, но мы собираемся использовать JSON в этом руководстве.

Давайте подумаем о том, какие поля мы хотим включить в класс представления событий. Событие должно иметь имя. Также нам нужно знать, когда и где происходит мероприятие. Хозяева могут захотеть добавить дополнительную информацию о событии. Это требует поля описания. Рекомендуется также добавить идентификатор, поскольку мы хотим убедиться, что каждое событие уникально идентифицируемо.

Создайте новый класс Event в com.mycompany.api (или любой другой схеме именования пакетов, которую вы используете).

 public class Event { private long id; private String name; private String description; private String location; private Date date; //getters and setters omitted } 

В большинстве случаев использование строки для представления местоположения может быть недостаточно. Вы можете создать класс Location который может содержать более подробную информацию (например, широту, долготу). Dropwizard проверит правильность сериализации вложенных объектов.

Проверьте тег event-representation чтобы увидеть проект после создания нового класса представления.

Создать простой ресурс

Под капотом Dropwizard использует Jersey для создания веб-сервисов RESTful. Джерси является эталонной реализацией JAX-RS ( JSR 311 и JSR 339 ). Многое происходит в реализации ресурсов, и я не намерен, чтобы эта статья была всеобъемлющим обзором Джерси. Если вы хотите узнать больше, не стесняйтесь просматривать документацию Джерси .

Чтобы начать с Джерси, давайте создадим ресурс для событий. Кроме того, нам нужно определить URL, который можно использовать для доступа к ресурсу и получения его текущего состояния.

Давайте создадим очень простую реализацию ресурса событий. Цель состоит в том, чтобы выставить URL для извлечения всех событий. Сейчас мы собираемся вернуть фиктивные данные. Создайте новый класс с именем EventResource в пакете resources .

 @Path("events") @Produces(MediaType.APPLICATION_JSON) public class EventResource { @GET public List<Event> allEvents() { Event e = new Event(); e.setDate(new Date()); e.setName("Birthday"); e.setId(1L); e.setDescription("Please be on time!"); e.setLocation("221B Baker Street"); return Collections.singletonList(e); } } 

Аннотация @Path указывает корневой каталог URL для этого ресурса. В следующей строке мы указываем формат представления. Классы представления сериализуются в JSON и возвращаются клиенту. EventResource в своем текущем состоянии имеет только один метод: allEvents . Он аннотирован HTTP-глаголом, на который он должен ответить. Например, когда allEvents получает запрос GET для /events , вызывается allEvents . Говоря REST, GET используется для получения представления текущего состояния ресурса.

Внутри метода создается новый объект Event с фиктивными данными. Объект события помещается в список, который затем возвращается. Для удобства я использую singletonList из класса Collections. Создание нового списка вручную и добавление элемента в список будет также работать отлично.

Чтобы увидеть проект после создания ресурса, проверьте тег event-resource .

Регистрация ресурса

По умолчанию Dropwizard не знает о классах ресурсов, и нам нужно явно указать, какие ресурсы выставлять. Технически говоря, ресурсы должны быть зарегистрированы в среде Dropwizard’s Jersey Environment. Как упоминалось ранее, регистрация ресурса может быть выполнена в EventsApplication класса EventsApplication .

Измените его так, чтобы он выглядел как следующий пример.

 @Override public void run(EventsConfiguration configuration, Environment environment) { DateFormat eventDateFormat = new SimpleDateFormat(configuration.getDateFormat()) environment.getObjectMapper().setDateFormat(eventDateFormat); EventResource eventResource = new EventResource(); environment.jersey().register(eventResource); } 

Текущее состояние проекта можно увидеть, проверив тег register-resource .

Сборка приложения

Чтобы запустить приложение Dropwizard, его нужно сначала собрать. Рекомендуется создавать приложение в виде толстого файла JAR . Это JAR-файл, содержащий классы из вашего проекта и все библиотеки, от которых он зависит, поэтому все необходимое для приложения объединено в один файл, что упрощает его развертывание и запуск. Один и тот же артефакт может быть переведен из тестового режима в промежуточный и производственный, при этом он должен быть уверен, что в используемых библиотеках не будет изменений версии

Если вы следили за статьей и создали новый проект с dropwizard-archetype то Maven уже настроен для создания толстого JAR-файла с помощью maven-shade-plugin .

Просто запустите следующую команду в корне вашего проекта (в папке, где находится pom.xml ).

 mvn package 

Запуск приложения

Теперь вы можете выполнить файл JAR следующим образом.

 java -jar target/events-0.0.1-SNAPSHOT.jar server config.yml 

Для успешного выполнения нам нужно передать два аргумента командной строки в Dropwizard. Первый, server , инструктирует Dropwizard запустить HTTP-сервер и запустить сервис. Второй аргумент — это файл конфигурации, который требуется для команды сервера.

Если приложение запустилось без ошибок, укажите в браузере (или в инструменте командной строки http, например, curl ) http://localhost:8080/api/events . Сервер должен вернуться с правильным ответом, содержащим следующее тело сообщения.

 [{"id":1,"name":"Birthday","description":"Please be on time!","location":"221B Baker Street","date":"2016-10-03T12:09+0200"}] 

Резюме

К настоящему времени вы должны иметь общее представление о том, что такое Dropwizard. С помощью существующих библиотек Dropwizard позволяет разработчикам легко создавать новые веб-сервисы RESTful.

Там много чего мы не освещали. Прежде всего, требования, которые мы устанавливаем для нашего приложения, не выполняются. На данный момент клиенту возвращаются только фиктивные данные. Будет следующая статья, в которой мы добавим дополнительные функции в службу Events и рассмотрим части Dropwizard, которые мы не смогли описать в этой статье.