В прошлом посте мы начали рассказывать о разработке на платформе WSO2 и сделали REST API-сервис. Сегодня мы продолжаем тему: в этом посте поделюсь с вами тем, как мы в WSO2 создаем SOAP-сервисы. В этом посте я делаю акцент на различиях, поэтому на случай каких-то общих вопросов можете параллельно открыть пост про REST API.

В WSO2 Integration Studio создаем новый проект (File – New – Integration Project). Назовем его, например, Rosstat Service. Не забываем создать RegistryResources, поскольку SOAP-сервис в любом случае предусматривает WSDL/XSD, а их нужно где-то хранить

Добавляем в каждый из отмеченных каталогов пустой файл с именем «.gitkeep» для контроля версий:

Далее настраиваем остальные параметры в зависимости от проекта. Все ссылки репозитория WSO2 Nexus во всех файлах «pom.xml» меняем на ваши собственные. У нас, соответственно, https://maven.wso2.org/nexus/content/groups/wso2-public/ меняется на https://nexus.gts.rus.socgen/repository/maven-wso2-public/.
Создаем шаблоны
Создадим шаблон для вызова внешнего сервиса CallAPI.

В типе шаблона нужно выбрать Sequence Template. С точки зрения кода шаблон будет таким же, как и при создании REST API-сервиса, поскольку мы принимаем SOAP, а вызываем REST:
<template name="MOEX_callAPI_Template" xmlns="http://ws.apache.org/ns/synapse"> <parameter defaultValue="" isMandatory="false" name="setCallEndpointName"/> <parameter defaultValue="" isMandatory="false" name="setEndpointURL"/> <parameter defaultValue="" isMandatory="false" name="setEndpointURL_Suffix"/> <parameter defaultValue="" isMandatory="false" name="setQueryParams"/> <sequence> <property expression="get-property('file', $func:setEndpointURL)" name="ENV_ENDPOINT_URL" scope="default" type="STRING"/> <filter regex="true" source="boolean($ctx:ENV_ENDPOINT_URL) and string-length($ctx:ENV_ENDPOINT_URL) > 0"> <then/> <else> <property expression="get-property('env', $func:setEndpointURL)" name="ENV_ENDPOINT_URL" scope="default" type="STRING"/> </else> </filter> <switch source="boolean($func:setQueryParams) and string-length($func:setQueryParams) > 0"> <case regex="true"> <property expression="fn:concat($ctx:ENV_ENDPOINT_URL, $func:setEndpointURL_Suffix, '?', $func:setQueryParams)" name="uri.var.endpointURL_FullAddress" scope="default" type="STRING"/> </case> <default> <property expression="fn:concat($ctx:ENV_ENDPOINT_URL, $func:setEndpointURL_Suffix)" name="uri.var.endpointURL_FullAddress" scope="default" type="STRING"/> </default> </switch> <class description="OutReqLoggerTXT" name="ru.rosbank.mediator.LoggerMediatorTXT"> <property name="logLevel" value="DEBUG"/> <property name="ReqType" value="OutRequest"/> <property expression="fn:concat('sending request to endpointURL_FullAddress=', $ctx:uri.var.endpointURL_FullAddress)" name="Payload"/> </class> <call> <endpoint key-expression="$func:setCallEndpointName"/> </call> </sequence> </template>
Теперь создаем шаблон для обработки ошибок SOAPFault. Здесь нужно обратить внимание, какая версия протокола SOAP используется, 1.1 или 1.2. От этого будут зависеть некоторые параметры формирования ошибки, в частности, различаться ContentType. Вот код обработчика для SOAP 1.1:
<template name="Rosstat_SOAPFault_Template" xmlns="http://ws.apache.org/ns/synapse"> <parameter defaultValue="" isMandatory="false" name="MessageID"/> <parameter defaultValue="" isMandatory="false" name="ErrorText"/> <parameter defaultValue="" isMandatory="false" name="Exception"/> <sequence> <payloadFactory description="ExceptionPayload" media-type="xml"> <format> <m:Exception xmlns:m="http://wso2.rosbank.ru/types/Fault"> <msgID xmlns="">$1</msgID> <text xmlns="">$2</text> <exception xmlns="">$3</exception> </m:Exception> </format> <args> <arg evaluator="xml" expression="$func:MessageID"/> <arg evaluator="xml" expression="$func:ErrorText"/> <arg evaluator="xml" expression="$func:Exception"/> </args> </payloadFactory> <enrich description="body to property"> <source clone="true" type="body"/> <target property="MESSAGE_PAYLOAD" type="property"/> </enrich> <makefault description="SoapFault" version="soap11"> <code value="soap11Env:Server" xmlns:soap11Env="http://schemas.xmlsoap.org/soap/envelope/"/> <reason value="Error message processing"/> <detail expression="get-property('MESSAGE_PAYLOAD')"/> </makefault> <propertyGroup description="removeHeaders"> <property action="remove" name="TRANSPORT_HEADERS" scope="axis2"/> <property action="remove" name="EXCESS_TRANSPORT_HEADERS" scope="axis2"/> </propertyGroup> <propertyGroup description="setHeaders"> <property name="HTTP_SC" scope="axis2" type="STRING" value="500"/> <property name="HTTP_SC_DESC" scope="axis2" type="STRING" value="Internal Server Error"/> <property name="MESSAGE_FORMAT" scope="default" type="STRING" value="soap11"/> <property name="messageType" scope="axis2" type="STRING" value="text/xml"/> <property name="ContentType" scope="axis2" type="STRING" value="text/xml"/> <property name="Content-Type" scope="transport" type="STRING" value="text/xml;charset=UTF-8"/> <property name="RESPONSE" scope="default" type="STRING" value="true"/> </propertyGroup> </sequence> </template>
При возникновении ошибки этот обработчик передает XML-сообщение с уникальным id, по которому можно будет легко ее найти в логах. Также не забудьте проставить свою версию SOAP для SOAPFault: description="SoapFault" version="soap11".
А вот код обработчика для SOAP 1.2:
<template name="Rosstat_SOAPFault_Template" xmlns="http://ws.apache.org/ns/synapse"> <parameter defaultValue="" isMandatory="false" name="MessageID"/> <parameter defaultValue="" isMandatory="false" name="ErrorText"/> <parameter defaultValue="" isMandatory="false" name="Exception"/> <sequence> <payloadFactory description="ExceptionPayload" media-type="xml"> <format> <m:Exception xmlns:m="http://wso2.rosbank.ru/types/Fault"> <msgID xmlns="">$1</msgID> <text xmlns="">$2</text> <exception xmlns="">$3</exception> </m:Exception> </format> <args> <arg evaluator="xml" expression="$func:MessageID"/> <arg evaluator="xml" expression="$func:ErrorText"/> <arg evaluator="xml" expression="$func:Exception"/> </args> </payloadFactory> <enrich description="body to property"> <source clone="true" type="body"/> <target property="MESSAGE_PAYLOAD" type="property"/> </enrich> <makefault description="SoapFault" version="soap12"> <code value="soap12Env:Receiver" xmlns:soap12Env="http://www.w3.org/2003/05/soap-envelope"/> <reason value="Error message processing"/> <detail expression="get-property('MESSAGE_PAYLOAD')"/> </makefault> <propertyGroup description="removeHeaders"> <property action="remove" name="TRANSPORT_HEADERS" scope="axis2"/> <property action="remove" name="EXCESS_TRANSPORT_HEADERS" scope="axis2"/> </propertyGroup> <propertyGroup description="setHeaders"> <property name="HTTP_SC" scope="axis2" type="STRING" value="500"/> <property name="HTTP_SC_DESC" scope="axis2" type="STRING" value="Internal Server Error"/> <property name="MESSAGE_FORMAT" scope="default" type="STRING" value="soap12"/> <property name="messageType" scope="axis2" type="STRING" value="application/soap+xml"/> <property name="ContentType" scope="axis2" type="STRING" value="application/soap+xml"/> <property name="Content-Type" scope="transport" type="STRING" value="application/soap+xml;charset=UTF-8"/> <property name="RESPONSE" scope="default" type="STRING" value="true"/> </propertyGroup> </sequence> </template>
Создаем обработчики
Теперь создаем общие шаги — Sequence — для обработки входящих ошибок:

