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 .