Клиент web-сервиса SOAP

Данная статья является продолжением описания WEB-сервиса SOAP. С общим описанием веб-сервисов (что это такое и какие типы веб-сервисов используются) можно познакомиться здесь. Создание и тестирование WEB-сервиса SOAP рассмотрено отдельно на практическом примере в среде разработки Eclipse. Для описания WEB-сервиса SOAP используется язык WSDL В этой статье на рабочем примере будем рассматривать вопрос создания клиента веб-сервисов SOAP. В качестве «подопытных» используем действующие на момент написания статьи два веб-сервиса.

Первый веб-сервис http://www.webservicex.net/uszip.asmx используем для получения почтовых значений ZIP районов города New York. На следующем скриншоте представлены методы WEB-сервиса, которые Вы можете увидеть при нажатии на ссылку. Используем второй по списку метод GetInfoByCity.

Второй веб-сервис BELAVIA включает метод получения списка аэропортов GetAirportsList и метод получения списка рейсов с информацией о вылете/прилёте и состоянии рейса GetTimeTable. По ссылке можно перейти на страницу описания веб-сервиса и посмотреть параметры методов web-сервиса BELAVIA, а также примеры запросов и ответов. В примере будем получать список аэропортов, используя метод GetAirportsList.

Примечание : если по указанным выше ссылкам можно открыть описания WEB-сервисов, то рассматриваемый на странице пример сможет выполнить запрос и получить ответ.

Структура сообщений SOAP

С WEB-сервисом SOAP «разговаривают на языке сообщений» определенного формата. Структура SOAP-сообщения состоит из оболочки, разделенной на две главные части: секция с описанием заголовка <soap:Header> и секция с телом сообщения <soap:Body>. Следующий код демонстрирует сообщение запроса списка аэропортов веб-сервиса BELAVIA.

<soap:Envelope 
     xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
     xmlns:ns="http://webservices.belavia.by">
    <soap:Header/>
    <soap:Body>
        <ns:GetAirportsList/>
    </soap:Body>
</soap:Envelope>

Оболочка сообщения (<soap:Envelope>) содержит элементы Header и Body, которые также, как и Envelope принадлежат пространству имен http://schemas.xmlsoap.org/soap/envelope/.

SOAPConnectionFactory - класс создания подключения и SOAP сообщения

Для работы с WEB-сервисом SOAP удобнее всего использовать SAAJ (SOAP with Attachments API for Java), который представляет программный интерфейс Java для сообщений SOAP. В пакет SAAJ включен класс SOAPConnection, который позволяет отправлять запросы веб-сервису. Объект подключения SOAPConnection создается с помощью SOAPConnectionFactory, который также используется и для создания SOAP сообщения (SOAPMessage). Следующий код демонстрирует создание SOAPConnection и SOAPMessage.

import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPPart;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPConnectionFactory;

...

SOAPConnectionFactory soapConnFactory;
SOAPConnection        soapConnection ;
MessageFactory        messageFactory ;
try {
    // Создание соединения
    soapConnFactory = SOAPConnectionFactory.newInstance();
    soapConnection  = soapConnFactory.createConnection();

    // Создание сообщения
    messageFactory = MessageFactory.newInstance();
    SOAPMessage message = messageFactory.createMessage();

    // Компоненты сообщения        
    SOAPPart     soapPart = message.getSOAPPart();
    SOAPEnvelope envelope = soapPart.getEnvelope();
    SOAPBody     body     = envelope.getBody();

    // Закрываем соединение
    soapConnection.close();

} catch(Exception e) {
    System.out.println(e.getMessage());
}

С помощью объекта MessageFactory создается объект сообщения SOAPMessage, у которого первоначально разделы envelope и header пусты. Объект SOAPPart содержит envelope, в который включается тело сообщения. Для формирования тела сообщения определяется ссылка SOAPBody.

SAAJ также позволяет напрямую создать объект SOAPPart-сообщения из внешнего файла. Так часто отправляемый запрос можно поместить в файл weather.msg, чтобы при необходимости его содержимое загружать в тело SOAP вместо ручного создания. Следующий код демонстрирует формирование тела SOAP сообщения с использованием потока ввода.

// Создание сообщения
messageFactory = MessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();

// Компоненты сообщения     
SOAPPart     soapPart = message.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPBody     body     = envelope.getBody();

// Формирование сообщения
StreamSource msgSrc;

FileInputStream fis = FileInputStream("weather.msg");
msgSrc = new StreamSource(fis);
soapPart.setContent(msgSrc);

//Сохранение сообщения
message.saveChanges();

Класс StreamSource открывает файловый поток ввода FileInputStream и читает готовое к отправке сообщение.

Пример клиента WEB-сервиса SOAP

Создадим простенький проект в Eclipse, структура которого представлена на следующем скриншоте. В проект включим библиотеку saaj.jar и класс SoapClientExample, который будет отправлять WEB-сервисам запросы и получать от них ответы. Проще проект и не представить, но какие возможности ... .

