核心概念
在开始之前,先理解几个基本概念:
- WebService: 一种基于 Web 的、跨平台的、跨语言的远程服务调用技术,通常使用 SOAP (Simple Object Access Protocol) 协议,并通过 WSDL (Web Services Description Language) 文件来描述其接口(有哪些方法、参数、返回值等)。
- SOAP: 一种基于 XML 的协议,用于在 Web 上交换结构化的信息,SOAP 消息是 XML 格式的,非常“重”。
- WSDL: 一个 XML 文件,它是 WebService 的“说明书”,它定义了服务的位置(URL)、可用的操作、输入/输出的消息格式等,要调用一个 WebService,首先需要获取它的 WSDL 地址。
- Endpoint (服务端点): WebService 的实际访问地址。
使用 JDK 自带的 javax.xml.ws (JAX-WS API)
这是 Java 标准库中调用 WebService 的官方方式,无需添加任何第三方依赖(只要你的 JDK 版本 >= 1.6),它非常适合调用简单的、基于 SOAP 的 WebService。
步骤:
- 获取 WSDL 文件地址:这是调用服务的第一步。
- 生成客户端代码:使用 JDK 自带的
wsimport工具,根据 WSDL 文件生成一系列 Java 类(客户端存根),这些类包含了调用服务所需的一切。 - 调用服务:在 Java 代码中实例化生成的服务类,然后调用相应的方法。
详细示例:
假设我们有一个天气预报的 WebService,其 WSDL 地址为:http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl
第1步:使用 wsimport 生成客户端代码
打开命令行(CMD 或 PowerShell),执行以下命令:
# -p: 指定生成的包名 # -d: 指定生成 .class 文件存放的目录 # -s: 指定生成 .java 文件存放的目录 (推荐,方便查看源码) # keep: 生成源代码文件 # wsdlLocation: 指定 wsdl 的最终地址,避免硬编码在生成的代码中 wsimport -p com.example.weather.client -d D:\temp\classes -s D:\temp\src -keep http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl
执行后,你会在 D:\temp\src\com\example\weather\client 目录下看到一堆生成的 Java 文件,核心的类通常包括:
WeatherWebService.java(服务接口)WeatherWebServiceService.java(服务工厂类)WeatherWebServiceSoap.java(具体的 SOAP 接口,包含我们要调用的方法)- 以及一系列用于映射 SOAP 消息的
XXX.java类。
第2步:在 Java 项目中调用服务
- 将生成的
.java文件编译后(或直接将.java源码文件)加入到你的项目中。 - 编写调用代码:
package com.example.weather.client;
public class WeatherClient {
public static void main(String[] args) {
try {
// 1. 创建服务工厂对象
WeatherWebServiceService service = new WeatherWebServiceService();
// 2. 获取服务端口 (Endpoint Interface),这是实际调用方法的接口
// 根据WSDL,可能不止一个端口,这里我们获取 "WeatherWebServiceSoap" 端口
WeatherWebServiceSoap port = service.getWeatherWebServiceSoap();
// 3. 调用方法,传入参数
// 查询中国所有省份
String result = port.getProvinceList();
// 4. 处理返回结果
// 返回结果是XML格式的字符串
System.out.println("获取到的省份列表:");
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用 Apache CXF 框架
wsimport 生成的方式虽然简单,但有时 WSDL 文件可能比较复杂,或者生成的代码不够灵活,Apache CXF 是一个功能更强大、更灵活的开源框架,它支持 JAX-WS 规范,并且提供了更多的特性。
步骤:
- 添加 Maven 依赖:在
pom.xml中添加 CXF 依赖。 - 编写调用代码:CXF 可以不生成客户端代码,直接通过动态代理的方式调用服务,非常方便。
详细示例:
第1步:添加 Maven 依赖
<dependencies>
<!-- Apache CXF 核心依赖 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-core</artifactId>
<version>3.4.5</version> <!-- 使用较新稳定版本 -->
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.4.5</version>
</dependency>
</dependencies>
第2步:编写调用代码
CXF 提供了一个 JaxWsProxyFactoryBean 类,可以动态地创建一个客户端代理。
package com.example.weather.cxf;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import com.example.weather.client.WeatherWebServiceSoap; // 假设我们也有WSDL生成的类,或者使用CXF的动态特性
public class CxfWeatherClient {
public static void main(String[] args) {
// 1. 创建工厂实例
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
// 2. 设置服务地址 (WSDL地址)
factory.setAddress("http://www.webxml.com.cn/WebServices/WeatherWebService.asmx");
// 3. 设置服务接口 (必须有接口)
// 如果没有提前生成代码,CXF也可以动态创建,但最好有接口
// 这里我们假设接口是 com.example.weather.client.WeatherWebServiceSoap
factory.setServiceClass(com.example.weather.client.WeatherWebServiceSoap.class);
// 4. 创建客户端代理
WeatherWebServiceSoap weatherService = (WeatherWebServiceSoap) factory.create();
// 5. 调用方法
String provinceList = weatherService.getProvinceList();
// 6. 处理结果
System.out.println("通过 CXF 获取到的省份列表:");
System.out.println(provinceList);
}
}
CXF 的优点:
- 无需生成代码:通过动态代理,可以直接调用,简化了开发流程。
- 功能强大:支持拦截器、数据绑定、WS-Security 等高级特性。
- 灵活性高:可以更精细地控制请求和响应的细节。
调用 RESTful WebService (非 SOAP)
大部分新开发的 WebService 都是 RESTful 风格的,它们通常返回 JSON 或 XML 数据,而不是 SOAP,调用这种服务,我们通常不使用 JAX-WS,而是使用更通用的 HTTP 客户端。
步骤:
- 确定 API 地址、请求方法、请求头、请求体和响应格式。
- 使用 HTTP 客户端发送请求。
- 解析响应数据。
详细示例:
假设有一个获取用户信息的 RESTful API:
- URL:
https://api.example.com/users/123 - 方法:
GET - 响应格式: JSON
使用 HttpURLConnection (JDK 自带)
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class RestHttpClient {
public static void main(String[] args) {
try {
String apiUrl = "https://api.example.com/users/123";
URL url = new URL(apiUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置请求方法
connection.setRequestMethod("GET");
// 设置请求头
connection.setRequestProperty("Accept", "application/json");
// 检查响应码
int responseCode = connection.getResponseCode();
System.out.println("Response Code: " + responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) { // 200
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// 打印 JSON 响应
System.out.println("Response JSON: " + response.toString());
// 这里可以使用如 Jackson, Gson 等库来解析 JSON
// User user = new ObjectMapper().readValue(response.toString(), User.class);
} else {
System.out.println("GET request failed");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用更现代的 OkHttp 或 Apache HttpClient
这些库提供了更简洁、更强大的 API。
OkHttp 示例 (需添加依赖)
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.10.0</version>
</dependency>
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class OkHttpExample {
public static void main(String[] args) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.example.com/users/123")
.header("Accept", "application/json")
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
// 获取响应体
String responseBody = response.body().string();
System.out.println("Response JSON: " + responseBody);
} catch (IOException e) {
e.printStackTrace();
}
}
}
总结与对比
| 特性 | JAX-WS (wsimport) |
Apache CXF | RESTful (OkHttp/HttpURLConnection) |
|---|---|---|---|
| 适用场景 | 传统 SOAP WebService | 传统 SOAP WebService,需要更多控制时 | 现代 RESTful API |
| 依赖 | 无 (JDK 内置) | 需要添加 CXF 依赖 | 无 (JDK 内置) 或 OkHttp |
| 开发流程 | 先 wsimport 生成代码,再调用 |
可动态代理,无需生成代码 | 直接发送 HTTP 请求 |
| 协议 | SOAP | SOAP | HTTP/HTTPS |
| 数据格式 | XML | XML | JSON / XML / Text |
| 易用性 | 简单,但 WSDL 复杂时麻烦 | 灵活,功能强大 | 简单直接,但对 JSON/XML 解析需额外库 |
| 推荐度 | 调用简单 SOAP 服务可用 | 强烈推荐调用复杂 SOAP 服务 | 现代标准,调用 REST API 的首选 |
如何选择?
-
如果服务是 SOAP 协议的:
- 如果服务简单,WSDL 文件不复杂,使用 JDK 自带的 JAX-WS (
wsimport) 最快。 - 如果服务复杂,或者你希望代码更灵活、需要高级功能(如安全、拦截器),强烈推荐使用 Apache CXF。
- 如果服务简单,WSDL 文件不复杂,使用 JDK 自带的 JAX-WS (
-
如果服务是 RESTful 风格的:
- 不要使用 JAX-WS/CXF。
- 使用 OkHttp 或 Apache HttpClient 发送 HTTP 请求,并配合 Jackson 或 Gson 库来解析 JSON 响应,这是目前最主流和最高效的方式。
