- JAX-WS (Java API for XML Web Services):Java 官方标准,用于创建和消费 SOAP WebService,最简单,适合调用已经存在的、基于 SOAP 的服务。
- Apache CXF:一个功能强大的开源框架,既支持 SOAP 也支持 RESTful (JAX-RS),它比 JAX-WS 更灵活,功能更丰富,是企业级开发中的常用选择。
- Spring Boot + RestTemplate / WebClient:现代 Java 开发的主流方式,如果你的 WebService 是 RESTful 风格(返回 JSON/XML 数据),这是最推荐的方式,因为它与 Spring 生态系统无缝集成。
场景设定
为了方便演示,我们假设有一个简单的 WebService,它提供以下功能:

- 地址:
http://www.webxml.com.cn/webservices/qqOnlineWebService.asmx?wsdl - 功能: 查询 QQ 号码是否在线。
- 操作:
qqCheckOnline - 参数:
qqCode(字符串) - 返回值: 一个字符串,如 "Y" (在线) 或 "N" (离线)
这个服务是公开的,非常适合用来做示例。
使用 JAX-WS (最简单、最直接)
JAX-WS 是 Java 标准库的一部分(从 JDK 1.6 开始),所以你不需要额外添加依赖(除了可能需要一些运行时库)。
步骤 1: 获取 WSDL 文件并生成客户端代码
你需要使用 JDK 自带的 wsimport 工具,根据 WSDL 文件生成一系列 Java 类(客户端存根),这些类封装了与服务器通信的细节。
打开你的命令行(CMD 或 PowerShell),执行以下命令:

# -keep: 生成源代码文件 # -d: 指定编译后的 .class 文件存放目录 # -p: 指定生成的包名 wsimport -keep -d D:\temp -p com.example.webservice.client http://www.webxml.com.cn/webservices/qqOnlineWebService.asmx?wsdl
执行成功后,你会在 D:\temp\com\example\webservice\client 目录下看到一堆 .java 和 .class 文件,其中最重要的是 QQOnlineWebService 和 QQOnlineWebServiceService。
步骤 2: 在项目中使用生成的客户端代码
- 将生成的
.class文件(或整个com.example.webservice.client包)添加到你的 Java 项目的 classpath 中。 - 编写调用代码。
import com.example.webservice.client.QQOnlineWebService;
import com.example.webservice.client.QQOnlineWebServiceService;
public class JaxWsClientExample {
public static void main(String[] args) {
// 1. 创建服务视图 (Service)
// QQOnlineWebServiceService 是 wsimport 生成的工厂类
QQOnlineWebServiceService service = new QQOnlineWebServiceService();
// 2. 获取服务端点 (Port)
// getQQOnlineWebServicePort() 方法返回一个代理对象,它实现了服务接口
QQOnlineWebService port = service.getQQOnlineWebServicePort();
// 3. 调用 WebService 方法
String qqNumber = "12345678"; // 你想查询的QQ号
String result = port.qqCheckOnline(qqNumber);
// 4. 处理结果
System.out.println("QQ号码 " + qqNumber + " 的在线状态是: " + result);
}
}
优点:
- 简单,是 Java 标准,无需额外依赖。
- IDE(如 IntelliJ IDEA、Eclipse)通常可以自动完成
wsimport的过程,更方便。
缺点:
- 主要用于 SOAP 协议,不够灵活。
- 生成的代码有时会很冗长,难以调试。
使用 Apache CXF (功能强大、灵活)
CXF 是一个更全面的框架,它支持 SOAP 和 REST,使用 CXF 调用 JAX-WS 服务同样非常简单,并且提供了更多高级特性。
步骤 1: 添加 Maven 依赖
在你的 pom.xml 文件中添加 CXF 的核心依赖:
<dependencies>
<!-- CXF 核心依赖 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.4.5</version> <!-- 使用最新稳定版 -->
</dependency>
<!-- CXF 的运行时依赖,包含 Jetty 服务器等 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.4.5</version>
</dependency>
</dependencies>
注意: CXF 也内置了 wsdl2java 工具,功能和 JDK 的 wsimport 类似,但更强大,你可以通过 Maven 插件或命令行使用它,但为了保持与 JAX-WS 示例的一致性,我们这里复用 JAX-WS 生成的客户端代码,只是用 CXF 的方式去调用它。
步骤 2: 使用 CXF 的 JAX-WS 前端调用服务
CXF 实现了 JAX-WS 规范,所以你可以用和标准 JAX-WS 几乎一样的方式调用,CXF 的优势在于你不需要关心底层实现,并且可以轻松添加拦截器、日志等功能。
import com.example.webservice.client.QQOnlineWebService;
import com.example.webservice.client.QQOnlineWebServiceService;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
public class CxfClientExample {
public static void main(String[] args) {
// 1. 创建 JaxWsProxyFactoryBean
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
// 2. 设置服务接口 (WSDL 中定义的 portType)
factory.setServiceClass(QQOnlineWebService.class);
// 3. 设置 WebService 的地址 (WSDL 中的 location)
factory.setAddress("http://www.webxml.com.cn/webservices/qqOnlineWebService.asmx");
// 4. 创建客户端代理对象
QQOnlineWebService service = factory.create(QQOnlineWebService.class);
// 5. 调用方法
String qqNumber = "87654321";
String result = service.qqCheckOnline(qqNumber);
// 6. 处理结果
System.out.println("使用 CXF 调用,QQ号码 " + qqNumber + " 的在线状态是: " + result);
}
}
优点:
- 功能强大,支持 SOAP 和 REST。
- 拥有丰富的插件机制(如日志、加密、WS-Security 等)。
- 社区活跃,文档完善。
缺点:
- 相比标准 JAX-WS,需要引入额外的框架依赖。
使用 Spring Boot + RestTemplate (现代 RESTful 服务首选)
如果你的 WebService 是 RESTful 风格(通常返回 JSON 或 XML),而不是 SOAP,那么这是最现代、最推荐的方式,我们以一个返回 JSON 的公共 API 为例。
场景设定:
- 地址:
http://api.exchangerate.host/latest?access_key=YOUR_KEY&base=USD&symbols=CNY - 功能: 获取美元对人民币的汇率。
- 返回格式: JSON
步骤 1: 创建 Spring Boot 项目并添加依赖
使用 Spring Initializr 创建项目,并添加 Spring Web 依赖。
步骤 2: 创建一个用于映射 JSON 的 Java 类 (POJO)
我们需要一个类来和返回的 JSON 结构对应。
// RateResponse.java
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true) // 忽略 JSON 中存在但 Java 类中没有的属性
public class RateResponse {
private String success;
private String base;
private String date;
private Rates rates;
// Getters and Setters
// ...
}
// Rates.java
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.Map;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Rates {
private Map<String, Double> rates;
// Getter and Setter
public Map<String, Double> getRates() {
return rates;
}
public void setRates(Map<String, Double> rates) {
this.rates = rates;
}
}
步骤 3: 配置 RestTemplate 并调用服务
在 Spring Boot 的主类或配置类中,声明一个 RestTemplate Bean。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class WebserviceApplication {
public static void main(String[] args) {
SpringApplication.run(WebserviceApplication.class, args);
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
步骤 4: 创建一个 Service 来调用 WebService
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class ExchangeRateService {
@Autowired
private RestTemplate restTemplate;
// 假设你有一个 API Key,这里用占位符
private final String API_KEY = "YOUR_API_KEY";
private final String API_URL = "http://api.exchangerate.host/latest?access_key=" + API_KEY + "&base=USD&symbols=CNY";
public double getUsdToCnyRate() {
// 使用 RestTemplate 发送 GET 请求,并将响应体自动映射为 RateResponse 对象
RateResponse response = restTemplate.getForObject(API_URL, RateResponse.class);
if (response != null && "true".equals(response.getSuccess())) {
// 从响应对象中提取汇率
return response.getRates().getRates().get("CNY");
} else {
throw new RuntimeException("Failed to get exchange rate");
}
}
}
步骤 5: 在 Controller 中调用 Service
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ExchangeRateController {
@Autowired
private ExchangeRateService exchangeRateService;
@GetMapping("/rate")
public String getRate() {
double rate = exchangeRateService.getUsdToCnyRate();
return "当前美元对人民币汇率为: " + rate;
}
}
启动 Spring Boot 应用,访问 http://localhost:8080/rate 即可看到结果。
优点:
- 现代标准:与 Spring 生态系统完美集成。
- 简洁易用:代码非常直观,基于 HTTP 协议,易于理解和调试。
- 灵活性高:可以轻松处理各种 HTTP 请求/响应,支持 JSON、XML 等多种数据格式。
- 异步支持:
WebClient(Spring WebFlux) 提供了强大的非阻塞异步调用能力。
缺点:
- 仅适用于 RESTful 风格的 WebService,不适用于 SOAP。
总结与如何选择
| 特性 | JAX-WS | Apache CXF | Spring Boot + RestTemplate |
|---|---|---|---|
| 适用协议 | SOAP | SOAP & REST | RESTful (首选) |
| 易用性 | 简单 (标准) | 中等 | 简单 (声明式) |
| 灵活性 | 低 | 高 | 高 |
| 依赖 | JDK 内置 | 需引入 CXF 框架 | 需引入 Spring Boot |
| 集成度 | 低 | 中等 | 极高 (与 Spring 生态) |
| 主要用途 | 调用传统、遗留的 SOAP 服务。 | 需要处理复杂 SOAP 协议(如 WS-Security)或同时需要 SOAP/REST 的项目。 | 开发新的 RESTful 服务或调用现代 REST API 的首选。 |
选择建议:
-
如果你的任务是调用一个现有的 SOAP WebService:
- 如果项目简单,不想引入新依赖,使用 JAX-WS。
- 如果项目复杂,需要日志、安全等高级功能,或者你熟悉 CXF,使用 Apache CXF。
-
如果你的任务是调用一个 RESTful WebService (返回 JSON/XML):
- 毫不犹豫地选择 Spring Boot + RestTemplate (或 WebClient),这是当前业界的主流和最佳实践。
-
如果你需要同时开发客户端和服务器端:
- 对于 SOAP,CXF 是一个非常健壮的选择。
- 对于 RESTful,Spring Boot 全家桶是绝对的首选。
