Web 服務支援

本章介紹了 Spring Integration 對 Web 服務的支援,包括

專案需要此依賴項

  • Maven

  • Gradle

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

出站 Web 服務閘道器

當您向通道傳送訊息時呼叫 Web 服務,您有兩個選項,兩者都基於 Spring Web Services 專案:SimpleWebServiceOutboundGatewayMarshallingWebServiceOutboundGateway。前者接受 Stringjavax.xml.transform.Source 作為訊息負載。後者支援 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 並將其設定為訊息負載。後者支援 MarshallerUnmarshaller 介面的實現。如果傳入的 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 對映的章節也再次適用。

要將 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”屬性。
預設情況下,當您使用 String 負載的請求 Message 呼叫 Web 服務後,如果 Web 服務返回空響應,則不會發送回復 Message。因此,您不需要設定“reply-channel”或在請求 Message 中包含 REPLY_CHANNEL 頭。如果您確實希望將空響應作為 Message 接收,可以將“ignore-empty-responses”屬性設定為 false。這樣做僅適用於 String 物件,因為使用 SourceDocument 物件會導致空響應,從而永遠不會生成回覆 Message

要設定入站 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 提供引用。

對於任何一種出站閘道器型別,您可以指定 destination-provider 屬性而不是 uri(兩者中正好需要一個)。然後您可以引用任何 Spring Web Services DestinationProvider 實現(例如,在執行時從登錄檔查詢 URI)。

對於任何一種出站閘道器型別,message-factory 屬性也可以配置為引用任何 Spring Web Services WebServiceMessageFactory 實現。

對於簡單入站閘道器型別,您可以將 extract-payload 屬性設定為 false,以將整個 WebServiceMessage 而不是僅將其負載作為 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/someApps?someKey={param}" encoding-mode="NONE">
          <http:uri-variable name="param"
            expression="T(org.apache.commons.httpclient.util.URIUtil)
                                             .encodeWithinQuery('Hello World!')"/>
</ws:outbound-gateway>
如果您設定了 DestinationProviderencoding-mode 將被忽略。

WS 訊息頭

Spring Integration Web 服務閘道器會自動對映 SOAP 動作頭。預設情況下,它透過使用 DefaultSoapHeaderMapper 在 Spring Integration MessageHeaders 之間複製。

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

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

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

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

從 4.1 版開始,AbstractHeaderMapperDefaultSoapHeaderMapper 的超類)允許為 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,thing5,!thing1 這樣的列表不對映 thing1thing2thing3。它對映標準標頭、thing4thing5。(請注意,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>
        <cat>CAT</cat>
        <can>CAN</can>
        <dog>DOG</dog>
    </soapenv:Header>
    <soapenv:Body>
        ...
    </soapenv:Body>
</soapenv:Envelope>

如果 mapped-request-headersauth, ca*,則 authcatcan 頭將被對映,但 dog 不會被對映。

以下示例展示瞭如何從名為 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 服務閘道器可以直接操作入站和出站 MimeMessage 例項,這些例項具有操作附件的 API。當您需要傳送帶有附件的 Web 服務訊息(無論是來自伺服器的回覆還是客戶端請求)時,您應該直接使用 WebServiceMessageFactory,並將帶有附件的 WebServiceMessage 作為 payload 傳送到閘道器的請求或回覆通道。以下示例展示瞭如何實現這一點

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

String request = "<test>test data</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));
© . This site is unofficial and not affiliated with VMware.