Soap web service client in java

Вызов веб-службы SOAP в Java

Сначала мы создадим клиентский код с помощью утилиты wsimport, а затем протестируем его с помощью JUnit.

Для тех, кто только начинает, наше введение в JAX-WS предоставляет отличную информацию по этому вопросу.

2. Веб-сервис​

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

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

2.1. Резюме реализации​

Поскольку мы сосредоточены на создании клиента, мы не будем вдаваться в подробности реализации нашего сервиса.

Предположим, что интерфейс CountryService используется для представления веб-службы внешнему миру. Для простоты мы создадим и развернем веб-службу, используя API javax.xml.ws.Endpoint в нашем классе CountryServicePublisher .

Мы запустим CountryServicePublisher как приложение Java, чтобы опубликовать конечную точку, которая будет принимать входящие запросы. Другими словами, это будет наш сервер.

После запуска сервера переход по URL-адресу http://localhost:8888/ws/country?wsdl дает нам файл описания веб-службы. WSDL действует как руководство для понимания предложений службы и создания кода реализации для клиента.

2.2. Язык описания веб-сервисов​

Давайте посмотрим на WSDL нашего веб-сервиса, страна :

    definitions  namespace declarations -->   targetNamespace="http://server.ws.soap.foreach.com/" name="CountryServiceImplService">  types>   xsd:schema>   xsd:import namespace="http://server.ws.soap.foreach.com/"   schemaLocation="http://localhost:8888/ws/country?xsd=1">xsd:import>   xsd:schema>   types>   message name="findByName">   part name="arg0" type="xsd:string">part>   message>   message name="findByNameResponse">   part name="return" type="tns:country">part>   message>   portType name="CountryService">   operation name="findByName">   input wsam:Action="http://server.ws.soap.foreach.com/CountryService/findByNameRequest"   message="tns:findByName">input>   output wsam:Action="http://server.ws.soap.foreach.com/CountryService/findByNameResponse"   message="tns:findByNameResponse">output>   operation>   portType>   binding name="CountryServiceImplPortBinding" type="tns:CountryService">   soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc">soap:binding>   operation name="findByName">   soap:operation soapAction="">soap:operation>   input>   soap:body use="literal" namespace="http://server.ws.soap.foreach.com/">soap:body>   input>   output>   soap:body use="literal" namespace="http://server.ws.soap.foreach.com/">soap:body>   output>   operation>   binding>   service name="CountryServiceImplService">   port name="CountryServiceImplPort" binding="tns:CountryServiceImplPortBinding">   soap:address location="http://localhost:8888/ws/country">soap:address>   port>   service>   definitions> 

В двух словах, это полезная информация, которую он предоставляет:

  • Мы можем вызвать метод findByName со строковым аргументом.
  • В ответ сервис вернет нам пользовательский тип страны .
  • Типы определяются в схеме xsd , сгенерированной по адресу http://localhost:8888/ws/country?xsd=1 :
    xs:schema  namespace declarations -->   targetNamespace="http://server.ws.soap.foreach.com/">  xs:complexType name="country">   xs:sequence>   xs:element name="capital" type="xs:string" minOccurs="0">xs:element>   xs:element name="currency" type="tns:currency" minOccurs="0">xs:element>   xs:element name="name" type="xs:string" minOccurs="0">xs:element>   xs:element name="population" type="xs:int">xs:element>   xs:sequence>   xs:complexType>   xs:simpleType name="currency">   xs:restriction base="xs:string">   xs:enumeration value="EUR">xs:enumeration>   xs:enumeration value="INR">xs:enumeration>   xs:enumeration value="USD">xs:enumeration>   xs:restriction>   xs:simpleType>   xs:schema> 

Это все, что нам нужно для реализации клиента.

Давайте посмотрим, как в следующем разделе.

3. Использование wsimport для генерации клиентского кода​

3.1. Для JDK 8​

Во-первых, давайте посмотрим, как сгенерировать клиентский код с помощью JDK 8.

Для начала добавим в наш pom.xml плагин для использования этого инструмента через Maven:

 plugin>   groupId>org.codehaus.mojogroupId>   artifactId>jaxws-maven-pluginartifactId>   version>2.6version>   executions>   execution>   id>wsimport-from-jdkid>   goals>   goal>wsimportgoal>   goals>   execution>   executions>   configuration>   wsdlUrls>   wsdlUrl>http://localhost:8888/ws/country?wsdlwsdlUrl>   wsdlUrls>   keep>truekeep>   packageName>com.foreach.soap.ws.client.generatedpackageName>   sourceDestDir>src/main/javasourceDestDir>   configuration>   plugin> 

