领先一步
VMware 提供培训和认证,助您加速进步。
了解更多经过近一年的开发,我很高兴地宣布 Spring Web Services 2.0 已经发布!在这篇文章中,我将介绍一些主要的新特性。
正如您可能已经知道的,我们将对象 XML 映射 (OXM) 模块从 Spring-WS 项目移到了 Spring 3.0 中。因此,由于 org.springframework.oxm 包中存在冲突的类,使用 Spring-WS 1.5(带有自己的 OXM 模块)与 Spring 3.0 可能会有些问题。
从2.0版本开始,我们不再将OXM模块作为Spring-WS的一部分发布,而是依赖于Spring的OXM。因此,Spring Web Services 2.0需要Spring 3.0才能工作。通常,我们对版本要求会更宽松一些,不一定要求最新的Spring版本,但这是唯一能让一切正常工作的方式。
由于依赖于Spring 3.0,我们也有了Java 5+的要求,并且整个代码库都使用了Java 5的特性(例如泛型、可变参数和枚举),只要它们有意义。例如,与XPathTemplate结合使用的NodeMapper接口现在是泛型的,因此不再需要进行类型转换
Person person = template.evaluateAsObject("//person", new DOMSource(document), new NodeMapper<Person>() {
public Person mapNode(Node node, int nodeNum) throws DOMException {
Element personElement = (Element) node;
return new Person(personElement.getAttribute("firstName"), personElement.getAttribute("lastName"));
}
});
请注意,尽管我们确实将代码库升级为使用Java 5+特性,但我们是以向后兼容的方式进行的。因此,Spring Web Services 2.0向后兼容1.5。但是,我们确实删除了已弃用的类。例如,XsdBasedSoap11Wsdl4jDefinitionBuilder已被DefaultWsdl11Definition取代,后者具有相同的功能,但可定制性更强。
Spring Web Services 2.0最重要的一个新特性是能够在@Endpoint方法中使用任意参数类型。Spring-WS 1.5的@Endpoint模型的一大改进是,您现在可以混合和匹配参数,并且返回类型不再那么受限。基本上,这将Spring-WS的@Endpoint编程模型提升到了与Spring 3的@Controller模型相同的水平。
例如,您可以有以下@Endpoint方法
@PayloadRoot(localPart = "myRequest", namespace = "http://example.com")
@ResponsePayload
public MyJaxb2Response handleMyRequest(@RequestPayload org.w3c.dom.Element myElement,
SoapHeader requestHeader,
MessageContext messageContext) {
// do something interesting here
}
此方法将接收所有载荷根元素具有“http://example.com”命名空间和“myRequest”本地名称的SOAP消息。此载荷将作为W3C DOM元素传递,并结合SoapHeader(用于访问单个头部元素)和整个消息上下文。
目前支持的参数/返回类型包括
要将请求消息的载荷作为这些参数类型中的任何一种获取,您需要用@RequestPayload注解该参数。同样,如果您希望返回值最终出现在响应消息的载荷中,您需要用@ResponsePayload注解该方法。这与Spring 3的@Controller模型非常相似,在该模型中我们有@RequestBody和@ResponseBody,它们在HTTP空间中提供类似的功能。
此外,我们支持以下没有@RequestPayload的参数类型
@Namespaces(@Namespace(prefix = "tns", uri = "http://springframework.org/spring-ws"))
public void myEndpointMethod(@XPathParam("/tns:root")String s) {
// do something slightly more interesting here
}
这些命名空间注解(@Namespace和@Namespaces)可以出现在方法、类或包级别(即package-info.java)上。
要启用此编程模型,您只需在Spring Web Services应用程序上下文中放置<sws:annotation-driven/>即可
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sws="http://www.springframework.org/schema/web-services"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd">
<sws:annotation-driven/>
<!-- other beans go here, or perhaps a <context:component-scan/> -->
</beans>
您可以选择为此元素提供marshaller和unmarshaller属性,分别指向一个OXM Marshaller和Unmarshaller。这将启用支持使用此marshaller支持的类型作为@RequestPayload/@ResponsePayload类型。
请注意,我们还弃用了对<sws:marshalling-endpoints/>和<sws:xpath-endpoints/>的支持,转而支持<sws:annotation-driven/>。因此,这两个元素在XSD模式的2.0版本中不存在,但仍存在于其1.5版本中。所以您可以坚持使用1.5版本的模式,或者升级到2.0并使用<sws:annotation-driven/>。
最后,正如Spring中的所有内容一样,参数/返回类型机制是完全可插拔的。因此,如果您没有看到您想看到的参数类型,请随意编写您自己的MethodArgumentResolver或MethodReturnValueHandler,将其插入Spring-WS,然后就大功告成了!
另一个主要的新特性是新的Web服务集成测试模块spring-ws-test。此模块包含测试客户端(即使用WebServiceTemplate的类)和服务器(即@Endpoints)的功能。客户端和服务器端测试模块都提供了“流畅”的API,因此您通常可以使用IDE中的代码完成功能(即ctrl-space)来指导您完成测试设置过程。
测试客户端代码的典型场景包括
例如,考虑这个Web服务客户端类
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
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的典型测试将如下所示
import javax.xml.transform.Source;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.xml.transform.StringSource;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
import org.springframework.ws.test.client.MockWebServiceServer;
import static org.springframework.ws.test.client.RequestMatchers.*;
import static org.springframework.ws.test.client.ResponseCreators.*;
@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();
}
}
有关客户端测试的更多信息,请参阅参考手册。
执行服务器端集成测试的核心类是MockWebServiceClient。其基本思想是,此客户端创建请求消息,然后将其发送到标准MessageDispatcherServlet应用程序上下文中配置的端点。这些端点将处理消息并创建响应。然后,客户端接收此响应,并根据注册的期望对其进行验证。
MockWebServiceClient的典型用法是
例如,考虑这个简单的Web服务端点类
@Endpoint
public class CustomerEndpoint {
@ResponsePayload
public CustomerCountResponse getCustomerCount(
@RequestPayload CustomerCountRequest request) {
CustomerCountResponse response = new CustomerCountResponse();
response.setCustomerCount(10);
return response;
}
}
CustomerEndpoint的典型测试将如下所示
import javax.xml.transform.Source;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.xml.transform.StringSource;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.ws.test.server.MockWebServiceClient;
import static org.springframework.ws.test.server.RequestCreators.*;
import static org.springframework.ws.test.server.ResponseMatchers.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("spring-ws-servlet.xml")
public class CustomerEndpointIntegrationTest {
@Autowired
private ApplicationContext applicationContext;
private MockWebServiceClient mockClient;
@Before
public void createClient() {
mockClient = MockWebServiceClient.createClient(applicationContext);
}
@Test
public void customerEndpoint() 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>");
mockClient.sendRequest(withPayload(requestPayload)).
andExpect(payload(responsePayload));
}
}
有关服务器端测试的更多信息,请参阅参考手册。
如果您想尝试Spring Web Services 2.0,可以访问网站,或直接前往下载。如果您使用Maven,升级应该很简单,只需添加以下仓库
<repository>
<id>spring-release</id>
<name>Spring Release Repository</name>
<url>http://maven.springframework.org/release</url>
</repository>
然后可以像这样添加单个依赖项
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-core</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
这些jar应该很快就可以在Maven Central上找到。
最后,我要感谢Lukáš Křečan和Tareq Abed Rabbo。这两位社区成员在本次发布的开发过程中提供了巨大的帮助。