- 自上而下(Top-Down):先定义 WSDL 文件,然后根据 WSDL 生成 Java 代码(客户端或服务端骨架),这是更推荐、更标准化的方式,因为它确保了接口的契约先于实现存在。
- 自下而上(Bottom-Up):先编写 Java 代码(服务接口和实现),然后由框架(如 JAX-WS)自动生成 WSDL 文件,这种方法在本问答中重点介绍。
下面我将详细讲解第二种方法(自下而上),并提供完整的代码示例。

核心概念:JAX-WS
Java API for XML Web Services (JAX-WS) 是 Java 平台用于构建 Web 服务的标准 API,它极大地简化了 Web 服务的开发,当我们使用 JAX-WS 时,WSDL 文件通常不是手动编写的,而是由运行时环境在服务首次部署时自动生成的。
使用 JAX-WS 注解(自下而上)
这是最常见、最直接的方法,你只需要编写标准的 Java 接口和实现类,并使用 JAX-WS 提供的注解来标记 Web 服务,通过一个简单的 Java 程序或构建工具(如 Maven)来触发 WSDL 的生成。
步骤 1:创建 Maven 项目
创建一个标准的 Maven 项目,并添加 JAX-WS 所需的依赖,在 pom.xml 中加入以下内容:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>java-wsdl-generator</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- JAX-WS API -->
<dependency>
<groupId>jakarta.xml.ws</groupId>
<artifactId>jakarta.xml.ws-api</artifactId>
<version>3.0.1</version>
</dependency>
<!-- JAX-WS RI (Reference Implementation) - 包含了 wsimport 等工具 -->
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>3.0.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 这个插件可以在编译后自动生成 WSDL 文件到 target 目录 -->
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
</execution>
</executions>
<configuration>
<sourceDestDir>${project.build.directory}/generated-sources/jaxws-wsimport</sourceDestDir>
<wsdlDirectory>${project.build.directory}/wsdl</wsdlDirectory>
<!-- 如果需要,可以配置 wsdlLocation -->
</configuration>
</plugin>
</plugins>
</build>
</project>
注意:jaxws-maven-plugin 的 wsimport 目标主要是用来从 WSDL 生成客户端代码,为了在编译后直接生成 WSDL,我们通常会用一个简单的 Java 主程序来手动触发生成过程。

