Web Services Support
本章介绍 Spring Integration 对 Web 服务的支持,包括:
你需要将此依赖项包含在你的项目中:
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-ws</artifactId>
<version>{project-version}</version>
</dependency>
compile "org.springframework.integration:spring-integration-ws:{project-version}"
Outbound Web Service Gateways
要在向通道发送消息时调用 Web 服务,你有两个选择,这两个选择都建立在 Spring Web Services 项目上:SimpleWebServiceOutboundGateway
和 MarshallingWebServiceOutboundGateway
。前者接受 String
或 javax.xml.transform.Source
作为消息有效负载。后者支持任何 Marshaller
和 Unmarshaller
接口的实现。两者都需要一个 Spring Web Services DestinationProvider
,以确定要调用的 Web 服务的 URI。以下示例展示了调用 Web 服务的两种选择:
simpleGateway = new SimpleWebServiceOutboundGateway(destinationProvider);
marshallingGateway = new MarshallingWebServiceOutboundGateway(destinationProvider, marshaller);
当使用名称空间支持 (described later) 时,你只需要设置一个 URI。在内部,解析器会配置一个固定的 URI |
从版本 5.0 开始,您可以为 SimpleWebServiceOutboundGateway
和 MarshallingWebServiceOutboundGateway
提供一个外部 WebServiceTemplate
实例,您可以为它配置任何自定义属性,包括 checkConnectionForFault
(它允许您的应用程序处理不一致的服务)。
有关内部工作原理的更多详细信息,请参阅 Spring Web Services 参考指南中介绍 client access 的章节和介绍 Object/XML mapping 的章节。
Inbound Web Service Gateways
在接收 Web 服务调用时将消息发送到通道,您还有两个选项: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
接口,因此它们可以使用 MessageDispatcherServlet
按照标准 Spring Web Services 配置进行配置。
有关如何使用这些组件的更多详细信息,请参阅 Spring Web Services 参考指南中介绍 creating a web service 的章节。介绍 Object/XML mapping 的章节也同样适用。
要将 SimpleWebServiceInboundGateway
和 MarshallingWebServiceInboundGateway
配置添加到 Spring WS 基础设施,您应在 MessageDispatcherServlet
和目标 MessageEndpoint
实现之间添加 EndpointMapping
定义,就像对于普通的 Spring WS 应用程序一样。出于此目的(从 Spring 集成角度来看),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 定义。
有关详细信息,请参阅 endpoint mappings。
Web Service Namespace Support
要配置出站 Web 服务网关,请使用 ws
命名空间中的 outbound-gateway
元素,如下例所示:
<int-ws:outbound-gateway id="simpleGateway"
request-channel="inputChannel"
uri="https://example.org"/>
此示例不提供“回复频道”。如果 Web 服务返回一个非空响应,则包含该响应的 |
默认情况下,当你调用一个在使用字符串有效负载时返回空响应的网络服务, |
要设置入站 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"/>
大多数 |
对于任一类型的出站网关,你可以指定 destination-provider
属性,而不是 uri
(其中确需一项)。随后你可以引用任何 Spring Web Services DestinationProvider
实现(例如,在运行时从注册表中查找 URI)。
对于任一类型的出站网关,还可以使用对任何 Spring Web Services WebServiceMessageFactory
实现的引用来配置 message-factory
属性。
对于简单的入站网关类型,你可以将 extract-payload
属性设置为 false
,以便将整个 WebServiceMessage
转发,而不是将其有效负载作为 Message
转发到请求通道。这样做可能很有用,例如,当定制转换器直接适用于 WebServiceMessage
时。
从版本 5.0 开始,web-service-template
引用属性允许你注入具有任何可能的定制属性的 WebServiceTemplate
。
Web Service Java DSL Support
在 Web Service Namespace Support 中展示的网关的等效配置在以下代码段中展示:
@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))
)
Outbound URI Configuration
对于 Spring Web Services 支持的所有 URI 方案(参见 URIs and Transports),均提供了 <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
,则不支持变量替换,并且如果你提供变量,就会发生配置错误。
Controlling URI Encoding
在将请求发送出去之前,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>
如果你设置 |
WS Message Headers
Spring Integration Web 服务网关自动映射 SOAP 操作标头。在默认情况下,它会使用 DefaultSoapHeaderMapper
来将标头从 Spring Integration MessageHeaders
复制到 Spring Integration MessageHeaders
,反之亦然。
你可以传入你自己的 SOAP 特定头映射程序的实现,因为网关具有支持此操作的属性。
除非显式指定 DefaultSoapHeaderMapper
的 requestHeaderNames
或 replyHeaderNames
属性,否则任何用户定义的 SOAP 头都不会复制到 SOAP 消息中或从 SOAP 消息中复制。
当你使用 XML 命名空间进行配置时,可以使用 mapped-request-headers
和 mapped-reply-headers
属性设置这些属性,你可以通过设置 header-mapper
属性提供一个定制的映射器。
当映射用户自定义头部时,值也可以包含简单的通配符号模式(例如 |
从版本 4.1 开始,AbstractHeaderMapper
(一个 DefaultSoapHeaderMapper
超类)允许在 requestHeaderNames
和 replyHeaderNames
属性中配置 NON_STANDARD_HEADERS
令牌(除了现有的 STANDARD_REQUEST_HEADERS
和 STANDARD_REPLY_HEADERS
)以映射所有用户定义的头。
与其使用通配符号 ( |
从版本 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 规范:
<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 Support
规范边界传入和传出 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>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));