Статьи

Начало работы с Dropwizard: первые шаги

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

Самый простой способ создать проект Dropwizard — использовать архетип Maven, называемый java-simple, который является частью Dropwizard. Это может быть выполнено либо через командную строку, либо с помощью вашей любимой IDE. Давайте придерживаться прежнего подхода. Команда ниже отформатирована для ясности, но она должна быть вставлена ​​в терминал одной строкой.

mvn archetype:generate
  -DgroupId=com.javaeeeee
  -DartifactId=DWGettingStarted
  -Dname=DWGettingStarted
  -Dpackage=com.javaeeeee.dwstart
  -DarchetypeGroupId=io.dropwizard.archetypes
  -DarchetypeArtifactId=java-simple
  -DinteractiveMode=false

После создания проекта его можно изменить с помощью редактора или открыть в IDE. Все три IntelliJ, Eclipse и Netbeans имеют поддержку Maven. Важным параметром, который следует отметить в файле pom.xml вновь созданного проекта, является dropwizard.version, который на момент написания был автоматически установлен на 0.8.0-rc2-SNAPSHOT, а последняя стабильная версия была 0.7.1. Позже мы обсудим важные последствия версии для разработки проекта. Структура каталогов проекта показана ниже.

Есть несколько подпакетов и два класса, которые были созданы для нас в пакете  com.javaeeeee. dwstart. Теперь давайте создадим простой класс ресурсов, который создает строку «Hello world!», Запустим приложение и протестируем результаты, используя как браузер, так и cURL. Фрагмент ниже показывает класс ресурса.

@Path("/hello")
public class HelloResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getGreeting() {
        return "Hello world!";
    }
}

Существует специальный пакет,  com.javaeeeee. dwstart.recources для размещения классов ресурсов или соответствующей папки можно найти на скриншоте выше, если вы используете текстовый редактор, а не IDE.

Одним из основных принципов стиля архитектуры REST является то, что каждому ресурсу назначается URL. В нашем случае URL нашего ресурса будет http: // localhost: 8080 / hello, то есть мы обращаемся к нему с нашего локального компьютера, порт по умолчанию, который используется Dropwizard, равен 8080, а последняя часть URL закреплена в @Path аннотация в нашем классе, другими словами, вышеупомянутая аннотация помогает описать URL, используемый для доступа к ресурсу.

Переходя к методу getGreeting (), можно увидеть, что это простой метод, который возвращает желаемую строку «Hello world!», Хотя он помечен двумя аннотациями: во-первых, @GET предписывает, чтобы этот метод вызывался при упоминании вышеупомянутого URL доступ осуществляется с помощью метода HTTP GET, во-вторых, аннотация @Produces указывает, какие типы носителей могут создаваться при доступе метода к клиенту, например, в браузере, cURL или какой-либо другой программе. В нашем случае это простой текст. Эти аннотации являются частью  Java API для веб-служб RESTful  (JAX-RS), и его эталонная реализация  Jersey   является краеугольным камнем Dropwizard.

Другие аннотации включают @POST для метода HTTP POST, @DELETE для DELETE и т. Д., А типы носителей включают MediaType.APPLICATION_JSON и не очень популярный MediaType.APPLICATION_XML среди других. Теперь, чтобы увидеть результат нашего кодирования, нам нужно выполнить некоторую настройку. Давайте откроем один из созданных Maven файлов, DWGettingStartedApplication.java, и зарегистрируем наш ресурс.

    public void run(final DWGettingStartedConfiguration configuration,
            final Environment environment) {
        environment.jersey().register(new HelloResource());
    }