FaultSequence перехватывает исключения, которые могут произойти при обработке запроса, и вызывает шаблон SOAPFault, который мы только что сделали:

Создадим обработчик Inbound для приема входящих запросов:
<sequence name="Rosstat_InboundSequence" onError="Rosstat_FaultSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse"> <propertyGroup description="setProperty"> <property name="ENV_SERVICE_NAME" scope="default" type="STRING" value="RosstatService"/> <property expression="$axis2:TransportInURL" name="ENV_REST_URL_POSTFIX" scope="default" type="STRING"/> <property expression="fn:substring-after(get-property('MessageID'), 'uuid:')" name="ENV_MESSAGE_ID" scope="default" type="STRING"/> <property expression="local-name(//soapenv:Envelope/soapenv:Body/*[1])" name="ENV_METHOD_NAME" scope="default" type="STRING" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"/> <property expression="fn:substring-after($axis2:TransportInURL, '?')" name="ENV_QUERY_PARAMS" scope="default" type="STRING"/> <property expression="string('')" name="ENV_EMPTY_STRING" scope="default" type="STRING"/> <property expression="$axis2:REMOTE_ADDR" name="ENV_IP_ADDRESS" scope="default" type="STRING"/> </propertyGroup> <class description="InReqLoggerTXT" name="ru.rosbank.mediator.LoggerMediatorTXT"> <property name="logLevel" value="DEBUG"/> <property name="ReqType" value="Begin"/> <property name="Payload" value="Request accepted..."/> </class> </sequence>
В параметре ENV_SERVICE_NAME указываем название сервиса. Это же имя будет использоваться в LoggerService для записи логов в отдельный файл. В параметре «onError» здесь и далее в инструкции указываем ссылку на ранее созданный обработчик ошибок: onError="Rosstat_FaultSequence".
Здесь есть небольшие отличия от REST. Сгенирировав uuid, мы идем в SOAP Envelope – Body и оттуда получаем название метода. В протоколе SOAP название метода передается именно в теле.
Теперь сделаем Outbound — обработчик, который будет заносить в лог факт обработки запроса.
<sequence name="Rosstat_OutboundSequence" onError="Rosstat_FaultSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse"> <class description="InResLoggerTXT" name="ru.rosbank.mediator.LoggerMediatorTXT"> <property name="logLevel" value="DEBUG"/> <property name="ReqType" value="End"/> <property name="Payload" value="Request processed success"/> </class> </sequence>
И наконец, новый обработчик, которого не было в REST API. UnsupportedSequence используется для обработки ошибки, когда метод был объявлен в WSDL, но не был реализован (или мы сами не хотим его выставлять).

