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 專案之上:SimpleWebServiceOutboundGateway
和 MarshallingWebServiceOutboundGateway
。前者接受 String
或 javax.xml.transform.Source
作為訊息 Payload。後者支援 Marshaller
和 Unmarshaller
介面的任何實作。兩者都需要 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 開始,您可以為 SimpleWebServiceOutboundGateway
和 MarshallingWebServiceOutboundGateway
提供外部 WebServiceTemplate
實例,您可以針對任何自訂屬性進行設定,包括 checkConnectionForFault
(允許您的應用程式處理不符合規範的服務)。
輸入 Web 服務閘道
若要在接收到 Web 服務調用時傳送訊息到通道,您再次有兩個選項:SimpleWebServiceInboundGateway
和 MarshallingWebServiceInboundGateway
。前者從 WebServiceMessage
中提取 javax.xml.transform.Source
並將其設定為訊息 Payload。後者支援 Marshaller
和 Unmarshaller
介面的實作。如果傳入的 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 設定一樣。
若要將 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 服務命名空間支援
若要設定輸出 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 物件,因為使用 Source 或 Document 物件會導致 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}&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 特定標頭對應器實作,因為閘道具有支援這樣做的屬性。
除非由 DefaultSoapHeaderMapper
的 requestHeaderNames
或 replyHeaderNames
屬性明確指定,否則任何使用者定義的 SOAP 標頭都不會複製到 SOAP 訊息或從 SOAP 訊息複製。
當您使用 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 標頭對應到回覆。 |
從版本 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 服務閘道直接透過 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));