Во-вторых, давайте запустим этот плагин:

Это все! Приведенная выше команда сгенерирует код в указанном пакете com.foreach.soap.ws.client.generated внутри sourceDestDir , который мы указали в конфигурации плагина.

Другой способ добиться того же — использовать утилиту wsimport . Он поставляется из коробки со стандартным дистрибутивом JDK 8 и находится в каталоге JAVA_HOME/bin .

Чтобы сгенерировать клиентский код с помощью wsimport , мы можем перейти в корень проекта и выполнить эту команду:

 JAVA_HOME/bin/wsimport -s src/main/java/ -keep -p com.foreach.soap.ws.client.generated "http://localhost:8888/ws/country?wsdl" 

Важно помнить, что конечная точка службы должна быть доступна для успешного выполнения подключаемого модуля или команды.

3.2. Для JDK 11​

Начиная с JDK 11, wsimport был удален как часть JDK и больше не входит в стандартный дистрибутив.

Однако исходный код был открыт для фонда Eclipse.

Чтобы использовать wsimport для генерации клиентского кода для Java 11 и выше, нам нужно добавить зависимости jakarta.xml.ws-api , jaxws-rt и jaxws-ri в дополнение к jaxws-maven-plugin :

 dependencies>   dependency>   groupId>jakarta.xml.wsgroupId   >jakarta.xml.ws-apiartifactId   >3.0.0version>   dependency>   dependency>   groupId>com.sun.xml.wsgroupId>   artifactId>jaxws-rtartifactId>   version>3.0.0version   >runtimescope>   dependency>   dependency>   groupId>com.sun.xml.wsgroupId>   artifactId>jaxws-riartifactId>   version>2.3.1version   >pomtype>   dependency>   dependencies>   build>   plugins>   plugin>   groupId>com.sun.xml.wsgroupId>   artifactId>jaxws-maven-pluginartifactId>   version>2.3.2version>   configuration>   wsdlUrls>   wsdlUrl>http://localhost:8888/ws/country?wsdlwsdlUrl>   wsdlUrls>   keep>truekeep>   packageName>com.foreach.soap.ws.client.generatedpackageName>   sourceDestDir>src/main/javasourceDestDir>   configuration>   plugin>   plugins>   build> 

Теперь для генерации клиентского кода в пакете com.foreach.soap.ws.client.generated нам понадобится та же команда Maven, что и раньше:

Далее давайте посмотрим на сгенерированные артефакты, одинаковые для обеих версий Java.

3.3. Сгенерированные POJO​

На основе xsd , который мы видели ранее, инструмент сгенерирует файл с именем Country.java :

 @XmlAccessorType(XmlAccessType.FIELD)   @XmlType(name = "country", propOrder =  "capital", "currency", "name", "population" >)   public class Country    protected String capital;   @XmlSchemaType(name = "string")   protected Currency currency;   protected String name;   protected int population;   // standard getters and setters   > 

Как мы видим, сгенерированный класс украшен аннотациями JAXB для маршалинга и демаршаллинга объекта в XML и обратно.

Кроме того, он генерирует перечисление валюты :

 @XmlType(name = "currency")   @XmlEnum   public enum Currency    EUR, INR, USD;   public String value()    return name();   >   public static Currency fromValue(String v)    return valueOf(v);   >   > 

3.4. CountryService ​

Второй сгенерированный артефакт — это интерфейс, который действует как прокси для фактической веб-службы.

Интерфейс CountryService объявляет тот же метод, что и наш сервер, findByName :

 @WebService(name = "CountryService", targetNamespace = "http://server.ws.soap.foreach.com/")   @SOAPBinding(style = SOAPBinding.Style.RPC)   @XmlSeeAlso( ObjectFactory.class >)   public interface CountryService    @WebMethod   @WebResult(partName = "return")   @Action(input = "http://server.ws.soap.foreach.com/CountryService/findByNameRequest",   output = "http://server.ws.soap.foreach.com/CountryService/findByNameResponse")   public Country findByName(@WebParam(name = "arg0", partName = "arg0") String arg0);   > 

