构成 Spring Web 服务的各种组件(二)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了构成 Spring Web 服务的各种组件(二)相关的知识,希望对你有一定的参考价值。

构成

6. 在客户端上使用 Spring Web 服务

Spring-WS提供了一个客户端Web服务API,允许对Web服务进行一致的XML驱动访问。它还迎合了编组程序和取消编组程序的使用,以便服务层代码可以专门处理 Java 对象。

该包提供了使用客户端访问 API 的核心功能。它包含简化Web服务的使用的模板类,就像Spring核心对JDBC所做的那样。Spring 模板类的共同设计原则是提供辅助方法来执行常见操作,并且对于更复杂的用法,委托给用户实现的回调接口。Web 服务模板遵循相同的设计。这些类提供了各种方便的方法​​org.springframework.ws.client.core​​​​JdbcTemplate​

  • 发送和接收 XML 消息
  • 在发送之前将对象封送到 XML
  • 允许多种运输选择

6.1. 使用客户端 API

本节介绍如何使用客户端 API。有关如何使用服务器端 API,请参阅 使用 Spring-WS 创建 Web 服务。

6.1.1.​​WebServiceTemplate​

这是 Spring-WS 中客户端 Web 服务访问的核心类。它包含用于发送对象和接收响应消息作为 or 的方法。此外,它可以在通过传输发送对象之前将对象封送到 XML,并再次将任何响应 XML 取消封送到对象中。​​WebServiceTemplate​​​​Source​​​​Source​​​​Result​

URI 和传输

该类使用 URI 作为消息目标。可以在模板本身上设置属性,也可以在模板上调用方法时显式提供 URI。URI 解析为 ,负责跨传输层发送 XML 消息。可以使用类的 or 属性设置一个或多个邮件发件人。​​WebServiceTemplate​​​​defaultUri​​​​WebServiceMessageSender​​​​messageSender​​​​messageSenders​​​​WebServiceTemplate​

HTTP 传输

有两种用于通过 HTTP 发送消息的接口实现。默认实现是 ,它使用 Java 本身提供的工具。另一种方法是使用 Apache HttpComponents HttpClient。如果需要更高级且易于使用的功能(如身份验证、HTTP 连接池等),请使用后者。​​WebServiceMessageSender​​​​HttpUrlConnectionMessageSender​​​​HttpComponentsMessageSender​

若要使用 HTTP 传输,请将 设置为 like 或为其中一个方法提供参数。​​defaultUri​​​​http://example.com/services​​​​uri​

以下示例演示如何使用 HTTP 传输的默认配置:

<beans>

<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="defaultUri" value="http://example.com/WebService"/>
</bean>

</beans>

以下示例演示如何覆盖默认配置以及如何使用 Apache HttpClient 通过 HTTP 身份验证进行身份验证:

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="messageSender">
<bean class="org.springframework.ws.transport.http.HttpComponentsMessageSender">
<property name="credentials">
<bean class="org.apache.http.auth.UsernamePasswordCredentials">
<constructor-arg value="john:secret"/>
</bean>
</property>
</bean>
</property>
<property name="defaultUri" value="http://example.com/WebService"/>
</bean>
联医系统传输

为了通过JMS发送消息,Spring Web Services提供了.这个类使用Spring框架的功能将JMS转换为JMS,在或上发送它,并接收响应(如果有的话)。​​JmsMessageSender​​​​WebServiceMessage​​​​Message​​​​Queue​​​​Topic​

要使用 ,您需要将 or 参数设置为 JMS URI,该 URI 至少由前缀和目标名称组成。JMS URI 的一些示例包括:、 和 。有关此 URI 语法的更多信息,请参阅 Javadoc for JmsMessageSender。​​JmsMessageSender​​​​defaultUri​​​​uri​​​​jms:​​​​jms:SomeQueue​​​​jms:SomeTopic?priority=3&deliveryMode=NON_PERSISTENT​​​​jms:RequestQueue?replyToName=ResponseName​

默认情况下,发送 JMS ,但您可以使用 JMS URI 上的参数覆盖它以使用,例如 。请注意,这是首选类型,因为 不支持附件和字符编码。​​JmsMessageSender​​​​BytesMessage​​​​TextMessages​​​​messageType​​​​jms:Queue?messageType=TEXT_MESSAGE​​​​BytesMessages​​​​TextMessages​

以下示例显示如何将 JMS 传输与 ActiveMQ 连接工厂结合使用:

