Создаем Web-сервисы RESTful при помощи Spring 3

В мире Java™ можно создавать Web-сервисы RESTful-стиля несколькими способами: некоторые используют JSR 311(JAX-RS) и ее эталонную реализацию Jersey, другие используют среду Restlet, а третьи даже начинают разработку с нуля. Spring, хорошо известная среда для создания приложений на Java EE, теперь поддерживает REST на уровне MVC. Этот новый способ создания Web-сервисов RESTful представлен в предлагаемой статье. Узнайте, как использовать интерфейсы прикладного программирования и аннотации Spring для создания Web-сервисов RESTful, и оцените, насколько органично эта новая возможность интегрируется в существующую среду Spring.

И Мин Хуан, инженер-программист, IBM

И Мин Хуан (Yi Ming Huang) - фотографияИ Мин Хуан (Yi Ming Huang) - инженер-программист China Development Lab, занимается Mashup-приложениями в Lotus. Он имеет опыт Web-разработки на базе портлетов и виджетов. Интересуется технологиями REST, OSGi и Spring.



Дун Фэй Ву, инженер-программист, IBM

Дун Фэй Ву (Dong Fei Wu) - фотографияДун Фэй Ву (Dong Fei Wu), инженер-программист China Development Lab, занимается Mashup-приложениями в Lotus. Он имеет обширный опыт Web-разработки на базе портлетов и виджетов. Дун также является главным разработчиком WebSphere Dashboard Framework.



15.03.2013

Введение

Концепция REST была представлена Роем Филдингом, одним из основных авторов спецификаций HTTP версии 1.0 и 1.1, в его докторской диссертации в 2000 году.

В архитектурном подходе, известном как передача репрезентативного состояния (Representational State Transfer — REST), запросы и ответы строятся вокруг передачи представлений ресурсов. Ресурсы определяются глобальными идентификаторами (ID) — обычно унифицированными идентификаторами ресурсов (Uniform Resource Identifier — URI). Клиентские приложения используют для управления ресурсами или коллекциями ресурсов HTTP-методы (такие как GET, POST, PUT или DELETE). Как правило, метод GET используется для получения ресурса или коллекции ресурсов, POST — для создания, PUT — для обновления или замены, а DELETE — для удаления ресурса.

Например, ответом на запрос GET http://host/context/employees/12345 будет представление сотрудника с идентификатором (ID) 12345. Это ответное представление, содержащее подробную информацию о сотруднике, может быть получено в виде XML или ATOM, а также в виде JSP/HTML-страниц с улучшенным пользовательским интерфейсом. Вид представления будет зависеть от реализации на стороне сервера и MIME-типа запроса клиентов.

Web-сервисы RESTful — это Web-сервисы, реализуемые с использованием HTTP и принципов REST. Как правило, Web-сервис RESTful определяет URI основного ресурса, поддерживаемые MIME-типы представления/ответа и операции.

В этой статье вы узнаете, как использовать Spring для создания Java Web-сервиса RESTful на стороне сервера. В примере используются браузер, утилита curl и Firefox-плагин RESTClient для клиентов, выполняющих запросы. Вы можете загрузить исходный код, используемый в этой статье.

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


Поддержка Spring 3 REST

До появления поддержки REST в Spring для создания Web-сервисов RESTful в Java-приложениях использовалось несколько других реализаций, таких как Restlet, RestEasy и Jersey. Наиболее заметная реализация из этой группы, Jersey, является эталонной реализацией JAX-RS (JSR 311). В разделе Ресурсы можно найти дополнительную информацию о JSR 311 и Jersey.

В Spring, широко распространенной среде Java EE, поддержка создания Web-сервисов RESTful появилась в версии 3 (Release 3). Хотя эта поддержка REST не является реализацией JAX-RS, она имеет больше возможностей, чем определяет спецификация. Поддержка REST полностью интегрирована в MVC-слой Spring и может быть легко использована в приложениях, созданных при помощи Spring.

