对于最新的稳定版本,请使用 Spring Integration 6.5.1! |
Web 服务支持
本章介绍了 Spring Integration 对 Web 服务的支持,包括:
您需要将此依赖项包含在您的项目中:
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-ws</artifactId>
<version>6.3.11</version>
</dependency>
compile "org.springframework.integration:spring-integration-ws:6.3.11"
出站 Web 服务网关
要在向通道发送消息时调用 Web 服务,您有两个选项,这两个选项都建立在 Spring Web Services 项目之上:SimpleWebServiceOutboundGateway
和MarshallingWebServiceOutboundGateway
.
前者接受String
或javax.xml.transform.Source
作为消息有效负载。
后者支持任何实现Marshaller
和Unmarshaller
接口。
两者都需要 Spring Web 服务DestinationProvider
,以确定要调用的 Web 服务的 URI。
以下示例显示了调用 Web 服务的两个选项:
simpleGateway = new SimpleWebServiceOutboundGateway(destinationProvider);
marshallingGateway = new MarshallingWebServiceOutboundGateway(destinationProvider, marshaller);
使用命名空间支持(稍后介绍)时,只需设置一个 URI。
在内部,解析器配置一个固定的 URIDestinationProvider 实现。
但是,如果您需要在运行时动态解析 URI,则DestinationProvider 可以提供诸如从注册表中查找 URI 之类的行为。
查看 Spring Web ServicesDestinationProvider Javadoc 以获取有关此策略的更多信息。 |
从 5.0 版开始,您可以提供SimpleWebServiceOutboundGateway
和MarshallingWebServiceOutboundGateway
与外部WebServiceTemplate
实例,您可以为任何自定义属性配置该属性,包括checkConnectionForFault
(这允许你的应用程序处理不合格服务)。
入站 Web 服务网关
要在收到 Web 服务调用时向通道发送消息,您还有两个选项:SimpleWebServiceInboundGateway
和MarshallingWebServiceInboundGateway
.
前者提取javax.xml.transform.Source
从WebServiceMessage
并将其设置为消息有效负载。
后者支持实现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 服务MessageEndpoint
接口,因此可以使用MessageDispatcherServlet
根据标准的 Spring Web Services 配置。
要添加SimpleWebServiceInboundGateway
和MarshallingWebServiceInboundGateway
配置到 Spring WS 基础架构中,您应该将EndpointMapping
之间的定义MessageDispatcherServlet
和目标MessageEndpoint
实现,就像对于普通的 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,并引用SimpleWebServiceInboundGateway
和/或MarshallingWebServiceInboundGateway
根据 WS 映射算法定义 bean。
有关详细信息,请参阅端点映射。
Web 服务命名空间支持
要配置出站 Web 服务网关,请使用outbound-gateway
元素中的ws
命名空间,如以下示例所示:
<int-ws:outbound-gateway id="simpleGateway"
request-channel="inputChannel"
uri="https://example.org"/>
此示例不提供“回复通道”。
如果 Web 服务返回非空响应,则Message 包含该响应的响应将发送到请求消息的REPLY_CHANNEL 页眉。
如果不可用,则会抛出通道解析异常。
如果要将回复发送到另一个通道,请在“outbound-gateway”元素上提供“reply-channel”属性。 |
默认情况下,当您调用 Web 服务时,该服务在对请求使用 String 有效负载后返回空响应Message ,无回复Message 被发送。
因此,您不需要设置“回复通道”或有一个REPLY_CHANNEL 请求中的标头Message .
如果您确实希望将空响应作为Message ,您可以将 'ignore-empty-responses' 属性设置为false .
这样做仅适用于String 对象,因为使用Source 或Document 对象导致空响应,因此永远不会生成回复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 服务DestinationProvider
实现(例如,在运行时从注册表中查找 URI)。
对于任一出站网关类型,message-factory
属性也可以配置为对任何 Spring Web Services 的引用WebServiceMessageFactory
实现。
对于简单入站网关类型,您可以将extract-payload
属性设置为false
转发整个WebServiceMessage
而不仅仅是将其有效负载作为Message
到请求通道。
这样做可能很有用,例如,当自定义转换器针对WebServiceMessage
径直。
从 5.0 版开始,web-service-template
reference 属性允许您注入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 进行部分编码,可以使用expression
在<uri-variable/>
,如以下示例所示:
<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作标头。
默认情况下,它被复制到 Spring Integration 或从 Spring Integration 复制MessageHeaders
通过使用DefaultSoapHeaderMapper
.
您可以传入自己的 SOAP 特定标头映射器的实现,因为网关具有支持这样做的属性。
除非requestHeaderNames
或replyHeaderNames
属性DefaultSoapHeaderMapper
,则不会将任何用户定义的 SOAP 标头复制到 SOAP 消息或从 SOAP 消息复制。
使用 XML 命名空间进行配置时,可以使用mapped-request-headers
和mapped-reply-headers
属性,您可以通过将header-mapper
属性。
映射用户定义的标头时,值还可以包含简单的通配符模式(例如myheader* 或myheader ).
例如,如果需要复制所有用户定义的标头,可以使用通配符: . |
从 4.1 版本开始,AbstractHeaderMapper
(一个DefaultSoapHeaderMapper
超类)让NON_STANDARD_HEADERS
为requestHeaderNames
和replyHeaderNames
属性(除了现有的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
未映射。
以下示例演示如何获取名为user
从名为auth
:
...
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
选项)。
从 V5.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));