Здесь тоже используется шаблон SOAPFault. В сообщении ошибки мы выдаем «Unsupported service»:
<sequence name="Rosstat_UnsupportedService_Sequence" onError="Rosstat_FaultSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse"> <class description="InReqLoggerSOAP" name="ru.rosbank.mediator.LoggerMediatorSOAP"> <property name="logLevel" value="INFO"/> <property name="ReqType" value="InRequest"/> <property name="isLogHeader" value="true"/> <property name="isLogPayload" value="true"/> </class> <call-template description="SoapFault" target="Rosstat_SOAPFault_Template"> <with-param name="MessageID" value="{$ctx:ENV_MESSAGE_ID}"/> <with-param name="ErrorText" value="Unsupported service"/> <with-param name="Exception" value="{$ctx:ENV_EMPTY_STRING}"/> </call-template> <class description="InResLoggerSOAP" name="ru.rosbank.mediator.LoggerMediatorSOAP"> <property name="logLevel" value="INFO"/> <property name="ReqType" value="InResponse"/> <property name="isLogHeader" value="true"/> <property name="isLogPayload" value="true"/> </class> </sequence>
Еще один обработчик, которого не было в REST API — обработчик конкретного метода (операции) GetOrganizationInfo. В REST API мы это делали на уровне API с помощью <resource>, здесь это устроено иначе.

Логируем запрос, вызываем HTPP-сервис и логируем ответ:
<sequence name="Rosstat_GetOrganizationInfo_Sequence" onError="Rosstat_FaultSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse"> <class description="InReqLoggerSOAP" name="ru.rosbank.mediator.LoggerMediatorSOAP"> <property name="logLevel" value="INFO"/> <property name="ReqType" value="InRequest"/> <property name="isLogHeader" value="true"/> <property name="isLogPayload" value="true"/> </class> <sequence key="Rosstat_GetOrganizationInfo_HTTPRequest_Sequence"/> <class description="InResLoggerSOAP" name="ru.rosbank.mediator.LoggerMediatorSOAP"> <property name="logLevel" value="INFO"/> <property name="ReqType" value="InResponse"/> <property name="isLogHeader" value="true"/> <property name="isLogPayload" value="true"/> </class> </sequence>
Теперь нам нужно создать обработчик запросов.

