Web サービスのサポート

この章では、Spring Integration の Web サービスのサポートについて説明します。

この依存関係をプロジェクトに含める必要があります。

<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-ws</artifactId>
    <version>5.5.10</version>
</dependency>
compile "org.springframework.integration:spring-integration-ws:5.5.10"

送信 Web サービスゲートウェイ

チャネルにメッセージを送信するときに Web サービスを呼び出すには、2 つのオプションがあります。どちらも Spring Web Services プロジェクトに基づいて構築されています: SimpleWebServiceOutboundGateway および MarshallingWebServiceOutboundGateway。前者は、メッセージペイロードとして String または javax.xml.transform.Source を受け入れます。後者は、Marshaller および Unmarshaller インターフェースの実装をサポートします。どちらも、呼び出される Web サービスの URI を決定するために Spring Web Services DestinationProvider が必要です。次の例は、Web サービスを呼び出すための両方のオプションを示しています。

 simpleGateway = new SimpleWebServiceOutboundGateway(destinationProvider);

 marshallingGateway = new MarshallingWebServiceOutboundGateway(destinationProvider, marshaller);
ネームスペースサポート(後述)を使用する場合、必要なのは URI のみです。内部的に、パーサーは固定 URI DestinationProvider 実装を構成します。ただし、実行時に URI の動的な解決が必要な場合は、DestinationProvider はレジストリから URI を検索するなどの動作を提供できます。この戦略の詳細については、Spring Web Services DestinationProvider (Javadoc) Javadoc を参照してください。

バージョン 5.0 から、SimpleWebServiceOutboundGateway および MarshallingWebServiceOutboundGateway に外部 WebServiceTemplate インスタンスを提供できます。これは、checkConnectionForFault (アプリケーションが非準拠サービスを処理できるようにする)を含むカスタムプロパティ用に設定できます。

内部の仕組みの詳細については、Spring Web Services リファレンスガイドのクライアントアクセスに関する章とオブジェクト / XML マッピングに関する章を参照してください。

受信 Web サービスゲートウェイ

Web サービス呼び出しの受信時にチャネルにメッセージを送信するには、再び 2 つのオプション SimpleWebServiceInboundGateway と MarshallingWebServiceInboundGateway があります。前者は、WebServiceMessage から javax.xml.transform.Source を抽出し、それをメッセージペイロードとして設定します。後者は、Marshaller および Unmarshaller インターフェースの実装をサポートします。受信 Web サービスメッセージが SOAP メッセージの場合、SOAP アクションヘッダーは、リクエストチャネルに転送される Message のヘッダーに追加されます。次の例は、両方のオプションを示しています。

 simpleGateway = new SimpleWebServiceInboundGateway();
 simpleGateway.setRequestChannel(forwardOntoThisChannel);
 simpleGateway.setReplyChannel(listenForResponseHere); //Optional

 marshallingGateway = new MarshallingWebServiceInboundGateway(marshaller);
 //set request and optionally reply channel

両方のゲートウェイは、Spring Web Services MessageEndpoint インターフェースを実装しているため、標準 Spring Web Services 構成に従って MessageDispatcherServlet で構成できます。

これらのコンポーネントの使用方法の詳細については、Spring Web Services リファレンスガイドの Web サービスの作成に関する章を参照してください。オブジェクト / XML マッピングをカバーする章もまた適用可能です。

SimpleWebServiceInboundGateway および MarshallingWebServiceInboundGateway 構成を Spring WS インフラストラクチャに追加するには、通常の Spring WS アプリケーションの場合と同様に、MessageDispatcherServlet とターゲット MessageEndpoint 実装の間に EndpointMapping 定義を追加する必要があります。この目的のために(Spring Integration の観点から)、Spring WS は次の便利な EndpointMapping 実装を提供します。

  • o.s.ws.server.endpoint.mapping.UriEndpointMapping

  • o.s.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping

  • o.s.ws.soap.server.endpoint.mapping.SoapActionEndpointMapping

  • o.s.ws.server.endpoint.mapping.XPathPayloadEndpointMapping

アプリケーションコンテキストでこれらのクラスの Bean を指定し、WS マッピングアルゴリズムに従って SimpleWebServiceInboundGateway および / または MarshallingWebServiceInboundGateway Bean 定義を参照する必要があります。

詳細については、エンドポイントマッピングを参照してください。

Web サービス名前空間のサポート

送信 Web サービスゲートウェイを構成するには、次の例に示すように、ws 名前空間の outbound-gateway 要素を使用します。

