什么是 wsdl2java?
wsdl2java 是 Apache CXF 和 Apache Axis2 等开源 Web Service 框架提供的一个命令行工具,它的主要功能是:

- 解析 WSDL 文件:读取 WSDL 文件中对 Web Service 的所有描述。
- 生成 Java 代码:根据 WSDL 中的定义,自动创建一系列 Java 类,这些类代表了:
- 服务接口 (Service Interface):客户端可以直接调用的方法,对应 WSDL 中的
portType。 - 服务实现类 (Service Implementation):一个客户端代理,负责将你的方法调用转换为 SOAP 消息。
- 数据模型 (Data Models):与 WSDL 中定义的
complexType和element对应的 Java Bean (POJO) 类,用于封装请求和响应数据。 - 服务工厂 (Service Factory):一个用于获取服务接口实例的工厂类。
- 异常类:可能抛出的 SOAPFault 等异常。
- 服务接口 (Service Interface):客户端可以直接调用的方法,对应 WSDL 中的
通过使用这些生成的代码,你就可以像调用本地 Java 方法一样,轻松地调用远程的 Web Service,而无需关心底层的 SOAP 消息格式、网络传输等复杂细节。
准备工作:安装 Apache CXF
wsdl2java 是 CXF 框架的一部分,你需要先下载并配置 CXF。
步骤 1:下载 CXF
访问 Apache CXF 官方下载页面,下载最新的二进制分发版(apache-cxf-<version>-bin.zip)。
步骤 2:解压并设置环境变量

- 将下载的 ZIP 文件解压到一个你喜欢的目录,
D:\dev\apache-cxf-3.4.3。 - 重要:将
bin目录添加到系统的PATH环境变量中,添加D:\dev\apache-cxf-3.4.3\bin。- 这样你就可以在任何地方直接使用
wsdl2java命令了。
- 这样你就可以在任何地方直接使用
步骤 3:验证安装 打开一个新的命令行窗口(CMD 或 PowerShell),输入以下命令:
wsdl2java -version
如果能看到 CXF 的版本信息,说明安装和配置成功。
使用 wsdl2java 生成代码
基本语法
wsdl2java [options] <WSDL-File-URL-or-Path>
最简单的用法
如果你的 WSDL 文件非常简单,可以直接使用:
wsdl2http http://www.example.com/service?wsdl
这会在当前目录下生成一个 src 文件夹,里面包含所有代码。

