Статьи

RESTful веб-приложения с Джерси и Spring

Пару месяцев назад нам было поручено создать API для предоставления некоторых функций в нашей системе сторонним разработчикам. Мы решили представить эти функции в виде серии веб-сервисов REST. Я начал играть с Джерси , эталонной реализацией JSR 311 (Java API для Restful Services) это оказалось приятным сюрпризом, поскольку оказалось очень мощным и элегантным. В этом посте мы создадим очень простой веб-сервис REST с использованием Jersey.

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

Отдых вкратце

REST (Передача состояния представления) не нова — она ​​была впервые предложена в 2000 году (Fielding, Architectural Styles и Design of Network-Software Architectures ) — но сегодня она все еще недостаточно используется, поскольку в последние пару лет она действительно вошла в моду. , Он используется для описания ресурсов через URL и позволяет манипулировать такими ресурсами. Идея состоит в том, чтобы использовать HTTP-протокол для создания независимого от платформы, не сохраняющего состояния, кеш-интерфейса между клиентом и сервером. Хотя REST можно применять к другим протоколам, в настоящее время мы занимаемся только HTTP.

Проще говоря, URL-адрес типа «http://www.myserver.com/files/text.txt» описывает ресурс, который представляет собой файл с именем text.txt и находится в домене myserver.com. Ничего особенного там нет; вы можете указать браузеру этот файл, и ваш браузер отправит GET-запрос на сервер для его получения. Вам даже не нужно писать какое-либо приложение для этого; любой клиент и сервер будут общаться таким образом.

Это становится более интересным с другими методами запроса; все, кто читает это, должны быть знакомы с методом POST (обычно используется для форм). В приложении REST размещение сообщения по URL-адресу означает, что вы хотите изменить ресурс по этому URL-адресу. Менее распространенные методы PUT и DELETE используются для создания и удаления ресурсов соответственно; например, PUT http://www.myserver.com/files/text.txt должен создать текстовый файл, обычно с содержимым тела запроса. Стоит отметить, что в некоторых системах, особенно в тех, которые предназначены для непосредственного взаимодействия с браузером, метод POST иногда используется для этих целей, поскольку некоторые браузеры не очень хорошо справляются с этими двумя.

REST также использует заголовки для управления кэшированием или для определения типов контента или языков, которые ожидает клиент; В конце концов, запрос — это обычный старый HTTP-запрос. Это хорошо, это чисто, это гибко, и это не будет зависеть от того, сколько сантехники вам потребуется для обеспечения той же функциональности, скажем, с SOAP. Причина, по которой мы пошли с этим, должна быть достаточно ясной на данный момент.

Анатомия класса ресурсов REST

Несмотря на то, что за кулисами происходит много всего, Джерси отлично скрывает всю сложность своих хороших чистых аннотаций. Учтите следующее:

   1: @Path("/people/{code}")
   2:publicclass Individual {

   3:
   4:

     @GET
   5:     @Produces({"application/json", "application/xml"})
   6:public Object find(@PathParam("code") String code) { ... }

   7:
   8:

     @DELETE   9:public void remove(@PathParam("code") String code) { ... }
  10: }

Это простой класс, который может искать или удалять запись для человека на основе уникального кода. В первой аннотации Path указывается, к какому URL относится данный класс (или метод — вы можете переопределить путь на уровне метода, если хотите). В этом случае мы говорим, что хотим, чтобы этот класс обрабатывал запросы, сделанные «[независимо от домена] / people»; мы также будем ожидать значения после «людей», которое мы будем считать уникальным кодом для человека, которого мы хотим — это значение в скобках.

Мы можем использовать несколько переменных в пути; мы могли бы, например, сказать «/ team / {team_id} / {position}» или даже «/ team / {team_id} / staff / {position}», чтобы получить подробную информацию о лицах, занимающих данную должность в команде, в зависимости от того, насколько многословным мы хотим быть. Мы также можем создать ограничения для параметров; например, если мы хотим, чтобы код представлял собой числовое значение, мы можем определить его как «{code: [0-9] *}»; определение принимает шаблоны регулярных выражений.