<int-ws:outbound-gateway id="simpleGateway"
                     request-channel="inputChannel"
                     uri="https://example.org"/>
この例では、「レスポンスチャネル」は提供されません。Web サービスが空でないレスポンスを返す場合、そのレスポンスを含む Message は、リクエストメッセージの REPLY_CHANNEL ヘッダーで定義されたレスポンスチャネルに送信されます。それが利用できない場合、チャンネル解決例外がスローされます。代わりに別のチャネルにレスポンスを送信する場合は、'outbound-gateway' 要素で 'reply-channel' 属性を提供します。
デフォルトでは、リクエスト Message にストリングペイロードを使用した後に空のレスポンスを返す Web サービスを呼び出すと、レスポンス Message は送信されません。「返信チャネル」を設定したり、リクエスト Message に REPLY_CHANNEL ヘッダーを設定したりする必要はありません。空のレスポンスを Message として実際に受信する場合は、'ignore-empty-responses' 属性を false に設定できます。Source または Document オブジェクトを使用すると null レスポンスが発生し、その結果レスポンス Message が生成されないため、String オブジェクトに対してのみ機能します。

受信 Web サービスゲートウェイをセットアップするには、次の例に示すように、inbound-gateway 要素を使用します。

<int-ws:inbound-gateway id="simpleGateway"
                    request-channel="inputChannel"/>

Spring OXM マーシャラーまたはアンマーシャラーを使用するには、Bean 参照を提供する必要があります。次の例は、発信マーシャリングゲートウェイに Bean 参照を提供する方法を示しています。

<int-ws:outbound-gateway id="marshallingGateway"
                     request-channel="requestChannel"
                     uri="https://example.org"
                     marshaller="someMarshaller"
                     unmarshaller="someUnmarshaller"/>

次の例は、受信マーシャリングゲートウェイに Bean 参照を提供する方法を示しています。

<int-ws:inbound-gateway id="marshallingGateway"
                    request-channel="requestChannel"
                    marshaller="someMarshaller"
                    unmarshaller="someUnmarshaller"/>
ほとんどの Marshaller 実装は、Unmarshaller インターフェースも実装します。このような Marshaller を使用する場合、marshaller 属性のみが必要です。Marshaller を使用する場合でも、送信ゲートウェイで request-callback の参照を提供することもできます。

どちらの送信ゲートウェイ型でも、uri の代わりに destination-provider 属性を指定できます(正確に 1 つが必要です)。その後、Spring Web Services DestinationProvider 実装を参照できます(たとえば、実行時にレジストリから URI を検索するため)。

どちらの送信ゲートウェイ型でも、message-factory 属性は、Spring Web Services WebServiceMessageFactory 実装への参照を使用して構成できます。

単純な受信ゲートウェイ型の場合、extract-payload 属性を false に設定して、ペイロードだけでなく Message として WebServiceMessage 全体をリクエストチャネルに転送できます。これは、たとえば、カスタムトランスフォーマーが WebServiceMessage に対して直接動作する場合に便利です。

バージョン 5.0 以降、web-service-template 参照属性を使用して、可能なカスタムプロパティを使用して WebServiceTemplate を挿入できます。

Web サービス Java DSL サポート

Web サービス名前空間のサポートに示されているゲートウェイの同等の構成を以下のスニペットに示します。

@Bean
IntegrationFlow inbound() {
    return IntegrationFlows.from(Ws.simpleInboundGateway()
                .id("simpleGateway"))
        ...
        .get();
}
@Bean
IntegrationFlow outboundMarshalled() {
    return f -> f.handle(Ws.marshallingOutboundGateway()
                    .id("marshallingGateway")
                    .marshaller(someMarshaller())
                    .unmarshaller(someUnmarshalller()))
        ...
}
@Bean
IntegrationFlow inboundMarshalled() {
    return IntegrationFlows.from(Ws.marshallingInboundGateway()
                .marshaller(someMarshaller())
                .unmarshaller(someUnmarshalller())
                .id("marshallingGateway"))
        ...
        .get();
}

他のプロパティは、流れるような方法でエンドポイントスペックに設定できます(外部ゲートウェイに外部 WebServiceTemplate が提供されているかどうかに応じてプロパティが設定されます)。例:

.from(Ws.simpleInboundGateway()
                .extractPayload(false))