步骤 2:编写 Web 服务接口
创建一个 Java 接口,并使用 @WebService 注解来标记它。
// src/main/java/com/example/HelloWorld.java
package com.example;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
/**
* WebService 接口
*/
@WebService(
name = "HelloWorld", // wsdl:portType 的名称
serviceName = "HelloWorldService", // wsdl:service 的名称
targetNamespace = "http://example.com/" // 命名空间,非常重要
)
public interface HelloWorld {
/**
* WebService 方法
* @param name 用户名
* @return 问候语
*/
@WebMethod(operationName = "sayHello") // wsdl:operation 的名称
String sayHello(@WebParam(name = "userName") String name);
}
步骤 3:编写 Web 服务实现类
创建一个实现类,并使用 @WebService 注解(或者 @WebService(endpointInterface = "...") 来明确指定它实现的是哪个接口)。
// src/main/java/com/example/HelloWorldImpl.java
package com.example;
import javax.jws.WebService;
/**
* WebService 实现类
*/
@WebService(
endpointInterface = "com.example.HelloWorld" // 指定实现的接口
)
public class HelloWorldImpl implements HelloWorld {
@Override
public String sayHello(String name) {
if (name == null || name.trim().isEmpty()) {
return "Hello, Stranger!";
}
return "Hello, " + name + "!";
}
}
步骤 4:编写 Java 程序来生成 WSDL
我们写一个主类,利用 JAX-WS 的 Endpoint 类来发布服务,并从发布的服务中获取 WSDL 内容,然后将其写入文件。
// src/main/java/com/example/WsdlGenerator.java
package com.example;
import javax.xml.ws.Endpoint;
import javax.xml.ws.Service;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
public class WsdlGenerator {
public static void main(String[] args) {
// 1. 定义服务发布的地址(这是一个内存地址,不会被外部访问)
String address = "http://localhost:8080/ws/hello";
// 2. 创建并发布服务
// Endpoint.publish() 会将服务发布到指定的地址,并自动生成 WSDL
Endpoint endpoint = Endpoint.publish(address, new HelloWorldImpl());
System.out.println("Service published at: " + address);
// 3. 从已发布的服务中获取 WSDL 的 URL
// JAX-WS 规定,WSDL 文件的地址是在服务地址后加上 "?wsdl"
String wsdlUrl = address + "?wsdl";
System.out.println("WSDL location: " + wsdlUrl);
// 4. 创建目标文件
File wsdlFile = new File("target/hello-world.wsdl");
// 5. 使用 try-with-resources 确保流被正确关闭
try (FileOutputStream fos = new FileOutputStream(wsdlFile)) {
// 6. 从 URL 读取 WSDL 内容并写入文件
byte[] buffer = new byte[1024];
int bytesRead;
URL url = new URL(wsdlUrl);
while ((bytesRead = url.openStream().read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead);
}
System.out.println("WSDL file generated successfully at: " + wsdlFile.getAbsolutePath());
} catch (MalformedURLException e) {
System.err.println("Invalid WSDL URL: " + e.getMessage());
} catch (IOException e) {
System.err.println("Error writing WSDL file: " + e.getMessage());
} finally {
// 7. 停止服务,释放资源
if (endpoint != null) {
endpoint.stop();
System.out.println("Service stopped.");
}
}
}
}
步骤 5:运行并验证
- 编译项目:确保你的 Maven 项目已经编译成功。
- 运行
WsdlGenerator:在 IDE 中直接运行WsdlGenerator.java的main方法。 - 检查输出:你会在控制台看到类似下面的信息:
Service published at: http://localhost:8080/ws/hello WSDL location: http://localhost:8080/ws/hello?wsdl WSDL file generated successfully at: /path/to/your/project/target/hello-world.wsdl Service stopped. - 查看文件:去你的项目
target目录下,你会发现hello-world.wsdl文件已经生成,你可以用文本编辑器或浏览器打开它,查看其内容。
使用 wsimport 工具(间接生成)
这种方法通常用于客户端开发,但也可以用来反向生成一个临时的 WSDL,它更偏向于“从 WSDL 到 Java”,而不是“从 Java 到 WSDL”,如果你有一个 Java 类,想快速得到一个符合规范的 WSDL,可以先让 wsimport 为它生成一个存根,再尝试反向工程,但这非常复杂且不推荐。

方法一(自下而上)是生成 WSDL 的标准 Java 做法。
关键注解说明
@WebService:- 用在接口或类上,将其声明为一个 Web 服务。
name: 定义 WSDL 中portType的名称。serviceName: 定义 WSDL 中service的名称。targetNamespace: 定义 XML 命名空间,避免冲突,非常重要。endpointInterface(用在实现类上): 明确指定该实现类所实现的接口全限定名。
@WebMethod:- 用在接口方法上,将其暴露为 Web 服务的一个操作。
operationName: 定义 WSDL 中operation的名称。
@WebParam:- 用在方法参数上,为参数指定 WSDL 中的名称。
name: 定义参数在 WSDL 中的名称。
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 自下而上 (JAX-WS) | 开发者只需关注 Java 代码。 框架自动处理 WSDL 的复杂性。 代码和契约同步更新。 |
生成的 WSDL 可能非常复杂,包含大量框架信息。 对于复杂的消息结构,可能需要手动调整注解。 |
快速开发和迭代,内部服务,对 WSDL 结构要求不高的场景。 |
| 自上而下 (WSDL First) | WSDL 作为“契约”,定义清晰。 客户端和服务端都严格遵循契约,兼容性好。 生成的 WSDL 结构清晰、干净。 |
需要手动编写或维护 WSDL 文件。 契约变更时,需要同时修改 WSDL 和两端的代码。 |
对外发布的服务、需要严格保证接口稳定性的场景、系统集成。 |
对于你的问题“java 代码 生成 wsdl文件”,使用 JAX-WS 注解并编写一个生成器程序(如上面的 WsdlGenerator)是最佳实践。
