Web 服務支援

本章節描述 Spring Integration 對於 Web 服務的支援,包含

您需要將此依賴項加入到您的專案中

  • Maven

  • Gradle

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

輸出 Web 服務閘道

若要在傳送訊息到通道時調用 Web 服務,您有兩個選項,兩者都建立在 Spring Web Services 專案之上:SimpleWebServiceOutboundGatewayMarshallingWebServiceOutboundGateway。前者接受 Stringjavax.xml.transform.Source 作為訊息 Payload。後者支援 MarshallerUnmarshaller 介面的任何實作。兩者都需要 Spring Web Services DestinationProvider,以決定要呼叫的 Web 服務的 URI。以下範例顯示調用 Web 服務的兩種選項

 simpleGateway = new SimpleWebServiceOutboundGateway(destinationProvider);

 marshallingGateway = new MarshallingWebServiceOutboundGateway(destinationProvider, marshaller);
當使用命名空間支援 (稍後描述) 時,您只需要設定 URI。在內部,剖析器會設定固定的 URI DestinationProvider 實作。但是,如果您需要在執行階段動態解析 URI,則 DestinationProvider 可以提供此類行為,例如從登錄檔中查詢 URI。如需關於此策略的更多資訊,請參閱 Spring Web Services DestinationProvider Javadoc。

從版本 5.0 開始,您可以為 SimpleWebServiceOutboundGatewayMarshallingWebServiceOutboundGateway 提供外部 WebServiceTemplate 實例,您可以針對任何自訂屬性進行設定,包括 checkConnectionForFault (允許您的應用程式處理不符合規範的服務)。

如需內部運作的更多詳細資訊,請參閱 Spring Web Services 參考指南中涵蓋 用戶端存取 的章節和涵蓋 物件/XML 對應 的章節。

輸入 Web 服務閘道

若要在接收到 Web 服務調用時傳送訊息到通道,您再次有兩個選項:SimpleWebServiceInboundGatewayMarshallingWebServiceInboundGateway。前者從 WebServiceMessage 中提取 javax.xml.transform.Source 並將其設定為訊息 Payload。後者支援 MarshallerUnmarshaller 介面的實作。如果傳入的 Web 服務訊息是 SOAP 訊息,則 SOAP action 標頭會新增到轉發到請求通道的 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 介面,因此它們可以使用 MessageDispatcherServlet 進行設定,如同標準 Spring Web Services 設定一樣。

如需關於如何使用這些元件的更多詳細資訊,請參閱 Spring Web Services 參考指南中涵蓋 建立 Web 服務 的章節。涵蓋 物件/XML 對應 的章節也再次適用。

若要將 SimpleWebServiceInboundGatewayMarshallingWebServiceInboundGateway 設定新增到 Spring WS 基礎架構,您應該在 MessageDispatcherServlet 和目標 MessageEndpoint 實作之間新增 EndpointMapping 定義,就像您對一般 Spring WS 應用程式所做的一樣。為此目的 (從 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"/>
此範例未提供 'reply-channel'。如果 Web 服務傳回非空的回應,則包含該回應的 Message 會傳送到請求訊息的 REPLY_CHANNEL 標頭中定義的回覆通道。如果該標頭不可用,則會擲回通道解析例外狀況。如果您想要將回覆傳送到另一個通道,請在 'outbound-gateway' 元素上提供 'reply-channel' 屬性。
預設情況下,當您調用 Web 服務,在使用 String Payload 作為請求 Message 後傳回空的回應時,不會傳送任何回覆 Message。因此,您不需要設定 'reply-channel' 或在請求 Message 中具有 REPLY_CHANNEL 標頭。如果您實際上想要接收空的回應作為 Message,您可以將 'ignore-empty-responses' 屬性設定為 false。這樣做僅適用於 String 物件,因為使用 SourceDocument 物件會導致 null 回應,因此永遠不會產生回覆 Message

若要設定輸入 Web 服務閘道,請使用 inbound-gateway 元素,如下列範例所示

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

若要使用 Spring OXM marshaller 或 unmarshaller,您必須提供 bean 參考。以下範例顯示如何為輸出 marshalling 閘道提供 bean 參考

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

以下範例顯示如何為輸入 marshalling 閘道提供 bean 參考

<int-ws:inbound-gateway id="marshallingGateway"
                    request-channel="requestChannel"
                    marshaller="someMarshaller"
                    unmarshaller="someUnmarshaller"/>
大多數 Marshaller 實作也實作了 Unmarshaller 介面。當使用此類 Marshaller 時,只需要 marshaller 屬性。即使在使用 Marshaller 時,您也可以在輸出閘道上為 request-callback 提供參考。

對於任何一種輸出閘道類型,您可以指定 destination-provider 屬性而不是 uri (兩者必須選擇一個)。然後,您可以參考任何 Spring Web Services DestinationProvider 實作 (例如,在執行階段從登錄檔中查詢 URI)。

對於任何一種輸出閘道類型,message-factory 屬性也可以設定為參考任何 Spring Web Services WebServiceMessageFactory 實作。

對於簡單的輸入閘道類型,您可以將 extract-payload 屬性設定為 false,以轉發整個 WebServiceMessage,而不是僅轉發其 Payload 作為 Message 到請求通道。例如,當自訂轉換器直接針對 WebServiceMessage 工作時,這樣做可能很有用。

從版本 5.0 開始,web-service-template 參考屬性可讓您注入具有任何可能自訂屬性的 WebServiceTemplate

Web 服務 Java DSL 支援

Web 服務命名空間支援 中顯示的閘道的等效設定顯示在以下程式碼片段中

@Bean
IntegrationFlow inbound() {
    return IntegrationFlow.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 IntegrationFlow.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 字串會被編碼 (請參閱 UriComponentsBuilder) 為 URI 物件,然後再傳送請求。在某些具有非標準 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 action 標頭。預設情況下,它會使用 DefaultSoapHeaderMapper 複製到 Spring Integration MessageHeaders 和從 Spring Integration MessageHeaders 複製。

您可以傳入您自己的 SOAP 特定標頭對應器實作,因為閘道具有支援這樣做的屬性。

除非由 DefaultSoapHeaderMapperrequestHeaderNamesreplyHeaderNames 屬性明確指定,否則任何使用者定義的 SOAP 標頭都不會複製到 SOAP 訊息或從 SOAP 訊息複製。

當您使用 XML 命名空間進行設定時,您可以透過使用 mapped-request-headersmapped-reply-headers 屬性來設定這些屬性,您可以透過設定 header-mapper 屬性來提供自訂對應器。

當對應使用者定義的標頭時,值也可以包含簡單的萬用字元模式 (例如 myheader***myheader**)。例如,如果您需要複製所有使用者定義的標頭,您可以使用萬用字元:*

從版本 4.1 開始,AbstractHeaderMapper (DefaultSoapHeaderMapper 超類別) 允許為 requestHeaderNamesreplyHeaderNames 屬性設定 NON_STANDARD_HEADERS 權杖 (除了現有的 STANDARD_REQUEST_HEADERSSTANDARD_REPLY_HEADERS 之外) 以對應所有使用者定義的標頭。

我們建議使用以下組合,而不是使用萬用字元 (*):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-headersauth, 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 Envelope

<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 支援

marshalling 輸入和輸出 Web 服務閘道直接透過 marshaller 的內建功能支援附件 (例如,Jaxb2Marshaller 提供 mtomEnabled 選項)。從版本 5.0 開始,簡單的 Web 服務閘道可以直接使用輸入和輸出 MimeMessage 實例,這些實例具有操作附件的 API。當您需要傳送帶有附件的 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));