Мы добавили одну строку environment.jersey (). Register (new HelloResource ()); чтобы помочь Dropwizard найти наш класс ресурсов. Теперь нам нужно создать jar-файл, который содержит встроенный веб-сервер Джерси для обслуживания входящих запросов, а также все необходимые библиотеки. Приложения Dropwizard упакованы в виде исполняемых jar-файлов, а не war-файлов, которые развертываются на сервере приложений. Тип jar-файлов, используемых приложениями Dropwizard, также называют «толстыми», поскольку они включают в себя все файлы .class, необходимые для запуска приложения, поскольку это приводит к ситуации, когда версии всех библиотек одинаковы как в среде разработки, так и в рабочей среде, что приводит к меньшему количеству проблем. Не стоит беспокоиться о создании таких jar-файлов, поскольку Maven создает их для нас, используя инструкции в сгенерированном файле pom.xml проекта.Jar-файл может быть создан с помощью командной строки, выданной из папки проекта

mvn package

или используя IDE. После этого мы должны запустить приложение, которое можно выполнить либо из командной строки, введя команду

java -jar target/DWGettingStarted-1.0-SNAPSHOT.jar server

или из среды IDE, в которой можно передать аргумент «сервер» в исполняемый файл JAR. Чтобы остановить приложение, достаточно нажать Ctrl + C в терминале.

Теперь пришло время проверить, работает ли он. Самый простой способ добиться этого — перейти в браузере по указанному ранее URL-адресу. Вы должны увидеть строку приветствия в главном окне браузера. Если вы не видите приветствия, возможно, есть некоторые проблемы, и вывод программы — это место, где можно найти подсказки о том, что пошло не так.

Такое же приветствие можно увидеть в окне терминала с помощью cURL.

curl -w "\n" localhost:8080/hello

Протокол HTTP и метод GET являются значениями по умолчанию, поэтому нет необходимости явно указывать их в команде. В результате появляется сообщение «Hello world!» без кавычек должен быть напечатан. W-опция используется для добавления завершающего символа новой строки для предварительного вывода результатов.

Хорошей идеей будет начать использовать тесты как можно раньше, поэтому давайте напишем тест, который проверяет работу нашего класса ресурсов с использованием оперативной памяти Jersey. Мы создадим тест в тестовых пакетах, и при тестировании ресурса подходящим пакетом для размещения нашего теста будет  com.javaeeeee. dwstart.resources (или папка src / test / com / javaeeeee / dwstart / resources).

Необходимо добавить следующую зависимость в pom-файл проекта. (Работает без явной зависимости jUnit.)

        <dependency>
            <groupId>io.dropwizard</groupId>
            <artifactId>dropwizard-testing</artifactId>
            <version>${dropwizard.version}</version>
            <scope>test</scope>
        </dependency>

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

public class HelloResourceTest {

    @Rule
    public ResourceTestRule resource = ResourceTestRule.builder()
            .addResource(new HelloResource()).build();

    @Test
    public void testGetGreeting() {
        String expected = "Hello world!";
        //Obtain client from @Rule.
        Client client = resource.client();
        //Get WebTarget from client using URI of root resource.
        WebTarget helloTarget = client.target("http://localhost:8080/hello");
        //To invoke response we use Invocation.Builder
        //and specify the media type of representation asked from resource.
        Invocation.Builder builder = helloTarget.request(MediaType.TEXT_PLAIN);
        //Obtain response.
        Response response = builder.get();

        //Do assertions.
        assertEquals(Response.Status.OK, response.getStatusInfo());
        String actual = response.readEntity(String.class);
        assertEquals(expected, actual);

    }
}

Аннотация @Rule из области jUnit и может быть размещена в открытых нестатических полях и методах, которые возвращают значение. Эта аннотация может выполнять некоторую начальную настройку и очистку, например, методы @Before и @After, но она более мощная, поскольку позволяет обмениваться функциональностью между классами и даже проектами. Это правило необходимо для того, чтобы мы могли получить доступ к нашим ресурсам из кода теста, используя Джерси в памяти.