Библиотека saaj.jar позволяет использовать в клиенте web-сервиса SOAP программный интерфейс Java для сообщений SAAJ (SOAP with Attachments API for Java).

Структура класса SoapClientExample

SoapClientExample включает методы формирования SOAP сообщения (createSoapEnvelope, createSOAPRequest) и метод вызова веб-сервиса (callSoapWebService). Код методов представлен ниже. Переменные, определяющие параметры Web-сервиса и запроса, вынесены из методов и объявлены глобальными. Метод setSoapParams в зависимости от установленного флага belavia инициализирует параметры запроса одного из используемых web-сервисов.

package com.example;

import javax.xml.soap.*;

public class SoapClientExample
{
    private  boolean  belavia      = true;

    private  String   namespaceURI = null;
    private  String   soapUrl      = null;
    private  String   serviceName  = null;
    private  String   namespace    = null;
    private  String   soapAction   = null;

    public SoapClientExample()
    {
        setSoapParams();
        callSoapWebService(soapUrl, soapAction);
    }
    private void setSoapParams()
    {
        if (belavia) {
            namespaceURI = "http://webservices.belavia.by";
            soapUrl      = "http://86.57.245.235/TimeTable/Service.asmx";
            serviceName  = "GetAirportsList";  
        } else {
            namespaceURI = "http://www.webserviceX.NET";
            soapUrl      = "http://www.webservicex.net/uszip.asmx";
            serviceName  = "GetInfoByCity";
        }
        namespace  = "ns"; // namespace
        soapAction = namespaceURI + "/" + serviceName;
    }
    private void createSoapEnvelope(SOAPMessage soapMessage) throws SOAPException 
    {
         // код
    }
    private SOAPMessage createSOAPRequest(String soapAction) throws Exception
    {
         // код
    }
    private void callSoapWebService(String destination,
                                    String soapService) 
    {
         // код
    }
    public static void main(String[] args) 
    {
        new SoapClientExample();
        System.exit(0);
    }
}

Метод создания оболочки сообщения

Метод createSoapEnvelope формирует тело сообщения в зависимости от установленного флага belavia.

private void createSoapEnvelope(SOAPMessage soapMessage) 
                                throws SOAPException 
{
    SOAPPart soapPart = soapMessage.getSOAPPart();

    // SOAP Envelope
    SOAPEnvelope envelope = soapPart.getEnvelope();
    envelope.addNamespaceDeclaration(namespace, namespaceURI);

    // SOAP Body
    SOAPBody soapBody = envelope.getBody();
    SOAPElement soapBodyElem;
    SOAPElement soapBodyElem1;
    if (belavia) {
        soapBody.addChildElement(serviceName, namespace);
    } else {
        soapBodyElem =soapBody.addChildElement(serviceName, namespace);
        soapBodyElem1=soapBodyElem.addChildElement("USCity",namespace);
        soapBodyElem1.addTextNode("New York");
    }
}

Метод создания запроса к веб-сервису

Метод createSOAPRequest подготавливает SOAP сообщение и вызывает метод формирования тела сообщения createSoapEnvelope.

private SOAPMessage createSOAPRequest(String soapAction) 
                                     throws Exception
{
    MessageFactory messageFactory = MessageFactory.newInstance();
    SOAPMessage soapMessage = messageFactory.createMessage();

    createSoapEnvelope(soapMessage);

    MimeHeaders headers = soapMessage.getMimeHeaders();
    headers.addHeader("SOAPAction", soapAction);

    soapMessage.saveChanges();

    // Печать XML текста запроса
    System.out.println("Request SOAP Message:");
    soapMessage.writeTo(System.out);
    System.out.println("\n");

    return soapMessage;
}	

Метод вызова WEB-сервиса

Метод callSoapWebService используется для отправки запроса и получения ответа. Отправка сообщений SOAP и получение ответов выполняются за один шаг, т.е. синхронно. Сообщение отправляется в момент вызова метода call объекта SOAPConnection, который принимает в качестве аргументов адрес назначения и само сообщение. После этого соединение не закрывается и находится в ожидании ответа. В качестве ответа метод возвращает другой объект также типа SOAPMessage.

Вывод результата запроса выводится в консоль. Но поскольку полученный объект типа SOAPMessage, также является сообщением SOAP, то как и любое XML-сообщение, его можно трансформировать с помощью XSLT. SOAP позволяет выполнить XSLT-преобразование напрямую. В следующем листинге приводится метод printSOAPMessage, в котором выполняется данное преобразование.

Примечание :
1. XSLT (eXtensible Stylesheet Language Transformations) — это язык преобразования XML-документов. При применении таблицы стилей XSLT, состоящей из набора шаблонов, к XML-документу создается конечное дерево, которое может быть сериализовано в виде XML-документа.
2. Метод printSOAPMessage и флаг useXSLT не представлены в общей структуре класса SoapClientExample, поскольку в бо́льшей степени относятся к XML, чем к SOAP.

