Целью этой серии практических рекомендаций является демонстрация разработки API-интерфейса с широкими возможностями веб-служб на различных популярных средах разработки. Часть 5 (это руководство) предназначена для Apache Tapestry. (Предыдущие части: весна , шов JBoss , Struts , калитка .)
Мы собираемся использовать Enunciate для предоставления богатого API веб-сервиса для демонстрации TimeTracker (также размещенной здесь ). К концу урока приложение TimeTracker будет включать следующее:
- Конечные точки ОТДЫХА . Конечные точки REST будут предоставлять ресурсы в форматах данных XML и JSON.
- SOAP конечные точки . API будет представлен через SOAP и определен четко определенным и объединенным WSDL.
- Полная документация по API . API веб-сервиса будет полностью документирован.
- Код на стороне клиента . Приложение предоставит клиентский код Java, который сможет удаленно обращаться к API веб-службы.
Излагают делает это потрясающе легко развивать этот вид услуг API Web: несколько незначительных настроек в файл сборки и web.xml файл, файл конфигурации, и пару конечных точек служб.
Шаг 1: настройка среды
Сначала убедитесь, что у вас установлен Maven , так как это инструмент сборки, который мы будем использовать для запуска демонстрации. Тогда посмотрите демоверсию из SVN:
svn co
http://svn.apache.org/repos/asf/tapestry/tapestry4/tags/4.1.6/tapestry-examples/TimeTracker
Приложение TimeTracker будет извлечено в каталог TimeTracker . Отныне этот каталог будет называться $ TIME_TRACKER_HOME . К сожалению, приложение все еще указывает на версию Tapestry SNAPSHOT , поэтому, прежде чем двигаться дальше, нам нужно отредактировать файл $ TIME_TRACKER_HOME / pom.xml, чтобы он указывал на версию Tapestry версии 4.1.6 (без снимка):
pom.xml
...
<parent>
<groupId>org.apache.tapestry</groupId>
<artifactId>tapestry-examples</artifactId>
<!--<version>4.1.6-SNAPSHOT</version>-->
<version>4.1.6</version>
</parent>
...
Как только это будет сделано, запустите приложение:
Mvn причал: взорвалась
Вы должны иметь возможность открыть браузер по адресу http: // localhost: 8080 / app, чтобы увидеть демо TimeTracker во всей его красе.
Далее нам нужно интегрировать Enunciate с нашим проектом. Мы можем сделать это, добавив зависимость от Enunciate в наш файл pom.xml . Кроме того, конечные точки службы, которые мы будем писать, нуждаются в cglib :
pom.xml
...
<dependencies>
<dependency>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>enunciate-rt</artifactId>
<version>1.8.1</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.1_3</version>
</dependency>
...
</dependencies>
...
И мы также добавляем maven-enunciate-plugin в список плагинов в нашем файле pom.xml :
pom.xml
...
<plugins>
...
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
<version>1.8.1</version>
<executions>
<execution>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
...
Теперь давайте добавим API веб-сервиса.
Шаг 2. Настройте дескриптор развертывания
Мы должны внести некоторые незначительные изменения в наш файл web.xml, чтобы освободить место для нашего API веб-службы. Сначала мы избавимся от раздела, который определяет и применяет Tapestry RedirectFilter . Этот раздел выглядит так, закомментировано:
web.xml
...
<!--<filter>-->
<!--<filter-name>redirect</filter-name>-->
<!--<filter-class>org.apache.tapestry.RedirectFilter</filter-class>-->
<!--</filter>-->
<!--<filter-mapping>-->
<!--<filter-name>redirect</filter-name>-->
<!--<url-pattern>/</url-pattern>-->
<!--</filter-mapping>-->
...
Теперь нам нужно применить HiveMindFilter к приложению, чтобы наши конечные точки могли получить доступ к компонентам, настроенным с помощью Tapestry.
web.xml
...
<filter>
<filter-name>HiveMind Filter</filter-name>
<filter-class>org.apache.hivemind.servlet.HiveMindFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiveMind Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
Наконец, файл web.xml должен перейти из $ TIME_TRACKER_HOME / src / context / WEB-INF / web.xml в $ TIME_TRACKER_HOME / web.xml . Это сделано для того, чтобы не перезаписывать файл web.xml , который в конечном итоге будет сгенерирован Enunciate.
mv src / context / WEB-INF / web.xml.
Вы можете скачать окончательный web.xml файл здесь |
Шаг 3: Создайте конфигурацию
Вот файл конфигурации Enunciate, который Enunciate использует для предоставления API веб-службы для службы TimeTracker. Удалите это в $ TIME_TRACKER_HOME (рядом с файлом pom.xml ). Давайте кратко рассмотрим основные части этого файла.
Элемент <api-classes> просто сообщает Enunciate, какие классы должны использоваться для определения API веб-службы. По умолчанию Enunciate предполагает, что все классы в проекте являются частью API веб-службы, но в демонстрационной версии TimeTracker есть много других классов, которые используются для управления пользовательским интерфейсом и которые никогда не предназначались для определения API веб-службы, поэтому мы должны сказать Enunciate, что только классы в пакетах org.apache.tapestry.timetracker.model и org.apache.tapestry.timetracker.ws используются для определения нашего API веб-службы:
...
<api-classes>
<include pattern="org.apache.tapestry.timetracker.model.*"/>
<include pattern="org.apache.tapestry.timetracker.ws.*"/>
</api-classes>
...
Баланс файла конфигурации используется для определения поведения в конкретном модуле Enunciate. Enunciate генерирует документацию нашего API веб-сервиса из JavaDocs наших классов API. Настраивая модуль docs , мы говорим Enunciate поместить документацию в каталог / api приложения и назначить заголовок документации.
Enunciate собирает API веб-службы в форме стандартного приложения сервлета J2EE, и его необходимо объединить с демонстрацией TimeTracker. Мы делаем это путем слияния излагают сгенерированный web.xml файл с TimeTracker web.xml файл.
...
<modules>
<docs docsDir="api" title="Time Tracker Example API"/>
<spring-app>
<war mergeWebXML="web.xml"/>
</spring-app>
</modules>
...
Шаг 4: Напишите конечные точки API
Давайте представим два сервиса: ProjectService и TaskService . Мы создадим новый пакет org.apache.tapestry.timetracker.ws, в который мы можем поместить наши новые классы служб с именами ProjectService.java и TaskService.java соответственно.
Для каждого сервиса мы напишем два метода: метод get, который получает проект или задачу по идентификатору, и метод list, который перечисляет все проекты или задачи.
SOAP Метаданные
Чтобы представить интерфейс SOAP, нам просто нужно применить некоторые метаданные JAX-WS к нашим классам обслуживания. На самом деле, все, что нам нужно сделать, это применить аннотацию @ javax.jws.WebService к каждому классу.
ОТДЫХ Метаданные
Конечно, мы также хотим применить интерфейс REST к нашему API. Это можно сделать, применив аннотации JAX-RS к нашим классам обслуживания, но это немного сложнее из-за дополнительных ограничений API REST.
Прежде всего необходимо сопоставить службу с путем URI, применив аннотацию @ javax.ws.rs.Path к классу службы. Мы будем монтировать ProjectService по пути «/ projects» и TaskService по пути «/ tasks».
Далее, поскольку вы ограничены ограниченным набором операций, вы должны аннотировать конкретные методы, которые должны быть включены в REST API. Вы должны указать (1) метод HTTP, который используется для вызова метода, и (2) подпуть, который используется для его обнаружения. Мы сделаем это просто, предоставляя только методы get с помощью операции HTTP GET с помощью аннотации javax.ws.rs.GET и монтируя метод в «/ project / {id}» и «/ task / {id}» пути, соответственно, используя аннотацию javax.ws.rs.Path . «{Id}» в пути будет указывать идентификатор проекта / задачи, который мы хотим получить . Это означает, что параметр метода должен быть аннотирован @ javax.ws.rs.PathParam аннотация, которая также используется для указания имени параметра пути.
Конечно, вы можете использовать другие методы, используя другие аннотации, но мы отошлем вас к документации JAX-RS, чтобы узнать, как это сделать.
Вот как выглядят наши классы, когда мы закончим:
ProjectService.java
package org.apache.tapestry.timetracker.ws;
import org.apache.tapestry.timetracker.model.Project;
import org.apache.tapestry.timetracker.dao.ProjectDao;
import org.apache.hivemind.Registry;
import org.apache.hivemind.servlet.HiveMindFilter;
import org.codehaus.enunciate.modules.spring_app.HTTPRequestContext;
import javax.jws.WebService;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.PathParam;
import java.util.List;
/**
* Service for retrieving and updating projects.
*/
@WebService
@Path ("/projects")
public class ProjectService {
/**
* Get a project by id.
*
* @param id The id of the project.
* @return The project id.
*/
@Path("/project/{id}")
@GET
public Project getProject(@PathParam ("id") long id) {
for (Project project : listProjects()) {
if (project.getId() == id) {
return project;
}
}
return null;
}
/**
* The list of projects.
*
* @return The list of projects.
*/
public List<Project> listProjects() {
ProjectDao dao = (ProjectDao) getRegistry().getService(ProjectDao.class);
return dao.list();
}
private Registry getRegistry() {
return HiveMindFilter.getRegistry(HTTPRequestContext.get().getRequest());
}
}
TaskService.java
package org.apache.tapestry.timetracker.ws;
import org.apache.tapestry.timetracker.model.Task;
import org.apache.tapestry.timetracker.dao.TaskDao;
import org.apache.hivemind.Registry;
import org.apache.hivemind.servlet.HiveMindFilter;
import org.codehaus.enunciate.modules.spring_app.HTTPRequestContext;
import javax.jws.WebService;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.PathParam;
import java.util.List;
/**
* Service for retrieving and updating tasks.
*/
@WebService
@Path ("/tasks")
public class TaskService {
/**
* Get a task by id.
*
* @param id The id of the task.
* @return The task id.
*/
@Path("/task/{id}")
@GET
public Task getTask(@PathParam ("id") long id) {
for (Task task : listTasks()) {
if (task.getId() == id) {
return task;
}
}
return null;
}
/**
* The list of tasks.
*
* @return The list of tasks.
*/
public List<Task> listTasks() {
TaskDao dao = (TaskDao) getRegistry().getService(TaskDao.class);
return dao.list();
}
private Registry getRegistry() {
return HiveMindFilter.getRegistry(HTTPRequestContext.get().getRequest());
}
}
Обратите внимание на частные методы getRegistry (), определенные для каждого сервиса. Это то, что позволяет нам получить доступ к контейнеру компонентов Tapestry, чтобы получить компоненты (DAO), которые поддерживают наши услуги. |
Эти два класса также можно скачать здесь и здесь . |
Последнее, что нужно сделать, прежде чем мы сможем развернуть наши сервисы. Службы возвращают экземпляры org.apache.tapestry.timetracker.model.Project и org.apache.tapestry.timetracker.model.Task , которые будут сериализованы в XML и JSON. Для этого нам нужно применить аннотацию javax.xml.bind.annotation.XmlRootElement к каждому из этих классов, чтобы JAXB знал, как их сериализовать и десериализовать:
Project.java
@XmlRootElement
public class Project implements Serializable, Persistent
{
...
}
Task.java
@XmlRootElement
public class Task implements Serializable, Persistent
{
...
}
Шаг 4: Построить и развернуть
Вернемся к командной строке:
мвн чистая пристань: взорвалась
Вот слава
Ваше приложение полностью функционально по адресу http: // localhost: 8080 / app .
Ознакомьтесь с документацией по вашему новому API веб-службы по адресу http: // localhost: 8080 / api / :
Все задокументировано, снято с комментариев JavaDoc. Вот документация для SOAP API:
И документация для REST API:
И вы можете скачать клиентские библиотеки, которые генерируются Enunciate и могут использоваться для вызова вашего API веб-сервиса:
А как насчет вашего WSDL? HTTP: // локальный: 8080 / API / ns0.wsdl
А как насчет вашей XML-схемы? HTTP: // локальный: 8080 / API / ns1.xsd
Хотите увидеть свой API в действии? Ваши конечные точки SOAP монтируются в подконтексте / soap , а ваши конечные точки REST монтируются в подконтексте / rest . Чтобы просмотреть проект, просто используйте путь, который мы определили в аннотациях JAX-RS относительно подконтекста / rest . Поэтому для просмотра проекта, идентифицируемого с помощью идентификатора «1», мы используем http: // localhost: 8080 / rest / projects / project / 1 :
Для удобства тот же ресурс XML также можно найти по адресу http: // localhost: 8080 / xml / projects / project / 1 . И если вы хотите получить тот же ресурс, что и JSON, вы можете использовать http: // localhost: 8080 / wicket-examples / json / projects / project / 1 .
И дальше …
Ну, вот как легко добавить API веб-сервиса в ваше приложение Wicket. Но мы только слегка поцарапали поверхность того, что может сделать Enunciate. Как насчет всего этого:
- Безопасность (HTTP Auth, OAuth, вход в систему на основе форм, управление сеансами и т. Д.)
- Конечные точки GWT RPC и клиентский JavaScript для доступа к ним.
- Конечные точки AMF и ActionScript на стороне клиента для доступа к ним.
- Потоковый API для больших запросов.
- И т.п.
На данный момент, это только вопрос конфигурации ….