Примечательно, что интерфейс помечен как javax.jws.WebService с SOAPBinding.Style как RPC, как определено WSDL службы.

Метод findByName аннотирован, чтобы объявить, что это javax.jws.WebMethod с ожидаемыми типами входных и выходных параметров.

3.5. СтранаСервисИмплСервис ​

Наш следующий сгенерированный класс, CountryServiceImplService , расширяет javax.xml.ws.Service .

Его аннотация WebServiceClient означает, что это клиентское представление службы:

 @WebServiceClient(name = "CountryServiceImplService",   targetNamespace = "http://server.ws.soap.foreach.com/",   wsdlLocation = "http://localhost:8888/ws/country?wsdl")   public class CountryServiceImplService extends Service     private final static URL COUNTRYSERVICEIMPLSERVICE_WSDL_LOCATION;   private final static WebServiceException COUNTRYSERVICEIMPLSERVICE_EXCEPTION;   private final static QName COUNTRYSERVICEIMPLSERVICE_QNAME =   new QName("http://server.ws.soap.foreach.com/", "CountryServiceImplService");    static    URL url = null;   WebServiceException e = null;   try    url = new URL("http://localhost:8888/ws/country?wsdl");   > catch (MalformedURLException ex)    e = new WebServiceException(ex);   >   COUNTRYSERVICEIMPLSERVICE_WSDL_LOCATION = url;   COUNTRYSERVICEIMPLSERVICE_EXCEPTION = e;   >    public CountryServiceImplService()    super(__getWsdlLocation(), COUNTRYSERVICEIMPLSERVICE_QNAME);   >    // other constructors    @WebEndpoint(name = "CountryServiceImplPort")   public CountryService getCountryServiceImplPort()    return super.getPort(new QName("http://server.ws.soap.foreach.com/", "CountryServiceImplPort"),   CountryService.class);   >    private static URL __getWsdlLocation()    if (COUNTRYSERVICEIMPLSERVICE_EXCEPTION != null)    throw COUNTRYSERVICEIMPLSERVICE_EXCEPTION;   >   return COUNTRYSERVICEIMPLSERVICE_WSDL_LOCATION;   >    > 

Здесь важно отметить метод getCountryServiceImplPort . Учитывая полное имя конечной точки службы или QName и имя интерфейса конечной точки службы динамического прокси, он возвращает экземпляр прокси.

Чтобы вызвать веб-службу, нам нужно использовать этот прокси, как мы вскоре увидим.

Использование прокси создает впечатление, что мы вызываем службу локально, абстрагируясь от сложностей удаленного вызова.

4. Тестирование клиента​

Далее мы напишем тест JUnit для подключения к веб-службе с использованием сгенерированного клиентского кода.

Прежде чем мы сможем это сделать, нам нужно получить экземпляр прокси службы на стороне клиента:

 @BeforeClass   public static void setup()    CountryServiceImplService service = new CountryServiceImplService();   CountryService countryService = service.getCountryServiceImplPort();   > 

Для более сложных сценариев, таких как включение или отключение WebServiceFeature , мы можем использовать другие сгенерированные конструкторы для CountryServiceImplService .

Теперь давайте посмотрим на некоторые тесты:

 @Test   public void givenCountryService_whenCountryIndia_thenCapitalIsNewDelhi()    assertEquals("New Delhi", countryService.findByName("India").getCapital());   >    @Test   public void givenCountryService_whenCountryFrance_thenPopulationCorrect()    assertEquals(66710000, countryService.findByName("France").getPopulation());   >    @Test   public void givenCountryService_whenCountryUSA_thenCurrencyUSD()    assertEquals(Currency.USD, countryService.findByName("USA").getCurrency());   > 

Как мы видим, вызов методов удаленного сервиса стал таким же простым, как вызов методов локально. Метод findByName прокси- сервера вернул экземпляр Country , соответствующий предоставленному нами имени . Затем мы использовали различные геттеры POJO для утверждения ожидаемых значений.

5. Вывод​

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

В качестве альтернативы мы можем использовать другие реализации JAX-WS, такие как Apache CXF, Apache Axis2 и Spring, чтобы сделать то же самое.

Как всегда, исходный код доступен на GitHub для версий JDK 8 и JDK 11 .

Источник

Читайте также:  Call overridden method in java
Оцените статью