.handle(Ws.simpleOutboundGateway(template)
            .uri(uri)
            .sourceExtractor(sourceExtractor)
            .encodingMode(DefaultUriBuilderFactory.EncodingMode.NONE)
            .headerMapper(headerMapper)
            .ignoreEmptyResponses(true)
            .requestCallback(requestCallback)
            .uriVariableExpressions(uriVariableExpressions)
            .extractPayload(false))
)
.handle(Ws.marshallingOutboundGateway()
            .destinationProvider(destinationProvider)
            .marshaller(marshaller)
            .unmarshaller(unmarshaller)
            .messageFactory(messageFactory)
            .encodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY)
            .faultMessageResolver(faultMessageResolver)
            .headerMapper(headerMapper)
            .ignoreEmptyResponses(true)
            .interceptors(interceptor)
            .messageSenders(messageSender)
            .requestCallback(requestCallback)
            .uriVariableExpressions(uriVariableExpressions))
.handle(Ws.marshallingOutboundGateway(template)
            .uri(uri)
            .encodingMode(DefaultUriBuilderFactory.EncodingMode.URI_COMPONENT)
            .headerMapper(headerMapper)
            .ignoreEmptyResponses(true)
            .requestCallback(requestCallback)
            .uriVariableExpressions(uriVariableExpressions))
)

送信 URI 設定

Spring Web Services(URI とトランスポートを参照)でサポートされるすべての URI スキームについて、<uri-variable/> 置換が提供されます。次の例は、その定義方法を示しています。

<ws:outbound-gateway id="gateway" request-channel="input"
        uri="https://springsource.org/{thing1}-{thing2}">
    <ws:uri-variable name="thing1" expression="payload.substring(1,7)"/>
    <ws:uri-variable name="thing2" expression="headers.x"/>
</ws:outbound-gateway>

<ws:outbound-gateway request-channel="inputJms"
        uri="jms:{destination}?deliveryMode={deliveryMode}&amp;priority={priority}"
        message-sender="jmsMessageSender">
    <ws:uri-variable name="destination" expression="headers.jmsQueue"/>
    <ws:uri-variable name="deliveryMode" expression="headers.deliveryMode"/>
    <ws:uri-variable name="priority" expression="headers.jms_priority"/>
</ws:outbound-gateway>

DestinationProvider を指定すると、変数置換はサポートされず、変数を指定すると構成エラーが発生します。

URI エンコードの制御

デフォルトでは、リクエストを送信する前に、URL 文字列は URI オブジェクトにエンコードされます(UriComponentsBuilder (Javadoc) を参照)。非標準の URI を使用する一部のシナリオでは、エンコードを実行することは望ましくありません。<ws:outbound-gateway/> 要素は encoding-mode 属性を提供します。URL のエンコードを無効にするには、この属性を NONE に設定します(デフォルトでは TEMPLATE_AND_VALUES です)。一部の URL を部分的にエンコードする場合は、次の例に示すように、<uri-variable/> 内で expression を使用してエンコードできます。

<ws:outbound-gateway url="https://somehost/%2f/fooApps?bar={param}" encoding-mode="NONE">
          <http:uri-variable name="param"
            expression="T(org.apache.commons.httpclient.util.URIUtil)
                                             .encodeWithinQuery('Hello World!')"/>
</ws:outbound-gateway>
DestinationProvider を設定すると、encoding-mode は無視されます。

WS メッセージヘッダー

Spring Integration Web サービスゲートウェイは、SOAP アクションヘッダーを自動的にマップします。デフォルトでは、DefaultSoapHeaderMapper (Javadoc) を使用して Spring Integration MessageHeaders との間でコピーされます。

ゲートウェイにはそうすることをサポートするプロパティがあるため、SOAP 固有のヘッダーマッパーの独自の実装を渡すことができます。

DefaultSoapHeaderMapper の requestHeaderNames または replyHeaderNames プロパティで明示的に指定されていない限り、ユーザー定義の SOAP ヘッダーは SOAP メッセージとの間でコピーされません。

構成に XML 名前空間を使用する場合、mapped-request-headers および mapped-reply-headers 属性を使用してこれらのプロパティを設定でき、header-mapper 属性を設定してカスタムマッパーを提供できます。

ユーザー定義ヘッダーをマッピングする場合、値に単純なワイルドカードパターン(myheader* や myheader など)を含めることもできます。例: すべてのユーザー定義ヘッダーをコピーする必要がある場合は、ワイルドカード文字  を使用できます。

