Статьи

Богатый API веб-сервисов для вашей любимой платформы, часть 3: Struts

Целью этой серии практических рекомендаций является демонстрация разработки API-интерфейса с широкими возможностями веб-служб на различных популярных средах разработки. Часть 3 (это руководство) предназначена для Struts 2.

Мы собираемся использовать Enunciate для предоставления богатого API веб-сервиса для демонстрационного приложения Struts, включенного в дистрибутив Struts 2. При развертывании демонстрационного приложения вы заметите интерфейс менеджера сотрудника, который используется для демонстрации возможностей CRUD в Struts 2. Мы собираемся представить этот интерфейс через API веб-службы. К концу урока демонстрационное приложение будет включать следующее:

  • Конечные точки ОТДЫХА . Служба сотрудников и служба навыков будут доступны через конечные точки ресурса REST в форматах данных XML и JSON.
  • SOAP конечные точки . Сервисы будут представлены через SOAP и определены четко определенным и консолидированным WSDL.
  • Полная документация по API . API веб-сервиса будет полностью документирован.
  • Код на стороне клиента . Приложение предоставит клиентский код Java, который сможет удаленно обращаться к API веб-службы.

Излагают делает это потрясающе легко развивать этот вид услуг API Web: несколько незначительных настроек в файл проекта, файл конфигурации, и две простые услуги с некоторыми примечаниями применяются.

Шаг 1: настройка среды

Сначала убедитесь, что у вас установлен Maven , поскольку это инструмент сборки, который мы будем использовать для запуска демонстрационного приложения. Вам также понадобится Subversion, чтобы проверить витрину из исходного кода:


svn co
http://svn.apache.org/repos/asf/struts/struts2/tags/STRUTS_2_0_12/apps/showcase

Это извлечет приложение showcase в каталог showcase , который мы будем называть $ SHOWCASE_HOME . Теперь для запуска приложения:


CD-витрина

Mvn причал: взорвать взорвалась

Вы должны иметь возможность открыть браузер по адресу http: // localhost: 8080 / struts2-showcase, чтобы увидеть приложение витрины во всей его красе. Вы можете увидеть демонстрацию CRUD, перейдя по адресу http: // localhost: 8080 / struts2-showcase / empmanager / index.jsp .

Далее нам нужно интегрировать Enunciate с нашим проектом. Мы можем сделать это, добавив зависимость от Enunciate в наш файл pom.xml . Существует также конфликт версий библиотек Spring между Enunciate и демонстрацией Showcase, который необходимо разрешить явным объявлением версии 2.5.5 в зависимостях Spring. Мы также собираемся использовать CGLIB для некоторых перехватчиков Spring, поэтому мы также добавим зависимость от этого.

pom.xml

<dependencies>

<dependency>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>enunciate-rt</artifactId>
<version>1.8.1</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>2.5.5</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>2.5.5</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>2.5.5</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>2.5.5</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: Создайте конфигурацию

Вот файл конфигурации Enunciate, который Enunciate использует для предоставления API веб-службы для служб витрин. Удалите это в $ SHOWCASE_HOME (рядом с файлом pom.xml ). Давайте кратко рассмотрим основные части этого файла.

Элемент <api-classes> просто сообщает Enunciate, какие классы должны использоваться для определения API веб-службы. По умолчанию Enunciate предполагает, что все классы в проекте являются частью API веб-службы, но в витрине есть много других классов, которые используются для управления пользовательским интерфейсом и никогда не предназначались для определения API веб-службы, поэтому нам необходимо Расскажите Enunciate, что только классы в пакете org.apache.struts2.showcase.model и сервисные классы в пакете org.apache.struts2.showcase.dao используются для определения нашего API веб-сервиса:

...
<api-classes>
<include pattern="org.apache.struts2.showcase.model.*"/>
<include pattern="org.apache.struts2.showcase.dao.*Service"/>
</api-classes>
...

Баланс файла конфигурации используется для определения поведения в конкретном модуле Enunciate. Enunciate генерирует документацию нашего API веб-сервиса из JavaDocs наших классов API. Настраивая модуль docs , мы говорим Enunciate поместить документацию в каталог / api приложения и назначить заголовок документации.