На данный момент мы должны сделать паузу и обсудить версию нашего продукта. В папке dropwizard на GitHub есть файл pom.xml. , к которому можно легко получить доступ путем клонирования проекта, и этот файл указывает версию составляющих продуктов среди прочего. Из него видно, что версия Джерси в снэпшот-версии Dropwizard — 2.13, а в версии 0.7.1 — 1.18.1. Версия Jersey влияет на код тестов, поскольку версии 1.x и 2.x Jersey имеют разные клиентские API, то есть код для программного доступа к сервису из Java зависит от версии инфраструктуры Jersey. Давайте придерживаться последней версии 2.x Джерси, так как она может быть включена в следующие выпуски Dropwizard 0.8.x, и если вы заинтересованы в том, чтобы протестировать использование более старой версии клиента Джерси, пожалуйста, проверьте  репозиторий проекта. есть специальная ветка v0.7.x. Еще одно наблюдение, касающееся тестирования, заключается в том, что сопоставители Fest были заменены аналогами AssertJ.

Сначала мы получаем экземпляр клиента из Джерси для отправки запросов в наш сервис. Во-вторых, мы создаем экземпляр класса, который реализует интерфейс WebTarget для ресурса, используя его URL. После этого мы используем Invocation.Builder, который помогает построить запрос и отправить его на сервер. Интерфейс Invocation.Builder расширяет интерфейс SynchInvoker, который определяет набор методов get (…), используемых для синхронного вызова метода HTTP GET. Наконец, мы проверяем результаты, а именно, что код состояния HTTP был 200, и была возвращена желаемая строка.

Тот же результат может быть получен путём цепочки методов, как в приведенном ниже фрагменте.

       actual = resource.client()
                .target("http://localhost:8080/hello")
                .request(MediaType.TEXT_PLAIN)
                .get(String.class);
        assertEquals(expected, actual);

Замена двух утверждений одним возможна из-за того, что метод get (…), который мы использовали, выдает исключение WebApplicationException, если код состояния HTTP не находится в диапазоне 2xx, другими словами, если есть проблема.

Теперь давайте улучшим наш ресурс, чтобы взять имя и вернуть сделанное на заказ приветствие. Это можно сделать несколькими способами, используя аннотации Джерси. Во-первых, использовать так называемые параметры пути, то есть вы передаете имя, используя URL-адрес, например http: // localhost: 8080 / hello / path_param / your_name. Приложение должно вернуть «Hello your_name». Давайте посмотрим на фрагмент кода.

    @Path("/path_param/{name}")
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getNamedGreeting(@PathParam(value = "name") String name) {
        return "Hello " + name;
    }

Теперь мы видим аннотацию @Path для нашего метода. Он добавляет свой контент к тем, которые создаются аннотацией на уровне класса, как видно из URL. Методы, помеченные этой аннотацией, называются методами подресурсов. Имя параметра name указано в фигурных скобках. Нечто интересное происходит внутри скобок метода getNamedGreeting. Есть аннотация, которая предписывает извлекать содержимое URL после «/ path_param /» в метод в качестве значения. Следует отметить, что если вы помечаете каждый метод одинаковой аннотацией @Produces (MediaType.TEXT_PLAIN), последний может быть удален из методов и использован для маркировки класса, тогда все методы выдают нужные типы мультимедиа, хотя это может быть отменено аннотациями с другим типом медиа для некоторых методов.

Второй способ передать имя — использовать параметры запроса, и URL-адрес может выглядеть следующим образом: http: // localhost: 8080 / hello / query_param? Name = your_name. Вывод должен быть «Hello your_name» без кавычек. Фрагмент приведен ниже.

    @Path("/query_param")
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getNamedStringWithParam(@DefaultValue("world") @QueryParam("name") String name) {
        return "Hello " + name;
    }

Еще раз, аннотация @Path добавляет что-то к нашему URL-адресу, затем устанавливается значение по умолчанию для параметра, если в вопросе нет вопросительного знака и следующих за ним символов в аннотации @DefaultValue. Другими словами, если параметр пропущен в URL и выглядит как http: // localhost: 8080 / hello / query_param, выводится фраза «Hello world». Последняя аннотация вставляет параметр из URL в параметр метода. Кстати, все эти случаи можно протестировать, как было показано выше. Для тестирования метода с использованием параметров запроса можно использовать метод queryParam (…) интерфейса WebTarget.