GET и УДАЛЕНИЕ аннотации указать , какой метод Java должен обрабатывать HTTP , какой метод. Для этих методов также есть аннотации POST и PUT.

PathParam аннотация захватывает параметры из запроса URL и передает их на методу — в этом случае, он захватывает параметр кода. Пока что это понятно — существуют даже версии FormParam и HeaderParam для получения значений из полей формы POST или заголовков запросов соответственно.

Я нашел Выдает аннотации довольно интересно. Параметр к аннотации принимает коллекцию типов MIME, которые объявляют типы возвращаемых данных, которые метод может генерировать. В обоих вышеупомянутых случаях мы можем обслуживать ответы в формате JSON или XML — возвращаемый ответ выбирается на основе значения заголовка ACCEPT запроса — если запрос принимает несколько типов возврата, предоставленных методом, первый быть перечисленным в заголовке ПРИНЯТЬ является предпочтительным.

Возвращая что угодно

При возврате экземпляра класса, аннотированного XmlRootElement , Джерси заботится об определении возвращаемого типа и преобразовании объекта в требуемое представление. Без суеты, без суеты. Если вам нужно сделать более интересное форматирование — например, преобразование в PDF или HTML-страницу, это должно быть так же просто, как написать и зарегистрировать маршаллер для данного типа, хотя я еще не углубился в это.

Все это связано с весной

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

Во-первых, мы должны сказать Spring, что наш ресурс является настраиваемым компонентом. Чтобы сделать это, мы можем просто добавить аннотацию Component к классу. Затем нам нужно определить область действия; Так как REST предназначен для сохранения состояния, мы просто объявим область запроса, используя аннотацию Scope со значением «request». Пока никаких сюрпризов! Объявление нашего класса теперь выглядит так:

   1: @Component
   2: @Scope("request")
   3: @Path("/people/{code}")
   4:publicclass Individual {
   5:     ...
   6: }

Наконец, просто скажите Spring, где искать ваши компоненты:

   1:<?xmlversion="1.0"encoding="UTF-8"?>
   2:<beansxmlns="http://www.springframework.org/schema/beans"
   3:xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   4:xmlns:context="http://www.springframework.org/schema/context"
   5:xsi:schemaLocation="
   6:            http://www.springframework.org/schema/beans
   7:            http://www.springframework.org/schema/beans/spring-beans.xsd
   8:            http://www.springframework.org/schema/context
   9:            http://www.springframework.org/schema/context/spring-context.xsd">

  10:
  11:

<context:component-scanbase-package="your.namespace.here"/>
  12:</beans>

Где «your.namespace.here», очевидно, пространство имен для ваших классов ресурсов. Если вам нужно добавить какие-либо bean-компоненты Spring в ваши компоненты, вы можете использовать — сюрприз — аннотацию Inject для заполнения их полей. Вот и все … у вас есть готовый ресурс REST.

Это не все гуляет

Это действительно все, что нужно сделать. Помимо нескольких проблем, которые я все еще изучаю — JAXB полностью теряет свои шарики, когда находит круговую ссылку, что затрудняет маршализацию некоторых объектных моделей — JSR 311 предоставляет действительно чистый способ собрать все это вместе.

Есть одна схватка; Типы возвращаемых коллекций кажутся проблемой. Это можно обойти, поместив коллекции в контейнер, но это кажется ненужным шагом.

Пример приложения

Пример приложения список может, загружать или удалять отдельные записи из карты в памяти на сервере с помощью JQuery Ajax вызовов. Он был упакован в два файла WAR (сервер и клиент). Из-за изолированной программной среды браузера убедитесь, что пакеты клиента и сервера находятся в одном домене; это ограничение не существует, если вы подключаетесь к серверу программным способом.

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

 

С http://karlagius.com/2010/12/05/restful-web-applications-with-jersey-and-spring/