Enunciate собирает API веб-службы в форме приложения Spring, и его необходимо объединить с демонстрационным приложением. Мы делаем это путем слияния сгенерированного Enunciate файла web.xml с файлом примеров web.xml и путем «импорта» определений bean-компонентов приложения-витрины с определениями bean-компонентов приложения Enunciate. Чтобы сделать это надежно, нам нужно (1) переместить файл web.xml в $ SHOWCASE_HOME (рядом с файлом pom.xml ) и (2) переименовать $ SHOWCASE_HOME / src / main / webapp / WEB-INF / applicationContext .xml в $ SHOWCASE_HOME / src / main / webapp / WEB-INF / struts-context.xml, Это гарантирует, что файлы, созданные Enunciate, не будут растоптаны существующими файлами.

...
<modules>
<docs docsDir="api" title="Struts 2 Example API"/>
<spring-app>
<war mergeWebXML="web.xml"/>

<springImport file="src/main/webapp/WEB-INF/struts-context.xml"/>
</spring-app>
</modules>
...


mv src / main / webapp / WEB-INF / web.xml.

mv src / main / webapp / WEB-INF / applicationContext.xml src / main / webapp / WEB-INF / struts-context.xml

 

Шаг 3: Создание сервисных интерфейсов

Если вы посмотрите в пакет org.apache.struts2.showcase.dao приложения-витрины, вы найдете набор DAO, которые Struts использует для предоставления данных в пользовательский интерфейс Employee Manager. Эти DAO не очень хорошо соответствуют спецификациям JAX-WS и JAX-RS , поэтому, вероятно, проще просто создать наши собственные сервисные интерфейсы, чтобы представить функциональность этих DAO в качестве конечных точек веб-службы.

Мы создадим класс EmployeeService и класс SkillService, и Spring предоставит им собственные экземпляры EmployeeDao и SkillDao , используя аннотацию org.springframework.beans.factory.annotation.Autowired . Затем для каждого сервиса мы предоставим метод get, метод create и метод delete . Затем мы применим некоторые метаданные, чтобы представить их как конечные точки веб-службы.

SOAP Метаданные

Чтобы представить интерфейс SOAP, нам просто нужно применить некоторые метаданные JAX-WS к нашим сервисам. На самом деле все, что нам нужно, это javax.jws.WebService, применяемый к каждому классу.

ОТДЫХ Метаданные

Конечно, мы также хотим применить интерфейс REST к нашему API. Это можно сделать, применив аннотации JAX-RS к нашим классам обслуживания, но это немного сложнее из-за дополнительных ограничений API REST.

Прежде всего необходимо сопоставить службу с путем URI, применив аннотацию @ javax.ws.rs.Path . Мы будем применять путь «/ employee» к конечной точке Employee и путь «/ skill» к конечной точке Skills.

Далее, поскольку вы ограничены ограниченным набором операций, вы должны аннотировать каждый конкретный метод, который должен быть включен в REST API. Вы должны указать (1) HTTP-метод, который используется для вызова метода, и (2) подпуть, который используется для его обнаружения. Мы сделаем это просто, предоставляя только методы get с помощью операции HTTP GET с помощью аннотации javax.ws.rs.GET и монтируя методы в «/ employee / {id}» и «/ skill / {name}». пути к конечной точке сотрудника и конечной точке навыков, соответственно, с использованием аннотации javax.ws.rs.Path . «{Id}» в пути будет указывать идентификатор сотрудника, которого мы хотим получитьи также для «{имя}» на пути к службе навыков. Это означает, что параметры метода должны быть аннотированы аннотацией @ javax.ws.rs.PathParam, которая также используется для указания имени каждого параметра пути.

Конечно, вы можете использовать другие методы, используя другие аннотации, но мы отошлем вас к документации JAX-RS, чтобы узнать, как это сделать.

Вот как выглядят наши сервисы (вы также можете скачать их здесь и здесь ):

EmployeeService.java

package org.apache.struts2.showcase.dao;

import org.apache.struts2.showcase.model.Employee;
import org.apache.struts2.showcase.exception.CreateException;
import org.springframework.beans.factory.annotation.Autowired;

import javax.jws.WebService;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.GET;

/**
* Service for employees.
*/
@WebService
@Path ("/employees")
public class EmployeeService {

@Autowired
private EmployeeDao dao;

/**
* Get the employee.
*
* @param id The id of the employee.
* @return The employee.
*/
@GET
@Path("/employee/{id}")
public Employee getEmployee(@PathParam("id") long id) {
return (Employee) this.dao.get(id);
}

/**
* Create an employee.
*
* @param employee The employee to create.
*/
public void createEmployee(Employee employee) {
try {
this.dao.create(employee);
}
catch (CreateException e) {
throw new RuntimeException(e);
}
}

/**
* Delete an employee.
*
* @param id Id of the employee to delete.
*/
public void deleteEmployee(long id) {
try {
this.dao.delete(id);
}
catch (CreateException e) {
throw new RuntimeException(e);
}
}
}

