|
此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Integration 6.5.1! |
Web 服务支持
本章介绍了 Spring Integration 对 Web 服务的支持,包括:
项目需要此依赖项:
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-ws</artifactId>
<version>7.0.0-SNAPSHOT</version>
</dependency>
compile "org.springframework.integration:spring-integration-ws:7.0.0-SNAPSHOT"
出站 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 ServicesDestinationProviderJavadoc 以获取有关此策略的更多信息。 |
从 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-templatereference 属性允许您注入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));