Перейти к основному содержимому

Введение в JAX-WS

· 7 мин. чтения

1. Обзор

Java API для веб-служб XML (JAX-WS) — это стандартизированный API для создания и использования веб-служб SOAP (Simple Object Access Protocol).

В этой статье мы создадим веб-службу SOAP и подключимся к ней с помощью JAX-WS.

2. МЫЛО

SOAP — это спецификация XML для отправки сообщений по сети. Сообщения SOAP не зависят от какой-либо операционной системы и могут использовать различные протоколы связи, включая HTTP и SMTP.

SOAP тяжеловесен для XML, поэтому его лучше всего использовать с инструментами/фреймворками. JAX-WS — это фреймворк, упрощающий использование SOAP. Это часть стандартной Java.

3. Сверху вниз против снизу вверх

Существует два способа создания веб-служб SOAP. Мы можем использовать подход «сверху вниз» или подход «снизу вверх».

При подходе «сверху вниз» (сначала контракт) создается документ WSDL, а необходимые классы Java генерируются из WSDL. При подходе «снизу вверх» (последний контракт) классы Java записываются, а WSDL генерируется из классов Java.

Написание файла WSDL может быть довольно сложным в зависимости от сложности вашего веб-сервиса. Это делает подход «снизу вверх» более простым вариантом. С другой стороны, поскольку ваш WSDL генерируется из классов Java, любое изменение в коде может привести к изменению WSDL. Это не относится к нисходящему подходу.

В этой статье мы рассмотрим оба подхода.

4. Язык определения веб-сервисов (WSDL)

WSDL — это контрактное определение доступных сервисов. Это спецификация сообщений ввода/вывода и того, как вызывать веб-службу. Он не зависит от языка и определен в XML.

Давайте рассмотрим основные элементы документа WSDL.

4.1. Определения

Элемент определения является корневым элементом всех документов WSDL. Он определяет имя, пространство имен и т. д. сервиса и, как видите, может быть довольно просторным:

<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" 
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://jaxws.foreach.com/"
xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
xmlns:wsp="http://www.w3.org/ns/ws-policy"
xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://jaxws.foreach.com/"
name="EmployeeService">
...
</definitions>

4.2. Типы

Элемент types определяет типы данных, используемые веб-службой. WSDL использует XSD (определение схемы XML) в качестве системы типов, которая способствует взаимодействию:

<definitions ...>
...
<types>
<xsd:schema>
<xsd:import namespace="http://jaxws.foreach.com/"
schemaLocation = "http://localhost:8080/employeeservice?xsd=1" />
</xsd:schema>
</types>
...
</definitions>

4.3. Сообщения

Элемент сообщения обеспечивает абстрактное определение передаваемых данных. Каждый элемент сообщения описывает ввод или вывод метода службы и возможные исключения:

<definitions ...>
...
<message name="getEmployee">
<part name="parameters" element="tns:getEmployee" />
</message>
<message name="getEmployeeResponse">
<part name="parameters" element="tns:getEmployeeResponse" />
</message>
<message name="EmployeeNotFound">
<part name="fault" element="tns:EmployeeNotFound" />
</message>
...
</definitions>

4.4. Операции и типы портов

Элемент portType описывает каждую операцию , которая может быть выполнена, и все задействованные элементы сообщения . Например, операция getEmployee указывает ввод запроса , вывод и возможное исключение ошибки , выдаваемое операцией веб-службы :

<definitions ...>
...
<portType name="EmployeeService">
<operation name="getEmployee">
<input
wsam:Action="http://jaxws.foreach.com/EmployeeService/getEmployeeRequest"
message="tns:getEmployee" />
<output
wsam:Action="http://jaxws.foreach.com/EmployeeService/getEmployeeResponse"
message="tns:getEmployeeResponse" />
<fault message="tns:EmployeeNotFound" name="EmployeeNotFound"
wsam:Action="http://jaxws.foreach.com/EmployeeService/getEmployee/Fault/EmployeeNotFound" />
</operation>
....
</portType>
...
</definitions>

4.5. Привязки

Элемент привязки предоставляет сведения о протоколе и формате данных для каждого типа порта :

<definitions ...>
...
<binding name="EmployeeServiceImplPortBinding"
type="tns:EmployeeService">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="getEmployee">
<soap:operation soapAction="" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
<fault name="EmployeeNotFound">
<soap:fault name="EmployeeNotFound" use="literal" />
</fault>
</operation>
...
</binding>
...
</definitions>