Здесь мы удаляем все транспортные заголовки, превращаем SOAP в JSON, задаем формат из трех полей и ContentType, логируем запрос, вызываем CallTemplate и проверяем, что вернулся код 200. Если да, то мы вызываем sequence для обратной трансформации, если нет — логируем ошибку, вызываем шаблон SOAPfault:
<sequence name="Rosstat_GetOrganizationInfo_HTTPRequest_Sequence" onError="Rosstat_FaultSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse"> <propertyGroup description="removeHeaders"> <property action="remove" name="TRANSPORT_HEADERS" scope="axis2"/> <property action="remove" name="EXCESS_TRANSPORT_HEADERS" scope="axis2"/> </propertyGroup> <payloadFactory description="MappingIn" media-type="json"> <format>{"okpo":"$1", "inn":"$2", "ogrn":"$3"}</format> <args> <arg evaluator="xml" expression="//p:okpo/text()" xmlns:p="http://ru.rosbank.servicemix/cd/client"/> <arg evaluator="xml" expression="//p:inn/text()" xmlns:p="http://ru.rosbank.servicemix/cd/client"/> <arg evaluator="xml" expression="//p:ogrn/text()" xmlns:p="http://ru.rosbank.servicemix/cd/client"/> </args> </payloadFactory> <propertyGroup description="setHeader"> <property name="messageType" scope="axis2" type="STRING" value="application/json"/> </propertyGroup> <class description="OutReqLoggerJSON" name="ru.rosbank.mediator.LoggerMediatorJSON"> <property name="logLevel" value="INFO"/> <property name="ReqType" value="OutRequest"/> <property name="isLogHeader" value="true"/> <property name="isLogPayload" value="true"/> </class> <call-template description="callRosstat" onError="Rosstat_FaultSequence" target="Rosstat_callAPI_Template"> <with-param name="setCallEndpointName" value="Rosstat_GetOrganizationInfo_EP"/> <with-param name="setEndpointURL" value="webServiceURL_GetRosstatOrganizationInfo"/> <with-param name="setEndpointURL_Suffix" value=""/> <with-param name="setQueryParams" value=""/> </call-template> <filter regex="200" source="$axis2:HTTP_SC"> <then> <class description="OutResLoggerJSON" name="ru.rosbank.mediator.LoggerMediatorJSON"> <property name="logLevel" value="INFO"/> <property name="ReqType" value="OutResponse"/> <property name="isLogHeader" value="true"/> <property name="isLogPayload" value="true"/> </class> <sequence key="Rosstat_GetOrganizationInfo_MappingOUT_Sequence"/> </then> <else> <class description="OutResLoggerBINARY" name="ru.rosbank.mediator.LoggerMediatorBINARY"> <property name="logLevel" value="INFO"/> <property name="ReqType" value="OutResponse"/> <property name="isLogHeader" value="true"/> <property name="isLogPayload" value="true"/> </class> <call-template description="SoapFault" target="Rosstat_SOAPFault_Template"> <with-param name="MessageID" value="{$ctx:ENV_MESSAGE_ID}"/> <with-param name="ErrorText" value="GetOrganizationInfo returns non success response"/> <with-param name="Exception" value="{fn:concat('Error: ', $axis2:HTTP_SC, ' - ', $axis2:HTTP_SC_DESC)}"/> </call-template> </else> </filter> </sequence>
Следующий шаг — MappingOUT — обратная трансформация из JSON в SOAP:

Здесь мы сохраняем в локальные переменные из JSON интересные нам id, type и name и генерируем payload для xml-ки SOAPResponse:
<sequence name="Rosstat_GetOrganizationInfo_MappingOUT_Sequence" onError="Rosstat_FaultSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse"> <propertyGroup description="Group of properties that extract data from response"> <property expression="json-eval($.[0].id)" name="id" scope="default" type="STRING"/> <property expression="json-eval($.[0].type)" name="type" scope="default" type="STRING"/> <property expression="json-eval($.[0].name)" name="name" scope="default" type="STRING"/> <!-- остальные параметры протокола обмена удалены, для упрощения чтения --> </propertyGroup> <payloadFactory description="SOAPResponse" media-type="xml"> <format> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <p:RosstatOrganizationInfoResponse xmlns:p="http://ru.rosbank.servicemix/cd/client"> <p:id>$1</p:id> <p:type>$2</p:type> <p:name>$3</p:name> </p:RosstatOrganizationInfoResponse> </soapenv:Body> </soapenv:Envelope> </format> <args> <arg evaluator="xml" expression="get-property('id')"/> <arg evaluator="xml" expression="get-property('type')"/> <arg evaluator="xml" expression="get-property('name')"/> </args> </payloadFactory> <propertyGroup description="removeHeaders"> <property action="remove" name="TRANSPORT_HEADERS" scope="axis2"/> <property action="remove" name="EXCESS_TRANSPORT_HEADERS" scope="axis2"/> </propertyGroup> <propertyGroup description="setHeaders"> <property name="HTTP_SC" scope="axis2" type="STRING" value="200"/> <property name="HTTP_SC_DESC" scope="axis2" type="STRING" value="OK"/> <property name="MESSAGE_FORMAT" scope="default" type="STRING" value="soap11"/> <property name="messageType" scope="axis2" type="STRING" value="text/xml"/> <property name="ContentType" scope="axis2" type="STRING" value="text/xml"/> <property name="Content-Type" scope="transport" type="STRING" value="text/xml;charset=UTF-8"/> <property name="RESPONSE" scope="default" type="STRING" value="true"/> </propertyGroup> </sequence>
Конечно, удаляем все ненужные транспортные заголовки из REST API, как и в прошлом случае.
Обязательно нужно сделать и последовательность для HealthCheck — проверку готовности сервиса принимать траффик (Readness Probe). Он пригодится, когда мы будем деплоить всё в Kubernetes или OpenShift.

<sequence name="Rosstat_HealthRequest_Sequence" onError="Rosstat_FaultSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse"> <propertyGroup description="removeHeaders"> <property action="remove" name="TRANSPORT_HEADERS" scope="axis2"/> <property action="remove" name="EXCESS_TRANSPORT_HEADERS" scope="axis2"/> </propertyGroup> <payloadFactory description="SOAPResponse" media-type="xml"> <format> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <p:HealthResponse xmlns:p="http://ru.rosbank.servicemix/cd/client"> <p:status>OK</p:status> </p:HealthResponse> </soapenv:Body> </soapenv:Envelope> </format> <args/> </payloadFactory> <propertyGroup description="setHeaders"> <property name="HTTP_SC" scope="axis2" type="STRING" value="200"/> <property name="HTTP_SC_DESC" scope="axis2" type="STRING" value="OK"/> <property name="MESSAGE_FORMAT" scope="default" type="STRING" value="soap11"/> <property name="messageType" scope="axis2" type="STRING" value="text/xml"/> <property name="ContentType" scope="axis2" type="STRING" value="text/xml"/> <property name="Content-Type" scope="transport" type="STRING" value="text/xml;charset=UTF-8"/> <property name="RESPONSE" scope="default" type="STRING" value="true"/> </propertyGroup> <class description="InResLoggerSOAP" name="ru.rosbank.mediator.LoggerMediatorSOAP"> <property name="logLevel" value="INFO"/> <property name="ReqType" value="InResponse"/> <property name="isLogHeader" value="true"/> <property name="isLogPayload" value="true"/> </class> </sequence>
Далее создадим endpoint для вызова внешних сервисов. Здесь всё так же, как и с REST API.

<endpoint name="Rosstat_GetOrganizationInfo_EP" xmlns="http://ws.apache.org/ns/synapse"> <http method="post" uri-template="{uri.var.endpointURL_FullAddress}"> <timeout> <duration>40000</duration> <responseAction>fault</responseAction> </timeout> <suspendOnFailure> <errorCodes>101500,101501,101506,101507,101508</errorCodes> <initialDuration>1000</initialDuration> <progressionFactor>2.0</progressionFactor> <maximumDuration>60000</maximumDuration> </suspendOnFailure> <markForSuspension> <errorCodes>101503,101504,101505</errorCodes> <retriesBeforeSuspension>3</retriesBeforeSuspension> <retryDelay>100</retryDelay> </markForSuspension> </http> </endpoint>
Добавляем WSDL-файл и XSD-схемы
В модуле RosstatServiceRegistryResources (в нашем примере) выбираем New – RegistryResource и в появившемся окне — From existing template.

