RESTEasy Client API

RESTEasy Client API

1. Вступление

Вprevious article мы сосредоточились на реализацииJAX-RS 2.0 на стороне сервераRESTEasy.

JAX-RS 2.0 представляет новый клиентский API, позволяющий выполнять HTTP-запросы к удаленным веб-службам RESTful. Jersey, Apache CXF, Restlet и RESTEasy - это лишь часть наиболее популярных реализаций.

В этой статье мы рассмотрим, как использоватьREST API, отправляя запросы сRESTEasy API.

2. Настройка проекта

Добавьте в свойpom.xml следующую зависимость:


    3.0.14.Final


    
        org.jboss.resteasy
        resteasy-client
        ${resteasy.version}
    
    ...

3. Код на стороне клиента

Реализация клиента вполне, состоит из 3 основных классов:

    • клиент

    • WebTarget

    • отклик

ИнтерфейсClient является компоновщиком экземпляровWebTarget.

WebTarget представляет собой отдельный URL-адрес или шаблон URL-адреса, из которого вы можете создавать дополнительные WebTarget-ы подресурсов или вызывать запросы.

Существует действительно два способа создания клиента:

  • Стандартный способ, используяorg.jboss.resteasy.client.ClientRequest

  • RESTeasy Proxy Framework: с помощью классаResteasyClientBuilder

Мы сосредоточимся на RESTEasy Proxy Framework здесь.

Вместо использования аннотаций JAX-RS для сопоставления входящего запроса с вашим методом веб-службы RESTFul, клиентская среда создает HTTP-запрос, который она использует для вызова удаленной веб-службы RESTful.

Итак, давайте начнем писать интерфейс Java и использовать аннотации JAX-RS для методов и интерфейса.

3.1. ИнтерфейсServicesClient

@Path("/movies")
public interface ServicesInterface {

    @GET
    @Path("/getinfo")
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    Movie movieByImdbId(@QueryParam("imdbId") String imdbId);

    @POST
    @Path("/addmovie")
    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    Response addMovie(Movie movie);

    @PUT
    @Path("/updatemovie")
    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    Response updateMovie(Movie movie);

    @DELETE
    @Path("/deletemovie")
    Response deleteMovie(@QueryParam("imdbId") String imdbId);
}

3.2. Кино-класс

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "movie", propOrder = { "imdbId", "title" })
public class Movie {

    protected String imdbId;
    protected String title;

    // getters and setters
}

3.3. Создание запроса

Теперь мы создадим прокси-клиента, который сможем использовать для использования API:

String transformerImdbId = "tt0418279";
Movie transformerMovie = new Movie("tt0418279", "Transformer 2");
final String path = "http://127.0.0.1:8080/RestEasyTutorial/rest";

ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target(UriBuilder.fromPath(path));
ServicesInterface proxy = target.proxy(ServicesInterface.class);

// POST
Response moviesResponse = proxy.addMovie(transformerMovie);
System.out.println("HTTP code: " + moviesResponse.getStatus());
moviesResponse.close();

// GET
Movie movies = proxy.movieByImdbId(transformerImdbId);

// PUT
transformerMovie.setTitle("Transformer 4");
moviesResponse = proxy.updateMovie(transformerMovie);
moviesResponse.close();

// DELETE
moviesResponse = proxy.deleteMovie(batmanMovie.getImdbId());
moviesResponse.close();

Обратите внимание, что клиентский API RESTEasy основан на ApacheHttpClient.

Также обратите внимание, что после каждой операции нам нужно будет закрыть ответ, прежде чем мы сможем выполнить новую операцию. Это необходимо, потому что по умолчанию клиент имеет только одно доступное соединение HTTP.

Наконец, обратите внимание на то, как мы работаем напрямую с DTO - мы не имеем дело с логикой маршалинга / демаршала отJSON илиXML и обратно; это происходит за кулисами с использованиемJAXB илиJackson, поскольку классMovie был правильно аннотирован.

3.4. Создание запроса с пулом подключений

Одно замечание из предыдущего примера состояло в том, что у нас было только одно доступное соединение. Если - например, мы пытаемся сделать:

Response batmanResponse = proxy.addMovie(batmanMovie);
Response transformerResponse = proxy.addMovie(transformerMovie);

без вызоваclose() наbatmanResponse - при выполнении второй строки будет сгенерировано исключение:

java.lang.IllegalStateException:
Invalid use of BasicClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.

Опять же - это просто происходит потому, что по умолчанию RESTEasy используетHttpClient какorg.apache.http.impl.conn.SingleClientConnManager, что, конечно, делает доступным только одно соединение.

Теперь - чтобы обойти это ограничение - экземплярRestEasyClient должен быть создан иначе (с пулом соединений):

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();
cm.setMaxTotal(200); // Increase max total connection to 200
cm.setDefaultMaxPerRoute(20); // Increase default max connection per route to 20
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient);

ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build();
ResteasyWebTarget target = client.target(UriBuilder.fromPath(path));
ServicesInterface proxy = target.proxy(ServicesInterface.class);

Теперь мы можемbenefit from a proper connection pool и можем иметь несколько запросов, проходящих через наш клиент, без необходимости каждый раз разрывать соединение.

4. Заключение

В этом кратком руководстве мы представилиRESTEasy Proxy Framework и создали с его помощью супер простой клиентский API.

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

Пример, использованный в этой статье, доступен какsample project in GitHub.