Основные возможности поддержки REST в Spring:

  • Аннотации, такие как @RequestMapping и @PathVariable, для поддержки идентификации ресурсов и отображений URI.
  • ContentNegotiatingViewResolver для поддержки различных представлений с различными MIME-типами и типами содержимого.
  • Полная интеграция в исходный MVC-слой с аналогичной моделью программирования.

Создание примера Web-сервиса RESTful

В этом разделе мы шаг за шагом рассмотрим на примере шаги по настройке среды Spring 3 и созданию приложения "Hello World", которое может быть интегрировано в Tomcat. Затем мы перейдем к более сложным приложениям, чтобы представить основные элементы поддержки REST в Spring 3, такие как поддержка разнообразных MIME-типов и поддержка JAXB. Фрагменты кода проиллюстрируют концепции. Вы можете загрузить все примеры кода для этой статьи.

В данной статье предполагается, что вы знакомы со средой Spring и Spring MVC.

Пример Hello World: использование поддержки REST в Spring 3

Для настройки среды разработки для рассматриваемого примера вам понадобятся:

  • IDE: Eclipse IDE for JEE (v3.4+).
  • Java SE5 или выше.
  • Web-контейнер: Apache Tomcat 6.0 (Jetty или другие, которые тоже будут работать).
  • Среда Spring 3 (актуальная версия на момент написания статьи - v3.0.3).
  • Другие библиотеки: JAXB 2, JSTL, commons-logging.

Создайте динамическое Web-приложение в Eclipse и настройте его на выполнение в Tomcat 6. Затем нужно настроить файл web.xml, чтобы разрешить Spring WebApplicationContext. В примере конфигурация bean-компонента Spring разделена на два файла: в rest-servlet.xml находятся настройки, относящиеся к MVC/REST, а в rest-context.xml — настройки уровня сервиса (например, bean-компоненты источников данных). В листинге 1 показан фрагмент конфигурации Spring в web.xml.

Листинг 1. Разрешение Spring WebApplicationContext в web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
	/WEB-INF/rest-context.xml
</param-value>
</context-param>
	
<!-- Этот прослушиватель загрузит файл контекста приложения в дополнение к  
            rest-servlet.xml -->
<listener>
<listener-class>
	org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
	
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>
	org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>rest</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>

Настройте конфигурацию Spring MVC (Controller, View, View Resolver) в файле rest-servlet.xml.

В листинге 2 показан наиболее важный фрагмент.
<context:component-scan base-package="dw.spring3.rest.controller" />

<!--Чтобы разрешить обработку @RequestMapping на уровне типа и на уровне метода-->
<bean class="org.springframework.web.servlet.mvc.annotation
                       .DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation
                       .AnnotationMethodHandlerAdapter" />

<!--Используйте маршаллер JAXB OXM для маршаллизации/демаршаллизации следующего класса-->
<bean id="jaxbMarshaller"
class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
	<list>
	    <value>dw.spring3.rest.bean.Employee</value>
	    <value>dw.spring3.rest.bean.EmployeeList</value>
	</list>
</property>
</bean>

<bean id="employees" class=
	"org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg ref="jaxbMarshaller" />
</bean>

<bean id="viewResolver" class=
"org.springframework.web.servlet.view.BeanNameViewResolver" />

В приведенном выше коде:

Component-scan
Включает автоматическое сканирование для класса, который имеет аннотации Spring.
На практике он используется для обнаружения аннотации @Controller, определенной в классах контроллера.
DefaultAnnotationHanlderMappings и AnnotationMethodHandlerAdapter
Bean-компоненты, выполняющие аннотацию @ReqeustMapping класса или метода для обработки средой Spring.
Эта аннотация будет подробно рассмотрена в следующем разделе.
Jaxb2Mashaller
Определяет маршаллер/демаршаллер, который использует JAXB 2 для отображения объекта XML (Object XML Mapping — OXM).
MashallingView
Определяет XML-представление view, которое использует Jaxb2Mashaller.
BeanNameViewResolver
Задает резолвер (определитель) представления на основе имени bean-компонента, которое указывает пользователь.
В примере для MarshallingView будет использовано имя "employees" (сотрудники).

