1. 概述
之前我们已经演示过如何使用 Spring 构建一个 SOAP Web 服务。
本文将重点讲解如何基于 Spring 构建一个客户端来消费这个 SOAP 服务。
我们曾在另一篇文章 Java 中调用 SOAP Web 服务 中使用 JAX-WS RI 实现过类似功能。而本篇则聚焦于 Spring WS 的方式,更加契合 Spring 生态,集成也更简洁。
2. 回顾:Spring 中的 SOAP Web 服务
在前面的教程中,我们基于 Spring 实现了一个根据国家名称查询国家信息的 Web 服务。在进入客户端开发之前,先快速回顾一下服务端的关键结构。
我们采用的是 契约优先(Contract-First) 的开发方式:
- ✅ 编写 XSD 文件定义数据模型和接口契约
- ✅ 使用
jaxb2-maven-plugin
根据 XSD 自动生成 Java 类(请求、响应、实体) - ✅ 实现四个核心类:
CountryEndpoint
:处理请求的接口实现CountryRepository
:提供数据访问WebServiceConfig
:配置 Spring WS 所需的 BeanApplication
:Spring Boot 启动类
最后通过 cURL 发送 SOAP 请求完成了测试。
现在我们只需启动该服务(运行 Spring Boot 应用),就可以开始构建客户端了。
3. 客户端实现
接下来我们将 构建一个 Spring 客户端来调用并测试上述 Web 服务。
整个过程可以分为以下几个步骤。
3.1 生成客户端代码
首先,我们需要根据服务端提供的 WSDL 自动生成客户端所需的 Java 类。WSDL 地址如下:
http://localhost:8080/ws/countries.wsdl
我们将这个 WSDL 文件下载并保存到项目的 src/main/resources
目录下。
然后,在 pom.xml
中添加 maven-jaxb2-plugin
插件来自动生成代码:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.15.3</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaLanguage>WSDL</schemaLanguage>
<generateDirectory>${project.basedir}/src/main/java</generateDirectory>
<generatePackage>com.baeldung.springsoap.client.gen</generatePackage>
<schemaDirectory>${project.basedir}/src/main/resources</schemaDirectory>
<schemaIncludes>
<include>countries.wsdl</include>
</schemaIncludes>
</configuration>
</plugin>
⚠️ 插件配置说明:
generateDirectory
:生成类的输出目录generatePackage
:生成类所属的包名schemaDirectory
和schemaIncludes
:指定 WSDL 文件路径和名称
执行以下命令触发代码生成:
mvn compile
✅ 生成的类与服务端基本一致,主要包括:
Country.java
,Currency.java
:数据模型 POJOGetCountryRequest.java
:请求对象GetCountryResponse.java
:响应对象
这就是契约优先的好处——只要拿到 WSDL,客户端就能生成完全匹配的类型,不怕对接出错。
3.2 CountryClient:封装调用逻辑
接下来我们需要创建一个客户端类,继承 Spring 提供的 WebServiceGatewaySupport
,以便使用其内置的 WebServiceTemplate
。
定义 CountryClient
类如下:
public class CountryClient extends WebServiceGatewaySupport {
public GetCountryResponse getCountry(String country) {
GetCountryRequest request = new GetCountryRequest();
request.setName(country);
GetCountryResponse response = (GetCountryResponse) getWebServiceTemplate()
.marshalSendAndReceive(request);
return response;
}
}
📌 关键点解析:
- ✅
getCountry()
方法对应服务端暴露的操作 - ✅ 创建
GetCountryRequest
并设置参数 - ✅ 调用
marshalSendAndReceive()
完成 SOAP 请求/响应交换 - ✅ 返回反序列化后的
GetCountryResponse
底层的 XML 序列化/反序列化由 Marshaller
自动完成,我们无需手动处理 SOAP 消息体。
3.3 CountryClientConfig:配置客户端 Bean
为了让 CountryClient
正常工作,我们需要配置两个核心 Bean:
Jaxb2Marshaller
:负责 Java 对象与 XML 之间的转换CountryClient
:封装调用逻辑的客户端实例
配置类如下:
@Configuration
public class CountryClientConfig {
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.baeldung.springsoap.client.gen");
return marshaller;
}
@Bean
public CountryClient countryClient(Jaxb2Marshaller marshaller) {
CountryClient client = new CountryClient();
client.setDefaultUri("http://localhost:8080/ws");
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}
}
⚠️ 注意事项:
marshaller.setContextPath()
必须与pom.xml
中generatePackage
一致setDefaultUri()
设置的是服务端的 SOAP 接口地址,对应 WSDL 中的<soap:address location="..."/>
- 同时设置
marshaller
和unmarshaller
,确保收发都能正常处理
4. 测试客户端功能
使用 JUnit 编写集成测试,验证客户端是否能正确调用远程服务。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CountryClientConfig.class, loader = AnnotationConfigContextLoader.class)
public class ClientLiveTest {
@Autowired
CountryClient client;
@Test
public void givenCountryService_whenCountryPoland_thenCapitalIsWarsaw() {
GetCountryResponse response = client.getCountry("Poland");
assertEquals("Warsaw", response.getCountry().getCapital());
}
@Test
public void givenCountryService_whenCountrySpain_thenCurrencyEUR() {
GetCountryResponse response = client.getCountry("Spain");
assertEquals(Currency.EUR, response.getCountry().getCurrency());
}
}
✅ 测试要点:
- 使用
@ContextConfiguration
加载CountryClientConfig
配置类 - 自动注入
CountryClient
实例 - 调用
getCountry()
获取响应 - 利用生成的 POJO(如
Country
,Currency
)进行断言,类型安全且直观
运行测试前请确保服务端已启动,否则会报连接超时 ❌。
5. 总结
本文演示了如何使用 Spring WS 构建一个 简洁、类型安全的 SOAP 客户端。
核心流程总结如下:
- ✅ 获取 WSDL 文件
- ✅ 使用
maven-jaxb2-plugin
自动生成客户端类 - ✅ 继承
WebServiceGatewaySupport
封装调用逻辑 - ✅ 配置
Jaxb2Marshaller
和客户端 Bean - ✅ 编写测试验证功能
虽然我们只实现了最基础的调用,但 Spring WS 的能力远不止于此。比如它还支持:
- 拦截器(Interceptors)
- 错误处理(Fault Handling)
- 异步调用
- 安全(Spring Security 集成)
感兴趣的同学可以进一步查阅官方文档:Spring WS Reference
✅ 源码已上传至 GitHub:https://github.com/eugenp/tutorials/tree/master/spring-soap
建议集合,以后对接老系统踩坑时可以直接参考。