«1. Обзор
Java API для веб-служб XML (JAX-WS) — это стандартизированный API для создания и использования веб-служб SOAP (Simple Object Access Protocol).
В этой статье мы создадим веб-службу SOAP и подключимся к ней с помощью JAX-WS.
2. SOAP
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.baeldung.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.baeldung.com/"
name="EmployeeService">
...
</definitions>
4.2. Типы
Элемент types определяет типы данных, используемые веб-службой. WSDL использует XSD (определение схемы XML) в качестве системы типов, которая способствует взаимодействию:
<definitions ...>
...
<types>
<xsd:schema>
<xsd:import namespace="http://jaxws.baeldung.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.baeldung.com/EmployeeService/getEmployeeRequest"
message="tns:getEmployee" />
<output
wsam:Action="http://jaxws.baeldung.com/EmployeeService/getEmployeeResponse"
message="tns:getEmployeeResponse" />
<fault message="tns:EmployeeNotFound" name="EmployeeNotFound"
wsam:Action="http://jaxws.baeldung.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. служащийservicetopdown.wsdl. Для простоты у него есть только один метод:
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://topdown.server.jaxws.baeldung.com/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http://topdown.server.jaxws.baeldung.com/"
qname="EmployeeServiceTopDown">
<types>
<xsd:schema
targetNamespace="http://topdown.server.jaxws.baeldung.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.baeldung.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.baeldung.jaxws.server.topdown employeeservicetopdown.wsdl
Используемые параметры командной строки: -p указывает целевой пакет. -s указывает, куда поместить сгенерированные исходные файлы.
Для более поздних версий JDK мы можем использовать jaxws-maven-plugin от MojoHaus, как описано здесь.
В качестве альтернативы может пригодиться плагин org.jvnet.jaxb2 maven-jaxb2-plugin, как подробно описано в разделе Вызов веб-службы SOAP в Spring.
Сгенерированные файлы:
-
EmployeeServiceTopDown.java — интерфейс конечной точки службы (SEI), который содержит определения методов ObjectFactory.java — содержит фабричные методы для программного создания экземпляров классов, производных от схемы, EmployeeServiceTopDown_Service.java — « — это класс поставщика услуг, который может использоваться клиентом JAX-WS
«5.2. Интерфейс конечной точки веб-службы
Инструмент wsimport сгенерировал интерфейс конечной точки веб-службы EmployeeServiceTopDown. Он объявляет методы веб-сервиса:
@WebService(
name = "EmployeeServiceTopDown",
targetNamespace = "http://topdown.server.jaxws.baeldung.com/")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({
ObjectFactory.class
})
public interface EmployeeServiceTopDown {
@WebMethod(
action = "http://topdown.server.jaxws.baeldung.com/"
+ "EmployeeServiceTopDown/countEmployees")
@WebResult(
name = "countEmployeesResponse",
targetNamespace = "http://topdown.server.jaxws.baeldung.com/",
partName = "parameters")
public int countEmployees();
}
5.3. Реализация веб-службы
Инструмент wsimport создал структуру веб-службы. Мы должны создать реализацию веб-сервиса:
@WebService(
name = "EmployeeServiceTopDown",
endpointInterface = "com.baeldung.jaxws.server.topdown.EmployeeServiceTopDown",
targetNamespace = "http://topdown.server.jaxws.baeldung.com/")
public class EmployeeServiceTopDownImpl
implements EmployeeServiceTopDown {
@Inject
private EmployeeRepository employeeRepositoryImpl;
@WebMethod
public int countEmployees() {
return employeeRepositoryImpl.count();
}
}
6. Подход «снизу вверх» (последний контракт)
В подходе «снизу вверх» мы должны создать как интерфейс конечной точки, так и классы реализации. . WSDL создается из классов при публикации веб-службы.
Давайте создадим веб-сервис, который будет выполнять простые CRUD-операции с данными сотрудников.
6.1. Класс модели
Класс модели Employee:
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.baeldung.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.baeldung.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.