На этом завершается конфигурирование Spring. Следующим шагом является написание контроллера, обрабатывающего запрос пользователя. В листинге 3 показан класс контроллера.

Листинг 3. EmployeeController в пакете dw.spring3.rest.controller
@Controller
publicclass EmployeeController {
@RequestMapping(method=RequestMethod.GET, value="/employee/{id}")
public ModelAndView getEmployee(@PathVariable String id) {
	Employee e = employeeDS.get(Long.parseLong(id));
	returnnew ModelAndView(XML_VIEW_NAME, "object", e);
}
}

Аннотация @RequestMapping — это ключ к функциональности Spring REST. Она указывает, какой HTTP-метод (RequestMethod.GET) и какой URI (/employee/{id}) должны быть обработаны методом с этой аннотацией. Обратите внимание, что:

  • Значение, заключенное в {}, может быть введено в параметр метода при помощи аннотации @PathVariable.
  • XML_VIEW_NAME равно employees, а это имя представления, определенное в rest-servlet.xml.
  • employeeDS – простой источник данных, располагающийся в оперативной памяти (memory-based); его реализация выходит за рамки данной статьи.

Опубликуйте Web-приложение в Tomcat. Теперь можете открыть браузер и ввести http://<host>:<port>/<appcontext>/service/employee/1. Браузер должен отобразить XML-вид сотрудника с ID, равным 1.

Читайте дальше, чтобы узнать о других возможностях поддержки REST в Spring.

Методы

Управление ресурсами производится при помощи HTTP-методов, таких как GET, POST, PUT и DELETE. Ранее вы узнали, как использовать метод GET для получения информации о сотрудниках. Теперь мы рассмотрим POST, PUT и DELETE.

При использовании возможностей аннотации @RequestMapping код для обработки различных методов будет очень похожим. В листинге 4 показан фрагмент кода класса EmployeeController.

Листинг 4. EmployeeController в dw.spring3.rest.controller
@RequestMapping(method=RequestMethod.POST, value="/employee")
public ModelAndView addEmployee(@RequestBody String body) {
	Source source = new StreamSource(new StringReader(body));
	Employee e = (Employee) jaxb2Mashaller.unmarshal(source);
	employeeDS.add(e);
	returnnew ModelAndView(XML_VIEW_NAME, "object", e);
}

@RequestMapping(method=RequestMethod.PUT, value="/employee/{id}")
public ModelAndView updateEmployee(@RequestBody String body) {
	Source source = new StreamSource(new StringReader(body));
	Employee e = (Employee) jaxb2Mashaller.unmarshal(source);
	employeeDS.update(e);
	returnnew ModelAndView(XML_VIEW_NAME, "object", e);
}

@RequestMapping(method=RequestMethod.DELETE, value="/employee/{id}")
public ModelAndView removeEmployee(@PathVariable String id) {
	employeeDS.remove(Long.parseLong(id));
	List<Employee> employees = employeeDS.getAll();
	EmployeeList list = new EmployeeList(employees);
	returnnew ModelAndView(XML_VIEW_NAME, "employees", list);
}

В приведенном выше коде:

  • Значение RequestMethod.<Method> определяет, какой HTTP-метод должен обрабатывать аннотированный метод.
  • При помощи @RequestBody содержимое тела HTTP-запроса может быть введено в качестве параметра.

    В примере телом являются XML-данные, которые представляют сотрудника. Мы используем JAXB 2 для демаршаллизации XML в bean-компонент Java, а затем сохраняем его состояние. Пример тела запроса:

    <employee><id>3</id><name>guest</name></employee>
  • Другие полезные аннотации, которые могут быть введены в параметры метода, — это @PathVariable, @RequestParm и т.д. Полный список аннотаций приведен в документации по Spring (см. Ресурсы).

Коллекция ресурсов

Обычно существует необходимость управлять коллекцией ресурсов - например, если нужно получить информацию обо всех сотрудниках, а не только об одном человеке. Это можно реализовать аналогично предыдущему случаю; нужно всего лишь изменить URI с /employee на /employees. Множественное число для employee семантически соответствует коллекции. В листинге 5 показана реализация.