バージョン 4.1 以降、AbstractHeaderMapper (DefaultSoapHeaderMapper スーパークラス)により、NON_STANDARD_HEADERS トークンを(既存の STANDARD_REQUEST_HEADERS および STANDARD_REPLY_HEADERS に加えて) requestHeaderNames および replyHeaderNames プロパティ用に構成して、すべてのユーザー定義ヘッダーをマップできます。

ワイルドカード(*)を使用するのではなく、次の組み合わせを使用することをお勧めします: STANDARD_REPLY_HEADERS, NON_STANDARD_HEADERS。そうすることで、request ヘッダーを応答にマッピングすることを回避できます。

バージョン 4.3 以降では、パターンの前に ! を付けることにより、ヘッダーマッピングのパターンを無効にすることができます。否定パターンが優先されるため、STANDARD_REQUEST_HEADERS,thing1,thing*,!thing2,!thing3,qux,!thing1 などのリストは thing1thing2thing3 をマップしません。標準ヘッダー、thing4qux をマップします。(thing1 は、非否定形式と否定形式の両方に含まれていることに注意してください。否定された値が優先されるため、thing1 はマップされません。)

マッピングしたい ! で始まるユーザー定義ヘッダーがある場合は、次のように \ でエスケープできます: STANDARD_REQUEST_HEADERS,\!myBangHeader。次に、!myBangHeader がマップされます。

受信 SOAP ヘッダー(受信ゲートウェイのリクエストヘッダーと送信ゲートウェイの応答ヘッダー)は、SoapHeaderElement オブジェクトとしてマップされます。Source にアクセスして、コンテンツを探索できます。

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header>
        <auth>
            <username>user</username>
            <password>pass</password>
        </auth>
        <bar>BAR</bar>
        <baz>BAZ</baz>
        <qux>qux</qux>
    </soapenv:Header>
    <soapenv:Body>
        ...
    </soapenv:Body>
</soapenv:Envelope>

mapped-request-headers が auth, ca* の場合、authcatcan ヘッダーはマップされますが、qux はマップされません。

次の例は、auth という名前のヘッダーから user という名前の値を取得する方法を示しています。

...
SoapHeaderElement header = (SoapHeaderElement) headers.get("auth");
DOMSource source = (DOMSource) header.getSource();
NodeList nodeList = source.getNode().getChildNodes();
assertEquals("username", nodeList.item(0).getNodeName());
assertEquals("user", nodeList.item(0).getFirstChild().getNodeValue());
...

バージョン 5.0 以降、DefaultSoapHeaderMapper は型 javax.xml.transform.Source のユーザー定義ヘッダーをサポートし、<soapenv:Header> の子ノードとして取り込みます。次の例は、その方法を示しています。

Map<String, Object> headers = new HashMap<>();

String authXml =
     "<auth xmlns='http://test.auth.org'>"
           + "<username>user</username>"
           + "<password>pass</password>"
           + "</auth>";
headers.put("auth", new StringSource(authXml));
...
DefaultSoapHeaderMapper mapper = new DefaultSoapHeaderMapper();
mapper.setRequestHeaderNames("auth");

上記の例の結果は、次の SOAP エンベロープです。

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header>
        <auth xmlns="http://test.auth.org">
            <username>user</username>
            <password>pass</password>
        </auth>
    </soapenv:Header>
    <soapenv:Body>
        ...
    </soapenv:Body>
</soapenv:Envelope>

MTOM サポート

マーシャリングの受信および送信 Web サービスゲートウェイは、マーシャラーの組み込み機能を介して直接添付ファイルをサポートします(たとえば、Jaxb2Marshaller は mtomEnabled オプションを提供します)。バージョン 5.0 以降、単純な Web サービスゲートウェイは、添付ファイルを操作する API を備えた受信および送信 MimeMessage インスタンスで直接動作できます。添付ファイル付きの Web サービスメッセージ(サーバーからの応答またはクライアントリクエスト)を送信する必要がある場合は、WebServiceMessageFactory を直接使用し、添付ファイル付きの WebServiceMessage を payload としてゲートウェイのリクエストまたは応答チャネルに送信する必要があります。次の例は、その方法を示しています。

WebServiceMessageFactory messageFactory = new SaajSoapMessageFactory(MessageFactory.newInstance());
MimeMessage webServiceMessage = (MimeMessage) messageFactory.createWebServiceMessage();

String request = "<test>foo</test>";

TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new StringSource(request), webServiceMessage.getPayloadResult());

webServiceMessage.addAttachment("myAttachment", new ByteArrayResource("my_data".getBytes()), "plain/text");

this.webServiceChannel.send(new GenericMessage<>(webServiceMessage));