Есть пара моментов, на которые стоит обратить внимание. Во-первых, доступны другие аннотации @ * Param, а во-вторых, аннотация @DefaultValue не будет работать с параметрами пути, и для обработки отсутствия параметра необходимо ввести специальный метод подресурса.

Вы были достаточно терпеливы, чтобы нести весь этот текстовый персонал, но дело не в том, что такое API REST. Давайте создадим другой метод подресурса, который предварительно запрограммирован для возврата представления JSON. Первым шагом является создание класса представления, который должен быть помещен в пакет com.javaeeeee.dwstart.core. Давайте ограничимся чрезвычайно простым примером, который показан ниже.

public class Greeting {

    @JsonProperty
    private String greeting;

    public Greeting() {
    }

    public Greeting(String greeting) {
        this.greeting = greeting;
    }

    public String getGreeting() {
        return greeting;
    }
}

Приведенный выше класс опирается на еще одну важную часть стека Dropwizard, а именно  Jackson  , который может превращать объекты Java в JSON и наоборот. Для выполнения этой работы используется аннотация @JsonProperty. Метод подресурса выглядит почти так же, как наши ранее обсуждавшиеся методы.

    @Path("/hello_json")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Greeting getJSONGreeting() {
        return new Greeting("Hello world!");
    }

Разница в том, что мы изменили тип медиа, и метод возвращает экземпляр класса приветствия. Если вы перейдете в браузер по URL-адресу http: // localhost: 8080 / hello / hello_json или используете cURL, вы должны увидеть JSON-представление объекта {«reeting «:» Hello world! «}.

Что, если мы вообще удалим аннотацию @Path из вышеупомянутого метода? Что ж, если вы попытаетесь получить доступ к ресурсу localhost: 8080 / hello, вы увидите текстовое представление. Как можно получить доступ к JSON-производящему методу? Существует специальный заголовок HTTP, называемый Accept, который используется для указания серверу, какое представление вернуть, процесс называется согласованием содержимого. Джерси внутри Dropwizard выберет для нас, какой метод использовать, основываясь на содержимом заголовка Accept. Давайте попробуем cURL сделать это.

curl -w "\n" -H 'Accept: application/json' localhost:8080/hello/

Опция H используется для отправки заголовков, и мы дали команду cURL запросить ответ JSON. Другие возможные типы могут включать text / plain и application / xml. Первый должен возвращать текстовое представление, а буква должна приводить к ошибке, поскольку в нашем классе ресурсов нет метода, который мог бы генерировать последний тип медиа-ответа.

Другой способ участвовать в согласовании контента — использовать REST-клиент для вашего браузера. Существует несколько клиентов для каждого из основных браузеров, но мы будем использовать расширение Postman для браузера Chrome. Как показано на скриншоте ниже, есть специальные поля для ввода заголовков.

Можно ввести URL ресурса, заголовки и нажать кнопку «Отправить», и ответ появится в нижней части окна.

Подводя итог, мы создали простой REST-подобный API с помощью Dropwizard, который может приветствовать своих пользователей. Мы узнали, как создать проект Dropwizard с использованием архетипа Maven, и создали простой класс ресурсов для выполнения задачи приветствия и класс представления для получения ответа JSON. Важный компонент архитектурного стиля REST, HATEOAS, на данный момент для простоты опущен. Также была затронута проблема тестирования классов ресурсов, а также способы доступа к ресурсам как из браузера, так и из командной строки. Есть несколько других идей для создания подресурсов, таких как возврат текущей даты и добавление двух чисел с использованием параметров запроса, которые могут быть легко реализованы с использованием информации, представленной в этой статье.

Ссылки

  1. Dropwizard на  GitHub 
  2. Maven Архетипы 
  3. Dropwizard Начало работы 
  4. JAX-RS Ресурсы и подресурсы 
  5. Тестирование Dropwizard 
  6. API клиента Джерси 2.x
  7. API клиента Джерси 1.x 
  8. Джексон аннотации