SkillService.java

package org.apache.struts2.showcase.dao;

import org.apache.struts2.showcase.model.Skill;
import org.apache.struts2.showcase.exception.CreateException;
import org.springframework.beans.factory.annotation.Autowired;

import javax.jws.WebService;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.PathParam;

/**
* Service for skills.
*/
@WebService
@Path("/skills")
public class SkillService {

@Autowired
private SkillDao dao;

/**
* Get the skill.
*
* @param name The name of the skill.
* @return The skill.
*/
@GET
@Path("/skill/{name}")
public Skill getSkill(@PathParam("name") String name) {
return (Skill) this.dao.get(name);
}

/**
* Create an skill.
*
* @param skill The skill to create.
*/
public void createSkill(Skill skill) {
try {
this.dao.create(skill);
}
catch (CreateException e) {
throw new RuntimeException(e);
}
}

/**
* Delete an skill.
*
* @param name Name of the skill to delete.
*/
public void deleteSkill(String name) {
try {
this.dao.delete(name);
}
catch (CreateException e) {
throw new RuntimeException(e);
}
}
}

Еще одна вещь необходима для предоставления REST API. Поскольку по умолчанию конечные точки REST будут предоставлять данные XML, мы должны предоставить корневые элементы XML для ответов XML. Для этого мы просто аннотируем классы org.apache.struts2.showcase.model.Employee и org.apache.struts2.showcase.model.Skill с помощью @ javax.xml.bind.annotation.XmlRootElement .

Нам также нужно аннотировать методы getId () в классах Employee и Skill с помощью @ javax.xml.bind.annotation.XmlTransient, поскольку Serializable не является допустимым типом XML.

Employee.java

@XmlRootElement
public class Employee {
...
@XmlTransient
public Serializable getId() {
return getName();
}
...
}

Skill.java

@XmlRootElement
public class Skill {
...
@XmlTransient
public Serializable getId() {
return getName();
}
...
}

 

Шаг 4: Построить и развернуть

Вернемся к командной строке:


мвн чистая пристань: взорвалась

 

Вот слава

Ваше приложение полностью функционально по адресу http: // localhost: 8080 / struts2-showcase / .

Ознакомьтесь с документацией для вашего нового API веб-службы по адресу http: // localhost: 8080 / struts2-showcase / api / (обратите внимание, что фильтр Struts добавляет верхний и нижний колонтитулы; вы можете исправить это, сузив фильтр, если хотите) :

Все задокументировано, снято с комментариев JavaDoc. Вот документация для SOAP API:

И документация для REST API:

И вы можете скачать клиентские библиотеки, которые генерируются Enunciate и могут использоваться для вызова вашего API веб-сервиса:

А как насчет вашего WSDL? HTTP: // локальный: 8080 / struts2-витрина / API / ns0.wsdl

А как насчет вашей XML-схемы? HTTP: // локальный: 8080 / struts2-витрина / API / ns1.xsd

Хотите увидеть свой API в действии? Ваши конечные точки SOAP монтируются в подконтексте / soap , а ваши конечные точки REST монтируются в подконтексте / rest . Чтобы просмотреть сотрудника, просто используйте путь, который мы определили с помощью аннотаций JAX-RS относительно подконтекста / rest . Поэтому для просмотра сотрудника, идентифицированного идентификатором «1», мы используем http: // localhost: 8080 / struts2-showcase / rest / employee / employee / employee : 1 :

Для удобства тот же ресурс XML также можно найти по адресу http: // localhost: 8080 / struts2-showcase / xml / employee / employee / 1 . И если вы хотите получить тот же ресурс, что и JSON, вы можете использовать http: // localhost: 8080 / struts2-showcase / json / employee / employee / employee .

И дальше …

Ну, вот как легко добавить API веб-сервиса в ваше приложение Struts. Но мы только слегка поцарапали поверхность того, что может сделать Enunciate. Как насчет всего этого:

  • Безопасность (HTTP Auth, OAuth, вход в систему на основе форм, управление сеансами и т. Д.)
  • Конечные точки GWT RPC и клиентский JavaScript для доступа к ним.
  • Конечные точки AMF и ActionScript на стороне клиента для доступа к ним.
  • Потоковый API для больших запросов.
  • И т.п.

На данный момент, это только вопрос конфигурации ….

Предыдущие части этого руководства доступны на JavaLobby.
Часть 1
была основана на Struts, а
часть 2 была
посвящена JBoss Seam. На следующей неделе мы рассмотрим калитку.