常用选项和最佳实践
在实际项目中,通常需要使用一些选项来控制代码的生成,使其更符合项目结构。
| 选项 | 说明 | 示例 |
|---|---|---|
-p 或 --package |
指定生成的 Java 包名,强烈推荐使用,避免生成到默认的 org.tempuri 等无意义的包中。 |
-p com.example.client |
-d 或 --destDir |
指定生成的代码存放的根目录,通常是你项目的 src/main/java 目录。 |
-d ./src/main/java |
-client |
生成一个可以独立运行的客户端 main 方法,方便快速测试。 | -client |
-server |
生成一个服务端骨架代码(如果你要实现服务端)。 | -server |
-impl |
生成服务端实现类。 | -impl |
-all |
生成客户端和服务端的所有代码。 | -all |
-ant |
生成一个 Ant 构建文件。 | -ant |
-autoNameResolution |
自动解决命名冲突问题(WSDL 中有同名但不同命名空间的元素)。 | -autoNameResolution |
-frontend |
指定前端语言,默认是 jaxws(推荐)。jaxb 是旧版本。 |
-frontend jaxws |
-exsh |
禁用生成 SOAP 头。 | -exsh true |
推荐的完整命令示例
假设你的项目结构如下:
my-web-service-client/
├── pom.xml
└── src/
└── main/
└── java/
你的 WSDL 文件地址是 http://api.example.com/WeatherService?wsdl。
你可以在项目根目录 my-web-service-client/ 下执行以下命令:
wsdl2java \ -p com.example.weather.client \ -d ./src/main/java \ -client \ -autoNameResolution \ http://api.example.com/WeatherService?wsdl
命令解释:
-p com.example.weather.client:所有生成的代码都将放在com.example.weather.client包及其子包下。-d ./src/main/java:生成的.java文件会直接放到src/main/java目录中,符合 Maven/Gradle 的标准目录结构。-client:额外生成一个可运行的客户端测试类。-autoNameResolution:作为保险,防止因 WSDL 复杂导致命名冲突。http://api.example.com/WeatherService?wsdl:WSDL 文件的 URL。
生成的代码结构与使用
执行完上述命令后,你的 src/main/java 目录会变成类似这样:
src/main/java/
└── com/
└── example/
└── weather/
└── client/
├── WeatherService.java // 服务接口 (portType)
├── WeatherServiceService.java // 服务工厂 (Service)
├── Weather.java // 数据模型 (请求/响应对象)
├── GetWeatherRequest.java // 数据模型 (请求对象)
├── GetWeatherResponse.java // 数据模型 (响应对象)
└── WeatherServiceClient.java // 可运行的客户端测试类 (由 -client 生成)
如何在 Java 代码中使用生成的客户端?
-
获取服务工厂实例:
WeatherServiceService类有一个getWeatherServicePort()方法,它会返回WeatherService接口的实例。 -
调用方法: 拿到
WeatherService实例后,就可以像调用普通 Java 方法一样调用它的方法了。
示例代码:
package com.example.weather.client;
public class MainApp {
public static void main(String[] args) {
// 1. 创建服务工厂实例
WeatherServiceService service = new WeatherServiceService();
// 2. 获取服务接口的代理对象
WeatherService port = service.getWeatherServicePort();
try {
// 3. 创建请求数据对象
GetWeatherRequest request = new GetWeatherRequest();
request.setCity("Beijing");
// 4. 调用 Web Service 方法
GetWeatherResponse response = port.getWeather(request);
// 5. 处理响应结果
System.out.println("The temperature in " + request.getCity() + " is: " + response.getTemperature() + "°C");
} catch (Exception e) {
// 捕获可能的 SOAPFault 或其他异常
e.printStackTrace();
System.err.println("调用 Web Service 出错: " + e.getMessage());
}
}
}
常见问题与解决方案
Q1: wsdl2java 报错:java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
原因:从 Java 9 开始,JAXB (Java Architecture for XML Binding) 不再包含在标准的 JDK 中,而是作为一个可选模块,CXF 依赖它来处理 XML 和 Java 对象的转换。
解决方案: 如果你使用的是 Java 9 或更高版本,需要添加 JAXB 的依赖到你的项目中(以 Maven 为例):
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
Q2: 生成的代码包名不正确,或者有重复的类名
原因:WSDL 文件中可能定义了多个 targetNamespace,或者存在命名冲突。
解决方案:
- 使用
-autoNameResolution选项,让 CXF 自动处理。 - 使用
-p选项明确指定包名,并使用 或 分隔不同的命名空间映射。wsdl2java -p "http://tempuri.org/=com.example.client;http://schemas.datacontract.org/.../=com.example.client.model" ...
这种方式可以更精细地控制不同命名空间下的类生成到哪个包。
Q3: WSDL 文件需要用户名和密码认证才能访问
解决方案:
CXF 支持通过 HTTPConduit 来设置 HTTP 客户端认证信息,你需要编写一个简单的 Spring 配置文件,并将其与 CXF 的总线关联起来。
示例 Spring 配置文件 (cxf-client.xml):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:http="http://cxf.apache.org/transports/http/configuration"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/transports/http/configuration
http://cxf.apache.org/schemas/configuration/http-conf.xsd">
<!-- 定义 HTTP 客户端配置 -->
<http:conduit name="{http://api.example.com/}WeatherService.http-conduit">
<http:client ConnectionTimeout="30000" ReceiveTimeout="30000"/>
<http:Authorization>
<http:UserName>your_username</http:UserName>
<http:Password>your_password</http:Password>
</http:Authorization>
</http:conduit>
</beans>
然后在你的 Java 代码中加载这个配置:
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.transport.http.HTTPConduit;
import org.springframework.context.support.ClassPathXmlApplicationContext;
// ... 在获取 port 之前
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"cxf-client.xml"});
SpringBus springBus = (SpringBus) context.getBean("cxf");
// 将你的客户端总线设置为这个 SpringBus
ClientProxy.getClient(port).getBinding().get(Bus.class).setId("cxf"); // 或者其他方式关联
// 更简单的方式是,如果你的应用已经集成了 Spring,CXF 会自动发现配置。
注意:在现代应用中,更推荐使用 CXF 的 JAXRSClientFactory 或 JAXWSClientFactoryBean 来编程式地设置这些属性,或者将其集成到 Spring/Spring Boot 的配置中。
最佳实践
- 版本控制:将
wsdl2java生成的代码纳入版本控制系统(如 Git),不要将.java文件排除在外,这样可以确保团队成员和部署环境使用完全一致的客户端代码。 - 清晰的包结构:始终使用
-p选项指定一个有意义的包名,避免生成到默认包中。 - 使用构建工具集成:在 Maven 或 Gradle 项目中,使用
cxf-codegen-plugin来生成代码,而不是手动运行命令行,这样可以更好地将代码生成过程集成到自动化构建中。- Maven Plugin 示例:
<plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <version>3.4.3</version> <executions> <execution> <id>generate-sources</id> <phase>generate-sources</phase> <configuration> <sourceRoot>${project.build.directory}/generated-sources/cxf</sourceRoot> <wsdlOptions> <wsdlOption> <wsdl>http://api.example.com/WeatherService?wsdl</wsdl> <wsdlLocation>http://api.example.com/WeatherService?wsdl</wsdlLocation> </wsdlOption> </wsdlOptions> </configuration> <goals> <goal>wsdl2java</goal> </goals> </execution> </executions> </plugin>
- Maven Plugin 示例:
- 处理异常:始终用
try-catch块包裹 Web Service 调用,以捕获SOAPFaultException或其他运行时异常,这是处理服务端返回的错误信息的标准方式。