Листинг 5. GetAllEmployees в EmployeeController
@RequestMapping(method=RequestMethod.GET, value="/employees")
public ModelAndView getEmployees() {
	List<Employee> employees = employeeDS.getAll();
	EmployeeList list = new EmployeeList(employees);
	returnnew ModelAndView(XML_VIEW_NAME, "employees", list);
}

Необходимо объявить класс-оболочку для коллекции Employee. Класс-оболочка необходим для JAXB 2, поскольку он не может маршаллизовать класс java.util.List правильно. В листинге 6 показан класс EmployeeList.

Листинг 6. Класс EmployeeList в dw.spring3.rest.bean
@XmlRootElement(name="employees")
publicclass EmployeeList {
	privateint count;
	private List<Employee> employees;

	public EmployeeList() {}
	
	public EmployeeList(List<Employee> employees) {
		this.employees = employees;
		this.count = employees.size();
	}

	publicint getCount() {
		return count;
	}
	publicvoid setCount(int count) {
		this.count = count;
	}
	
	@XmlElement(name="employee")
	public List<Employee> getEmployees() {
		return employees;
	}
	publicvoid setEmployees(List<Employee> employees) {
		this.employees = employees;
	}
	
}

Согласование содержимого (content negotiation)

Другой общей чертой REST-сервисов является то, что они могут создавать различные представления в соответствии с запросом. Например, если клиент запрашивает представление всех сотрудников в виде HTML/text, сервер должен создать для пользователя надлежащим образом отформатированную HTML-страницу. Если клиент запрашивает представление всех сотрудников в виде application/XML, сервер должен выдать XML-результат. Другими популярными типами представлений являются ATOM и PDF.

В Spring 3 включен новый резолвер представления, именуемый ContentNegotiatingViewResolver. Он может переключать резолверы представлений в соответствии с типом содержимого запроса (свойство Accept в заголовке запроса) или суффиксом URI. В следующем примере ContentNegotiatingViewResolver используется для реализации поддержки нескольких представлений.

В файле rest-servlet.xml закомментируйте исходный viewResolver. Вместо него используйте ContentNegotiatingViewResolver, как показано в листинге 7.

Листинг 7. Определение согласования содержимого
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
	<map>
	<entry key="xml" value="application/xml"/>
	<entry key="html" value="text/html"/>
	</map>
</property>
<property name="viewResolvers">
	<list>
	<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
	<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
		<property name="viewClass" value=
		"org.springframework.web.servlet.view.JstlView"/>
		<property name="prefix" value="/WEB-INF/jsp/"/>
		<property name="suffix" value=".jsp"/>
	</bean>
	</list>
</property>
</bean>

Определение указывает на поддержку двух типов содержимого запроса: application/xml и text/html. Код также определяет два резолвера представления: BeanNameViewResolver для обработки application/xml и UrlBasedViewResolver для обработки text/html.

Если в браузере ввести http://<host>:<port>/<appcontext>/service/employees, для данных employees будет запрошен формат text/html. Затем вступит в силу UrlBasedViewResolver, и Spring в качестве представления выберет /WEB-INF/jsp/employees.jsp. Если добавить в заголовок запроса Accept:application/xml и выполнить запрос, вступит в силу BeanNameViewResolver. Согласно коду в листинге 5, он будет использовать представление под названием employees, – то есть представление, определенное в маршаллере JAXB 2.

Код контроллера для GetAllEmployees() не изменится. Для визуализации страница Employees.jsp будет использовать модель объекта с именем employees. В листинге 8 показан фрагмент кода для employees.jsp.

Листинг 8. employees.jsp в /WEB-INF/jsp
<table border=1>
	<thead><tr>
		<th>ID</th>
		<th>Name</th>
		<th>Email</th>
	</tr></thead>
	<c:forEach var="employee" items="${employees.employees}">
	<tr>
		<td>${employee.id}</td>
		<td>${employee.name}</td>
		<td>${employee.email}</td>
	</tr>
	</c:forEach>