<beans>

<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>

<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost?broker.persistent=false"/>
</bean>

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="messageSender">
<bean class="org.springframework.ws.transport.jms.JmsMessageSender">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
</property>
<property name="defaultUri" value="jms:RequestQueue?deliveryMode=NON_PERSISTENT"/>
</bean>

</beans>
电子邮件传输

Spring Web Services 还提供了电子邮件传输,您可以使用它通过 SMTP 发送 Web 服务消息,并通过 POP3 或 IMAP 检索它们。客户端电子邮件功能包含在类中。此类从请求创建电子邮件,并通过 SMTP 发送。然后,它等待响应消息到达传入的 POP3 或 IMAP 服务器。​​MailMessageSender​​​​WebServiceMessage​

要使用 ,请将 or 参数设置为 URI,例如 or 。确保邮件发件人正确配置了 ,前者指示用于发送请求的服务器(通常是 SMTP 服务器),后者指示要轮询响应的服务器(通常为 POP3 或 IMAP 服务器)。​​MailMessageSender​​​​defaultUri​​​​uri​​​​mailto​​​​mailto:john@example.com​​​​mailto:server@localhost?subject=SOAP%20Test​​​​transportUri​​​​storeUri​

以下示例演示如何使用电子邮件传输:

<beans>

<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="messageSender">
<bean class="org.springframework.ws.transport.mail.MailMessageSender">
<property name="from" value="Spring-WS SOAP Client <client@example.com>"/>
<property name="transportUri" value="smtp://client:s04p@smtp.example.com"/>
<property name="storeUri" value="imap://client:s04p@imap.example.com/INBOX"/>
</bean>
</property>
<property name="defaultUri" value="mailto:server@example.com?subject=SOAP%20Test"/>
</bean>

</beans>
XMPP 运输

Spring Web Services 2.0引入了XMPP(Jabber)传输,您可以使用它通过XMPP发送和接收Web服务消息。客户端 XMPP 功能包含在类中。此类从请求创建 XMPP 消息,并通过 XMPP 发送该消息。然后,它会侦听响应消息到达。​​XmppMessageSender​​​​WebServiceMessage​

要使用 ,请将 or 参数设置为 URI,例如 。发送方还需要 才能工作,可以使用 .​​XmppMessageSender​​​​defaultUri​​​​uri​​​​xmpp​​​​xmpp:johndoe@jabber.org​​​​XMPPConnection​​​​org.springframework.ws.transport.xmpp.support.XmppConnectionFactoryBean​

以下示例演示如何使用 XMPP 传输:

<beans>

<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>

<bean id="connection" class="org.springframework.ws.transport.xmpp.support.XmppConnectionFactoryBean">
<property name="host" value="jabber.org"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
</bean>

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="messageSender">
<bean class="org.springframework.ws.transport.xmpp.XmppMessageSender">
<property name="connection" ref="connection"/>
</bean>
</property>
<property name="defaultUri" value="xmpp:user@jabber.org"/>
</bean>

</beans>
消息工厂

除了消息发送者之外,还需要 Web 服务消息工厂。SOAP 有两个消息工厂:和 。如果未指定消息工厂(通过设置属性),则默认情况下 Spring-WS 使用 。​​WebServiceTemplate​​​​SaajSoapMessageFactory​​​​AxiomSoapMessageFactory​​​​messageFactory​​​​SaajSoapMessageFactory​

6.1.2. 发送和接收​​WebServiceMessage​

包含许多发送和接收 Web 服务消息的便捷方法。有接受并返回 a 的方法,也有返回 .此外,还有一些方法可以将对象封送和取消封送到 XML。下面的示例将简单的 XML 消息发送到 Web 服务:​​WebServiceTemplate​​​​Source​​​​Result​

import java.io.StringReader;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.WebServiceMessageSender;

public class WebServiceClient

private static final String MESSAGE =
"<message xmlns=\\"http://tempuri.org\\">Hello, Web Service World</message>";

private final WebServiceTemplate webServiceTemplate = new WebServiceTemplate();

public void setDefaultUri(String defaultUri)
webServiceTemplate.setDefaultUri(defaultUri);


// send to the configured default URI
public void simpleSendAndReceive()
StreamSource source = new StreamSource(new StringReader(MESSAGE));
StreamResult result = new StreamResult(System.out);
webServiceTemplate.sendSourceAndReceiveToResult(source, result);