Далее выставляем параметры.
ResourceName: RosstatOrganizationInfo (указываем имя файла WSDL без расширения)
ArtifactName: RosstatOrganizationInfoWSDL (то же самое, что и для ResourceName, только добавляем в конце суффикс WSDL)
Template: выбираем из списка значение WSDL File
Registry: выбираем из списка значение conf
RegistryPath: resources/rosstat/wsdl
Аналогичным образом добавляем XSD-схемы.
ResourceName: RosstatOrganizationInfo (указываем имя файла XSD без расширения)
ArtifactName: RosstatOrganizationInfoXSD (то же самое, что и для ResourceName, только добавляем в конце суффикс XSD)
Template: выбираем из списка значение XSD File
Registry: выбираем из списка значение conf
RegistryPath: resources/rosstat/wsdl
Создаем ProxyService
С SOAP и другими протоколами, кроме REST API, используется ProxyService. Сделаем новый ProxyService, используя ранее созданные Template, Sequence, Endpoint.

Выбираем тип Custom Proxy и указываем транспортные протоколы http и https:

В режиме Design ProxyService будет выглядеть вот так:

Атрибут name у корневого элемента proxy является именем SOAP-сервиса. Значение должно совпадать с тем, что будет в URL после /services/: https://localhost:8253/services/RosstatService?wsdl. Мы также добавили в код валидацию запроса по XSD:
<proxy name="RosstatService" startOnLoad="true" transports="http https" xmlns="http://ws.apache.org/ns/synapse"> <target> <inSequence> <sequence key="Rosstat_InboundSequence"/> <validate cache-schema="true"> <schema key="conf:resources/rosstat/wsdl/RosstatOrganizationInfo.xsd"/> <on-fail> <sequence key="Rosstat_FaultSequence"/> </on-fail> </validate> <switch source="$ctx:ENV_METHOD_NAME"> <case regex="RosstatOrganizationInfoRequest"> <sequence key="Rosstat_GetOrganizationInfo_Sequence"/> </case> <case regex="HealthRequest"> <sequence key="Rosstat_HealthRequest_Sequence"/> </case> <default> <sequence key="Rosstat_UnsupportedService_Sequence"/> </default> </switch> <sequence key="Rosstat_OutboundSequence"/> <respond/> </inSequence> <outSequence/> <faultSequence> <sequence key="Rosstat_FaultSequence"/> </faultSequence> </target> <publishWSDL key="conf:resources/rosstat/wsdl/RosstatOrganizationInfo.wsdl" preservePolicy="true"> <resource key="conf:resources/rosstat/wsdl/RosstatOrganizationInfo.xsd" location="RosstatOrganizationInfo.xsd"/> </publishWSDL> <parameter name="disableREST">true</parameter> <parameter name="disableSOAP12">true</parameter> </proxy>
В блоке «publishWSDL» нужно обязательно указать ссылки на WSDL-файл и XSD-схемы (если их несколько), которые были добавлены в проект на предыдущем шаге. Это необходимо как раз для валидации и получения корректных файлов WSDL/XSD через адрес https://localhost:8253/services/RosstatService?wsdl.
Если сервис должен работать по SOAP 1.1/1.2, необходимо отключить REST и ненужную версию протокола SOAP.
Для SOAP 1.1:
<parameter name="disableREST">true</parameter> <parameter name="disableSOAP12">true</parameter>
Для SOAP 1.2:
<parameter name="disableREST">true</parameter> <parameter name="disableSOAP11">true</parameter>
Собираем сервис
Открывает pom-файл в модуле RosstatServiceCompositeExporter и выбираем все созданные артефакты в модулях RosstatServiceConfig и RosstatServiceRegistryResources:

Сборка сервиса через Maven организована так же, как и в случае с REST API.

Дальнейшие действия зависят от конкретного проекта. Как я указывал в прошлой статье, мы пишем интеграционные тесты с использованием Postman и заглушки для BackendService с Wiremock.
Если у вас появились вопросы по разработке на WSO2, буду рад ответить на них в комментариях. Мы планируем продолжать серию публикаций по этой платформе, так что подписывайтесь, если интересно, и пишите, что еще хотели бы о ней узнать.
ссылка на оригинал статьи https://habr.com/ru/company/rosbank/blog/648919/
Добавить комментарий