boolean useXSLT = true;
...
private void callSoapWebService(String destination,
                                String soapAction) 
{
    SOAPConnectionFactory soapFactory  = null;
    SOAPConnection        soapConnect  = null;
    SOAPMessage           soapRequest  = null;
    SOAPMessage           soapResponse = null;
    try {
        // Создание SOAP Connection
        soapFactory = SOAPConnectionFactory.newInstance();
        soapConnect = soapFactory.createConnection();

        // Создание SOAP Message для отправки
        soapRequest  = createSOAPRequest(soapAction);
        // Получение SOAP Message
        soapResponse = soapConnect.call(soapRequest, destination);

            // Печать SOAP Response
        if (!useXSLT) {
            System.out.println("Response SOAP Message:");
            soapResponse.writeTo(System.out);
            System.out.println();
        } else
            printSOAPMessage (soapResponse);

        soapConnect.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private void printSOAPMessage (SOAPMessage soapResponse)
{
    TransformerFactory transformerFactory;
    Transformer        transformer;
    try {
        // Создание XSLT-процессора
        transformerFactory = TransformerFactory.newInstance();
        transformer = transformerFactory.newTransformer();
        // Получение содержимого ответа
        Source content;
        content = soapResponse.getSOAPPart().getContent();
        // Определение выходного потока
        StreamResult result = new StreamResult(System.out);
        transformer.transform(content, result);
        System.out.println();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

При использовании XSLT в методе printSOAPMessage сначала создается объект Transformer. После этого определяется содержимое content типа javax.xml.transform.Source. Поскольку content выводится только в консоль (System.out), то таблица стилей не используется. При обработке можно выделить как оболочку, так и тело сообщения.

Тестирование примера

Программа выводит в консоль тексты SOAP сообщений как запроса, так и ответа.

Ниже представлен результат выполнения запроса к сервису получения ZIP значений города Нью-Йорка. Ответ представлен в виде массива данных (отображены только первые два и последний элементы массива).

Request SOAP Message:

<SOAP-ENV:Envelope 
       xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
       xmlns:ns="http://www.webserviceX.NET">
    <SOAP-ENV:Header/>
    <SOAP-ENV:Body>
        <ns:GetInfoByCity>
            <ns:USCity>New York</ns:USCity>
        </ns:GetInfoByCity>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
-----------------------------------------------------------
Response SOAP Message:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope 
        xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <GetInfoByCityResponse xmlns="http://www.webserviceX.NET">
            <GetInfoByCityResult>
                <NewDataSet xmlns="">
                    <Table>
                        <CITY>New York</CITY>
                        <STATE>NY</STATE>
                        <ZIP>10001</ZIP>
                        <AREA_CODE>212</AREA_CODE>
                        <TIME_ZONE>E</TIME_ZONE>
                    </Table>
                    <Table>
                        <CITY>New York</CITY>
                        <STATE>NY</STATE>
                        <ZIP>10002</ZIP>
                        <AREA_CODE>212</AREA_CODE>
                        <TIME_ZONE>E</TIME_ZONE>
                    </Table>
                    ...
                    <Table>
                        <CITY>New York</CITY>
                        <STATE>NY</STATE>
                        <ZIP>10292</ZIP>
                        <AREA_CODE>212</AREA_CODE>
                        <TIME_ZONE>E</TIME_ZONE>
                    </Table>
                </NewDataSet>
            </GetInfoByCityResult>
        </GetInfoByCityResponse>
    </soap:Body>
</soap:Envelope>
 

Ответ на запрос получения списка аэропортов также представлен в виде массива данных (отображены только четыре первых и последний элементы массива).


Request SOAP Message:

<SOAP-ENV:Envelope 
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:ns="http://webservices.belavia.by">
    <SOAP-ENV:Header/>
    <SOAP-ENV:Body>
        <ns:GetAirportsList/>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
-----------------------------------------------------------
Response SOAP Message:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope 
        xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <GetAirportsListResponse 
                      xmlns="http://webservices.belavia.by/">
            <GetAirportsListResult>
                <Airport IATA="ADB" Name="Izmir" />
                <Airport IATA="AER" Name="Sochi(Adler)" />
                <Airport IATA="ALA" Name="Almaty" />
                <Airport IATA="AMS" Name="Amsterdam" />
                . . .
                <Airport IATA="ZTH" Name="Zakynthos" />
            </GetAirportsListResult>
        </GetAirportsListResponse>
    </soap:Body>
</soap:Envelope>
 

Скачать пример

Исходный код примера в виде проекта Eclipse soap-client, включающий библиотеку saaj.jar, можно скачать здесь (23 Кб).

  Рейтинг@Mail.ru