// send to an explicit URI
public void customSendAndReceive()
StreamSource source = new StreamSource(new StringReader(MESSAGE));
StreamResult result = new StreamResult(System.out);
webServiceTemplate.sendSourceAndReceiveToResult("http://localhost:8080/AnotherWebService",
source, result);


<beans xmlns="http://www.springframework.org/schema/beans">

<bean id="webServiceClient" class="WebServiceClient">
<property name="defaultUri" value="http://localhost:8080/WebService"/>
</bean>

</beans>

前面的示例使用 将“Hello, World”消息发送到位于(在方法的情况下)的 Web 服务,并将结果写入控制台。注入了缺省 URI,之所以使用该 URI,是因为 Java 代码中没有显式提供 URI。​​WebServiceTemplate​​​​http://localhost:8080/WebService​​​​simpleSendAndReceive()​​​​WebServiceTemplate​

请注意,该类一旦配置,就是线程安全的(假设它的所有依赖项也是线程安全的,Spring-WS 附带的所有依赖项都是这种情况),因此多个对象可以使用同一个共享实例。它公开了一个零参数构造函数和 Bean 属性,您可以使用这些构造函数和 Bean 属性(通过使用 Spring 容器或纯 Java 代码)。或者,考虑从 Spring-WS 的便利基类派生,该基类公开了方便的 Bean 属性以实现轻松配置。(您不必扩展此基类。它仅作为便利类提供。​​WebServiceTemplate​​​​WebServiceTemplate​​​​WebServiceTemplate​​​​messageFactory​​​​messageSender​​​​WebServiceGatewaySupport​

6.1.3. 发送和接收 POJO — 编组和解组

为了便于发送纯 Java 对象,有许多方法将 a 作为消息数据内容的参数。类中的方法将请求对象到 XML 的转换委托给 ,并将响应 XML 到对象的转换委托给 。(有关编组和取消编组器的更多信息,请参阅 Spring 框架参考文档。通过使用封送器,应用程序代码可以专注于正在发送或接收的业务对象,而不关心它如何表示为 XML 的详细信息。若要使用编组功能,必须使用类的 and 属性设置编组器和取消编组器。​​WebServiceTemplate​​​​send(..)​​​​Object​​​​marshalSendAndReceive(..)​​​​WebServiceTemplate​​​​Marshaller​​​​Unmarshaller​​​​marshaller​​​​unmarshaller​​​​WebServiceTemplate​

6.1.4. 使用​​WebServiceMessageCallback​

为了适应在消息上设置 SOAP 标头和其他设置,该接口允许您在创建消息之后但在发送消息之前访问消息。下面的示例演示如何在通过封送对象创建的消息上设置 SOAP 操作标头:​​WebServiceMessageCallback​

public void marshalWithSoapActionHeader(MyObject o) 

webServiceTemplate.marshalSendAndReceive(o, new WebServiceMessageCallback()

public void doWithMessage(WebServiceMessage message)
((SoapMessage)message).setSoapAction("http://tempuri.org/Action");

);

请注意,您还可以使用 来设置 SOAP 操作标头。​​org.springframework.ws.soap.client.core.SoapActionCallback​

WS-寻址

除了服务器端WS-Addressing支持之外,Spring Web Services在客户端也支持此规范。

要在客户端上设置 WS 寻址标头,可以使用 。此回调将所需的操作标头作为参数。它还具有用于指定 WS 寻址版本和标头的构造函数。如果未指定,则标头默认为正在建立的连接的 URL。​​org.springframework.ws.soap.addressing.client.ActionCallback​​​​To​​​​To​

下面的示例将标头设置为 :​​Action​​​​http://samples/RequestOrder​

webServiceTemplate.marshalSendAndReceive(o, new ActionCallback("http://samples/RequestOrder"));

6.1.5. 使用​​WebServiceMessageExtractor​

该接口是一个低级回调接口,您可以完全控制从收到的 .在与服务资源的基础连接仍处于打开状态时,在提供的 上调用该方法。以下示例显示了 in 操作:​​WebServiceMessageExtractor​​​​Object​​​​WebServiceMessage​​​​WebServiceTemplate​​​​extractData(..)​​​​WebServiceMessageExtractor​​​​WebServiceMessageExtractor​

public void marshalWithSoapActionHeader(final Source s) 
final Transformer transformer = transformerFactory.newTransformer();
webServiceTemplate.sendAndReceive(new WebServiceMessageCallback()
public void doWithMessage(WebServiceMessage message)
transformer.transform(s, message.getPayloadResult());
,
new WebServiceMessageExtractor()
public Object extractData(WebServiceMessage message) throws IOException
// do your own transforms with message.getPayloadResult()
// or message.getPayloadSource()


);

6.2. 客户端测试

在测试 Web 服务客户端(即使用 访问 Web 服务的类)时,有两种可能的方法:​​WebServiceTemplate​

  • 编写单元测试,模拟类、接口或完整的客户端类。WebServiceTemplateWebServiceOperations

    这种方法的优点是很容易实现。缺点是,您并没有真正测试通过网络发送的 XML 消息的确切内容,尤其是在模拟整个客户端类时。
  • 编写集成测试,测试消息的内容。

第一种方法可以通过模拟框架轻松实现,例如EasyMock,JMock等。下一节重点介绍如何使用 Spring Web Services 2.0 中引入的测试功能编写集成测试。

6.2.1. 编写客户端集成测试

Spring Web Services 2.0引入了对创建Web服务客户端集成测试的支持。在此上下文中,客户端是使用 访问 Web 服务的类。​​WebServiceTemplate​

集成测试支持位于包中。该包中的核心类是 .基本思想是 Web 服务模板连接到此模拟服务器并向其发送请求消息,然后模拟服务器根据注册的期望对其进行验证。如果满足预期,模拟服务器将准备一条响应消息,该消息将发送回模板。​​org.springframework.ws.test.client​​​​MockWebServiceServer​

的典型用法是:。​​MockWebServiceServer​

  1. 通过调用 、 或 创建实例。MockWebServiceServerMockWebServiceServer.createServer(WebServiceTemplate)MockWebServiceServer.createServer(WebServiceGatewaySupport)MockWebServiceServer.createServer(ApplicationContext)
  2. 通过调用 来设置请求期望,可能使用 中提供的默认实现(可以静态导入)。可以通过链接呼叫来设置多个期望。expect(RequestMatcher)RequestMatcherRequestMatchersandExpect(RequestMatcher)
  3. 通过调用 来创建适当的响应消息,可能使用 中提供的默认实现(可以静态导入)。andRespond(ResponseCreator)ResponseCreatorResponseCreators
  4. 像往常一样使用,直接或通过客户端代码。WebServiceTemplate
  5. 致电以确保满足所有期望。MockWebServiceServer.verify()

请注意,(和相关类)提供了“流畅”的 API,因此您通常可以使用 IDE 中的代码完成功能来指导您完成设置模拟服务器的过程。​​MockWebServiceServer​

另请注意,在单元测试中,您可以依赖 Spring Web Services 中提供的标准日志记录功能。有时,检查请求或响应消息以找出特定测试失败的原因可能很有用。有关详细信息,请参阅消息日志记录和跟踪。

例如,请考虑以下 Web 服务客户端类:

public class CustomerClient extends WebServiceGatewaySupport                           

public int getCustomerCount()
CustomerCountRequest request = new CustomerCountRequest();
request.setCustomerName("John Doe");

CustomerCountResponse response =
(CustomerCountResponse) getWebServiceTemplate().marshalSendAndReceive(request);

return response.getCustomerCount();


扩展,这为它提供了一个属性。​​CustomerClient​​​​WebServiceGatewaySupport​​​​webServiceTemplate​

​CustomerCountRequest​​​是由编组器支持的对象。例如,它可以有一个由 JAXB2 支持的注释。​​@XmlRootElement​

使用 提供的 by 将请求对象封送到 SOAP 消息中,并将其发送到 Web 服务。响应对象被解组为 .​​CustomerClient​​​​WebServiceTemplate​​​​WebServiceGatewaySupport​​​​CustomerCountResponse​

以下示例显示了 的典型测试:​​CustomerClient​

@RunWith(SpringJUnit4ClassRunner.class)                                                 
@ContextConfiguration("integration-test.xml")
public class CustomerClientIntegrationTest

@Autowired
private CustomerClient client;

private MockWebServiceServer mockServer;

@Before
public void createServer() throws Exception
mockServer = MockWebServiceServer.createServer(client);


@Test
public void customerClient() throws Exception
Source requestPayload = new StringSource(
"<customerCountRequest xmlns=http://springframework.org/spring-ws>" +
"<customerName>John Doe</customerName>" +
"</customerCountRequest>");
Source responsePayload = new StringSource(
"<customerCountResponse xmlns=http://springframework.org/spring-ws>" +
"<customerCount>10</customerCount>" +
"</customerCountResponse>");

mockServer.expect(payload(requestPayload)).andRespond(withPayload(responsePayload));

int result = client.getCustomerCount();
assertEquals(10, result);

mockServer.verify();



导入和静态导入和 .​​CustomerClientIntegrationTest​​​​MockWebServiceServer​​​​RequestMatchers​​​​ResponseCreators​


此测试使用 Spring 框架中提供的标准测试工具。这不是必需的,但通常是设置测试的最简单方法。


使用 配置并连接到此测试中。​​CustomerClient​​​​integration-test.xml​​​​@Autowired​


在方法中,我们使用工厂方法创建一个。​​@Before​​​​MockWebServiceServer​​​​createServer​


我们通过调用静态导入的 a 来定义期望(请参阅​​使用 RequestMatcher 和 RequestMatchers​​​)。​​expect()​​​​payload()​​​​RequestMatcher​​​​RequestMatchers​


我们还通过使用静态导入提供的调用来设置响应(请参阅​​使用 ResponseCreator 和 ResponseCreators​​​)。​​andRespond()​​​​withPayload()​​​​ResponseCreator​​​​ResponseCreators​



测试的这一部分可能看起来有点混乱,但 IDE 的代码完成功能非常有用。键入 后,IDE 可以为您提供可能的请求匹配策略列表,前提是静态导入 。这同样适用于 ,前提是您静态导入 。​​expect(​​​​RequestMatchers​​​​andRespond(​​​​ResponseCreators​



我们调用 ,因此使用 .到目前为止,模板已设置为“测试模式”,因此此方法调用不会建立真正的 (HTTP) 连接。我们还根据方法调用的结果做出一些 JUnit 断言。​​getCustomerCount()​​​​CustomerClient​​​​WebServiceTemplate​


我们调用 ,验证是否实际收到了预期的消息。​​verify()​​​​MockWebServiceServer​

6.2.2. 使用 和​​RequestMatcher​​​​RequestMatchers​

为了验证请求消息是否满足某些期望,请使用策略接口。此接口定义的协定如下:​​MockWebServiceServer​​​​RequestMatcher​

public interface RequestMatcher 

void match(URI uri,
WebServiceMessage request)
throws IOException,
AssertionError;

您可以编写自己的此接口实现,在消息不符合您的期望时引发异常,但您当然不必这样做。该类提供了标准实现,供您在测试中使用。通常静态导入此类。​​AssertionError​​​​RequestMatchers​​​​RequestMatcher​

该类提供以下请求匹配器:​​RequestMatchers​

​RequestMatchers​​方法

描述

​anything()​

期望任何类型的请求。

​payload()​

需要给定的请求有效负载。

​validPayload()​

期望请求有效负载根据给定的 XSD 架构进行验证。

​xpath()​

期望给定的 XPath 表达式存在、不存在或计算为给定值。

​soapHeader()​

期望请求消息中存在给定的 SOAP 标头。

​connectionTo()​

需要与给定 URL 的连接。

您可以通过链接调用来设置多个请求期望:​​andExpect()​

mockServer.expect(connectionTo("http://example.com")).
andExpect(payload(expectedRequestPayload)).
andExpect(validPayload(schemaResource)).
andRespond(...);

有关 提供的请求匹配器的更多信息,请参阅 Javadoc。​​RequestMatchers​

6.2.3. 使用 和​​ResponseCreator​​​​ResponseCreators​

当请求消息经过验证并满足定义的期望时,将创建响应消息供 使用。服务器使用策略接口来实现此目的:​​MockWebServiceServer​​​​WebServiceTemplate​​​​ResponseCreator​

public interface ResponseCreator 

WebServiceMessage createResponse(URI uri,

以上是关于构成 Spring Web 服务的各种组件(二)的主要内容,如果未能解决你的问题,请参考以下文章

[Java Web] Spring

图解 Spring:HTTP 请求的处理流程与机制

图解 Spring:HTTP 请求的处理流程与机制

图解 Spring:HTTP 请求的处理流程与机制

图解 Spring:HTTP 请求的处理流程与机制

HTTP -- 认识HTTP和HTTP相关组件(网络模型游览器Web服务器CDNWAFWeb ServiceHTMLWeb页面的构成)