Web Services 支援
本章描述了 Spring Integration 對 Web Services 的支援,包括
您需要在專案中包含此依賴項
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-ws</artifactId>
<version>6.4.4</version>
</dependency>
compile "org.springframework.integration:spring-integration-ws:6.4.4"
出站 Web Service 閘道器
當您將訊息傳送到通道時,可以透過兩種方式呼叫 Web Service,這兩種方式都基於 Spring Web Services 專案:SimpleWebServiceOutboundGateway
和 MarshallingWebServiceOutboundGateway
。前者接受 String
或 javax.xml.transform.Source
作為訊息 Payload。後者支援 Marshaller
和 Unmarshaller
介面的任何實現。兩者都需要 Spring Web Services 的 DestinationProvider
來確定要呼叫的 Web Service 的 URI。以下示例展示了呼叫 Web Service 的這兩種方式
simpleGateway = new SimpleWebServiceOutboundGateway(destinationProvider);
marshallingGateway = new MarshallingWebServiceOutboundGateway(destinationProvider, marshaller);
當使用名稱空間支援(稍後描述)時,您只需設定一個 URI。在內部,解析器會配置一個固定的 URI DestinationProvider 實現。但是,如果您需要在執行時動態解析 URI,則 DestinationProvider 可以提供此類行為,例如從登錄檔中查詢 URI。有關此策略的更多資訊,請參閱 Spring Web Services DestinationProvider 的 Javadoc。 |
從 5.0 版本開始,您可以為 SimpleWebServiceOutboundGateway
和 MarshallingWebServiceOutboundGateway
提供外部的 WebServiceTemplate
例項,您可以為該例項配置任何自定義屬性,包括 checkConnectionForFault
(允許您的應用程式處理不規範的服務)。
入站 Web Service 閘道器
當收到 Web Service 呼叫時將訊息傳送到通道,您同樣有兩種選擇:SimpleWebServiceInboundGateway
和 MarshallingWebServiceInboundGateway
。前者從 WebServiceMessage
中提取 javax.xml.transform.Source
並將其設定為訊息 Payload。後者支援 Marshaller
和 Unmarshaller
介面的實現。如果傳入的 Web Service 訊息是 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
介面,因此可以按照標準的 Spring Web Services 配置使用 MessageDispatcherServlet
進行配置。
有關如何使用這些元件的更多詳細資訊,請參閱 Spring Web Services 參考指南中關於建立 Web Service 的章節。關於物件/XML 對映的章節也同樣適用。
要將 SimpleWebServiceInboundGateway
和 MarshallingWebServiceInboundGateway
的配置新增到 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 Service 名稱空間支援
要配置出站 Web Service 閘道器,請使用 ws
名稱空間中的 outbound-gateway
元素,如下例所示
<int-ws:outbound-gateway id="simpleGateway"
request-channel="inputChannel"
uri="https://example.org"/>
此示例未提供 'reply-channel'。如果 Web Service 返回非空響應,包含該響應的 Message 將傳送到請求訊息的 REPLY_CHANNEL 頭部中定義的回覆通道。如果該通道不可用,則會丟擲通道解析異常。如果您想將回復發送到另一個通道,請在 'outbound-gateway' 元素上提供 'reply-channel' 屬性。 |
預設情況下,當您使用 String payload 傳送請求 Message 並呼叫返回空響應的 Web Service 時,不會發送回復 Message 。因此,您無需設定 'reply-channel' 或在請求 Message 中包含 REPLY_CHANNEL 頭部。如果您確實希望接收空響應作為 Message ,可以將 'ignore-empty-responses' 屬性設定為 false 。但這僅對 String 物件有效,因為使用 Source 或 Document 物件會導致空響應,從而永遠不會生成回覆 Message 。 |
要設定入站 Web Service 閘道器,請使用 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)。
對於任何一種出站閘道器型別,還可以使用對任何 Spring Web Services 的 WebServiceMessageFactory
實現的引用來配置 message-factory
屬性。
對於簡單的入站閘道器型別,您可以將 extract-payload
屬性設定為 false
,以便將整個 WebServiceMessage
而不僅僅是其 Payload 作為 Message
轉發到請求通道。例如,當自定義轉換器直接處理 WebServiceMessage
時,這樣做可能會很有用。
從 5.0 版本開始,web-service-template
引用屬性允許您注入一個具有任何可能自定義屬性的 WebServiceTemplate
。
Web Service Java DSL 支援
在 Web Service 名稱空間支援 中展示的閘道器的等效配置如下所示
@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}&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 Service 閘道器會自動對映 SOAP action 頭部。預設情況下,它使用 DefaultSoapHeaderMapper
複製到 Spring Integration MessageHeaders
並從中複製。
您可以傳入自己實現的 SOAP 特定頭部對映器,因為閘道器具有支援此功能的屬性。
除非在 DefaultSoapHeaderMapper
的 requestHeaderNames
或 replyHeaderNames
屬性中明確指定,否則任何使用者定義的 SOAP 頭部都不會被複制到 SOAP Message 或從 SOAP Message 中複製。
當您使用 XML 名稱空間進行配置時,可以使用 mapped-request-headers
和 mapped-reply-headers
屬性來設定這些屬性,您也可以透過設定 header-mapper
屬性來提供自定義對映器。
對映使用者定義的頭部時,值也可以包含簡單的萬用字元模式(例如 myheader* 或 *myheader* )。例如,如果您需要複製所有使用者定義的頭部,可以使用萬用字元字元:* 。 |
從 4.1 版本開始,AbstractHeaderMapper
(DefaultSoapHeaderMapper
的父類)允許為 requestHeaderNames
和 replyHeaderNames
屬性配置 NON_STANDARD_HEADERS
令牌(除了現有的 STANDARD_REQUEST_HEADERS
和 STANDARD_REPLY_HEADERS
),以對映所有使用者定義的頭部。
建議使用以下組合代替萬用字元(* ):STANDARD_REPLY_HEADERS, NON_STANDARD_HEADERS 。這樣做可以避免將 request 頭部對映到 reply。 |
從 4.3 版本開始,您可以透過在模式前加上 !
來否定頭部對映中的模式。否定模式具有優先權,因此像 STANDARD_REQUEST_HEADERS,thing1,thing*,!thing2,!thing3,qux,!thing1
這樣的列表不會對映 thing1
、thing2
或 thing3
。它會對映標準頭部、thing4
和 qux
。(請注意,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*
,則 auth
、cat
和 can
頭部會被對映,但 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 Service 閘道器透過 marshaller 的內建功能(例如,Jaxb2Marshaller
提供了 mtomEnabled
選項)直接支援附件。從 5.0 版本開始,簡單 Web Service 閘道器可以直接處理入站和出站的 MimeMessage
例項,這些例項具有用於操作附件的 API。當您需要傳送帶有附件的 Web Service 訊息(無論是來自伺服器的回覆還是客戶端請求)時,您應該直接使用 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));