4.6. Сервисы и порты

Элемент службы определяет порты, поддерживаемые веб-службой. Элемент port в сервисе определяет имя , привязку и адрес сервиса:

<definitions ...>
...
<service name="EmployeeService">
<port name="EmployeeServiceImplPort"
binding="tns:EmployeeServiceImplPortBinding">
<soap:address
location="http://localhost:8080/employeeservice" />
</port>
</service>
...
</definitions>

5. Подход «сверху вниз» (сначала контракт)

Начнем с нисходящего подхода, создав WSDL-файл employeeservicetopdown.wsdl. Для простоты он имеет только один метод:

<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://topdown.server.jaxws.foreach.com/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http://topdown.server.jaxws.foreach.com/"
qname="EmployeeServiceTopDown">
<types>
<xsd:schema
targetNamespace="http://topdown.server.jaxws.foreach.com/">
<xsd:element name="countEmployeesResponse" type="xsd:int"/>
</xsd:schema>
</types>

<message name="countEmployees">
</message>
<message name="countEmployeesResponse">
<part name="parameters" element="tns:countEmployeesResponse"/>
</message>
<portType name="EmployeeServiceTopDown">
<operation name="countEmployees">
<input message="tns:countEmployees"/>
<output message="tns:countEmployeesResponse"/>
</operation>
</portType>
<binding name="EmployeeServiceTopDownSOAP"
type="tns:EmployeeServiceTopDown">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document"/>
<operation name="countEmployees">
<soap:operation
soapAction="http://topdown.server.jaxws.foreach.com/
EmployeeServiceTopDown/countEmployees"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="EmployeeServiceTopDown">
<port name="EmployeeServiceTopDownSOAP"
binding="tns:EmployeeServiceTopDownSOAP">
<soap:address
location="http://localhost:8080/employeeservicetopdown"/>
</port>
</service>
</definitions>

5.1. Генерация исходных файлов веб-службы из WSDL

Существует несколько способов создания исходных файлов веб-службы из документа WSDL.

Один из способов — использовать инструмент wsimport , который является частью JDK (в $JAVA_HOME /bin) до версии JDK 8.

Из командной строки:

wsimport -s . -p com.foreach.jaxws.server.topdown employeeservicetopdown.wsdl

Используемые параметры командной строки: -p указывает целевой пакет. -s указывает, куда поместить сгенерированные исходные файлы.

Для более поздних версий JDK мы можем использовать jaxws-maven-plugin от MojoHaus, как описано здесь .

В качестве альтернативы может пригодиться maven- jaxb2 - plugin org.jvnet.jaxb2 , как подробно описано в разделе Вызов веб-службы SOAP в Spring .

Сгенерированные файлы:

  • EmployeeServiceTopDown.java — это интерфейс конечной точки службы (SEI), который содержит определения методов.
  • ObjectFactory.java — содержит фабричные методы для программного создания экземпляров классов, производных от схемы.
  • EmployeeServiceTopDown_Service.java — класс поставщика услуг, который может использоваться клиентом JAX-WS.

5.2. Интерфейс конечной точки веб-службы

Инструмент wsimport сгенерировал интерфейс конечной точки веб-службы EmployeeServiceTopDown . Он объявляет методы веб-сервиса:

@WebService(
name = "EmployeeServiceTopDown",
targetNamespace = "http://topdown.server.jaxws.foreach.com/")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({
ObjectFactory.class
})
public interface EmployeeServiceTopDown {
@WebMethod(
action = "http://topdown.server.jaxws.foreach.com/"
+ "EmployeeServiceTopDown/countEmployees")
@WebResult(
name = "countEmployeesResponse",
targetNamespace = "http://topdown.server.jaxws.foreach.com/",
partName = "parameters")
public int countEmployees();
}

5.3. Реализация веб-сервиса

Инструмент wsimport создал структуру веб-сервиса. Нам нужно создать реализацию веб-сервиса:

@WebService(
name = "EmployeeServiceTopDown",
endpointInterface = "com.foreach.jaxws.server.topdown.EmployeeServiceTopDown",
targetNamespace = "http://topdown.server.jaxws.foreach.com/")
public class EmployeeServiceTopDownImpl
implements EmployeeServiceTopDown {

@Inject
private EmployeeRepository employeeRepositoryImpl;

@WebMethod
public int countEmployees() {
return employeeRepositoryImpl.count();
}
}

6. Подход «снизу вверх» (последний контракт)

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

Давайте создадим веб-сервис, который будет выполнять простые операции CRUD с данными сотрудников .

6.1. Класс модели

Класс модели Сотрудник :

public class Employee {
private int id;
private String firstName;

// standard getters and setters
}

6.2. Интерфейс конечной точки веб-службы

Интерфейс конечной точки веб-службы, в котором объявляются методы веб-службы:

@WebService
public interface EmployeeService {
@WebMethod
Employee getEmployee(int id);

@WebMethod
Employee updateEmployee(int id, String name);

@WebMethod
boolean deleteEmployee(int id);

@WebMethod
Employee addEmployee(int id, String name);

// ...
}

Этот интерфейс определяет абстрактный контракт для веб-службы. Использованы аннотации:

  • @WebService означает, что это интерфейс веб-службы.
  • @WebMethod используется для настройки работы веб-службы.
  • @WebResult используется для настройки имени элемента XML, представляющего возвращаемое значение.

6.3. Реализация веб-сервиса

Класс реализации интерфейса конечной точки веб-службы:

@WebService(endpointInterface = "com.foreach.jaxws.EmployeeService")
public class EmployeeServiceImpl implements EmployeeService {

@Inject
private EmployeeRepository employeeRepositoryImpl;

@WebMethod
public Employee getEmployee(int id) {
return employeeRepositoryImpl.getEmployee(id);
}

@WebMethod
public Employee updateEmployee(int id, String name) {
return employeeRepositoryImpl.updateEmployee(id, name);
}

@WebMethod
public boolean deleteEmployee(int id) {
return employeeRepositoryImpl.deleteEmployee(id);
}

@WebMethod
public Employee addEmployee(int id, String name) {
return employeeRepositoryImpl.addEmployee(id, name);
}

// ...
}

7. Публикация конечных точек веб-службы

Чтобы опубликовать веб-службы (сверху вниз и снизу вверх), нам нужно передать адрес и экземпляр реализации веб-службы методу publish() класса javax.xml.ws.Endpoint :

public class EmployeeServicePublisher {
public static void main(String[] args) {
Endpoint.publish(
"http://localhost:8080/employeeservicetopdown",
new EmployeeServiceTopDownImpl());

Endpoint.publish("http://localhost:8080/employeeservice",
new EmployeeServiceImpl());
}
}

Теперь мы можем запустить EmployeeServicePublisher , чтобы запустить веб-службу. Чтобы использовать функции CDI, веб-службы можно развернуть в виде файла WAR на серверах приложений, таких как WildFly или GlassFish.

8. Клиент удаленной веб-службы

Давайте теперь создадим клиент JAX-WS для удаленного подключения к веб-службе EmployeeService .

8.1. Создание клиентских артефактов

Чтобы сгенерировать клиентские артефакты JAX-WS, мы снова можем использовать инструмент wsimport :

wsimport -keep -p com.foreach.jaxws.client http://localhost:8080/employeeservice?wsdl

Сгенерированный класс EmployeeService_Service инкапсулирует логику для получения порта сервера с использованием URL и QName .

8.2. Подключение к веб-сервису

Клиент веб-службы использует сгенерированный EmployeeService_Service для подключения к серверу и удаленного вызова веб-службы:

public class EmployeeServiceClient {
public static void main(String[] args) throws Exception {
URL url = new URL("http://localhost:8080/employeeservice?wsdl");

EmployeeService_Service employeeService_Service
= new EmployeeService_Service(url);
EmployeeService employeeServiceProxy
= employeeService_Service.getEmployeeServiceImplPort();

List<Employee> allEmployees
= employeeServiceProxy.getAllEmployees();
}
}

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

Эта статья представляет собой краткое введение в веб-службы SOAP с использованием JAX-WS .

Мы использовали как восходящий, так и нисходящий подходы к созданию веб-служб SOAP с использованием JAX-WS API. Мы также написали клиент JAX-WS, который может удаленно подключаться к серверу и выполнять вызовы веб-службы.

Полный исходный код доступен на GitHub .