</table>

Клиенты, взаимодействующие с REST-сервисами

Итак, мы создали простой RESTful Web-сервис, который поддерживает операции CRUD (create — создание, read — чтение, update — обновление, delete — удаление) для данных employees. В этом разделе рассказывается, как взаимодействовать с сервисом. Мы будем тестировать REST-сервисы при помощи curl.

Для тестирования REST-сервисов понадобится Firefox-плагин под названием RESTClient. Он прост в использовании и имеет хороший интерфейс. См. информацию о загрузке в разделе Ресурсы.

Использование curl

Curl - популярная утилита командной строки, позволяющая отправлять запросы на сервер по протоколам HTTP и HTTPS. Это удобный инструмент для взаимодействия с RESTful Web-сервисами, поскольку она позволяет отправлять содержимое при помощи любого HTTP-метода. В Linux® и Mac® Curl является встроенной. Для платформы Windows® ее можно загрузить (см. Ресурсы).

Чтобы выполнить первую команду curl для получения всех сотрудников, введите:

curl –HAccept:application/xml 

http://localhost:8080/rest/service/employees

Ответ в XML-представлении будет содержать всех сотрудников, как показано на рисунке 1.

Рисунок 1. XML-представление всех сотрудников
Рисунок 1. XML-представление всех сотрудников

Также можно ввести этот URL в браузере. В данном случае параметр Accept заголовка устанавливается в text/html, так что отобразится таблица, определенная в employees.jsp. На рисунке 2 показан пример.

Рисунок 2. XML-представление всех сотрудников
Рисунок 2. XML-представление всех сотрудников

Для добавления нового сотрудника на сервер при помощи метода POST используйте приведенный ниже код. Код addEmployee() в листинге 4 возьмет тело запроса и демаршаллизует его в объект Employee.

curl -X POST -HContent-type:application/xml --data
"<employee><id>3</id><name>guest</name><email>guest@ibm.com</employee>"
http://localhost:8080/rest/service/employee

Новый сотрудник добавлен. Можно проверить список сотрудников, повторив первый пример.

Метод PUT похож на метод POST.

curl -X PUT -HContent-type:application/xml --data
"<employee><id>3</id><name>guest3</name><email>guest3@ibm.com</employee>" 
http://localhost:8080/rest/service/employee/3

Этот код обновляет данные сотрудника с идентификатором 3.


Резюме

Теперь, когда инфраструктура Spring 3 поддерживает REST на своем MVC-уровне, можно использовать интерфейсы и аннотации Spring для создания Web-сервисов RESTful-стиля. В этой статье на примерах показано, как с помощью новых возможностей Spring 3 можно легко создавать Java RESTful Web-сервисы на стороне сервера.


Загрузка

ОписаниеИмяРазмер
Исходный код статьиsrc.zip9 КБ

Ресурсы

Научиться

  • Оригинал статьи Build RESTful web services using Spring 3 (EN).
  • Вводную информацию и ссылки на другие относящиеся к REST ссылки можно найти в Википедии.
  • Узнайте все о Spring 3.
  • Jersey: материалы для загрузки, архивы с примерами кода, руководство пользователя и документация по JAX-RS API. Jersey — это пригодная для производственного применения эталонная реализация с открытым исходным кодом (под двойной лицензией CDDL+GPL) JAX-RS (JSR 311) для создания Web-сервисов RESTful.
  • В статье Создание Web-сервиса RESTful при помощи Jersey и Apache Tomcat (DeveloperWorks, сентябрь 2009 года), написанной авторами данной статьи, рассказывается, как плавно перейти от сервиса в стиле сервлета к RESTful-сервису при помощи интеграции Jersey в Apache Tomcat (EN).
  • Узнайте больше о проекте JAXB Reference Implementation Project.

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Web-архитектура, SOA и web-сервисы
ArticleID=861568
ArticleTitle=Создаем Web-сервисы RESTful при помощи Spring 3
publish-date=03152013