杰瑞科技汇

Java如何调用WebService?

核心概念

在开始之前,先理解几个基本概念:

  1. WebService: 一种基于 Web 的、跨平台的、跨语言的远程服务调用技术,通常使用 SOAP (Simple Object Access Protocol) 协议,并通过 WSDL (Web Services Description Language) 文件来描述其接口(有哪些方法、参数、返回值等)。
  2. SOAP: 一种基于 XML 的协议,用于在 Web 上交换结构化的信息,SOAP 消息是 XML 格式的,非常“重”。
  3. WSDL: 一个 XML 文件,它是 WebService 的“说明书”,它定义了服务的位置(URL)、可用的操作、输入/输出的消息格式等,要调用一个 WebService,首先需要获取它的 WSDL 地址。
  4. Endpoint (服务端点): WebService 的实际访问地址。

使用 JDK 自带的 javax.xml.ws (JAX-WS API)

这是 Java 标准库中调用 WebService 的官方方式,无需添加任何第三方依赖(只要你的 JDK 版本 >= 1.6),它非常适合调用简单的、基于 SOAP 的 WebService。

步骤:

  1. 获取 WSDL 文件地址:这是调用服务的第一步。
  2. 生成客户端代码:使用 JDK 自带的 wsimport 工具,根据 WSDL 文件生成一系列 Java 类(客户端存根),这些类包含了调用服务所需的一切。
  3. 调用服务:在 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 项目中调用服务

  1. 将生成的 .java 文件编译后(或直接将 .java 源码文件)加入到你的项目中。
  2. 编写调用代码:
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 规范,并且提供了更多的特性。

步骤:

  1. 添加 Maven 依赖:在 pom.xml 中添加 CXF 依赖。
  2. 编写调用代码: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 客户端。

步骤:

  1. 确定 API 地址、请求方法、请求头、请求体和响应格式
  2. 使用 HTTP 客户端发送请求
  3. 解析响应数据

详细示例:

假设有一个获取用户信息的 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 的首选

如何选择?

  1. 如果服务是 SOAP 协议的

    • 如果服务简单,WSDL 文件不复杂,使用 JDK 自带的 JAX-WS (wsimport) 最快。
    • 如果服务复杂,或者你希望代码更灵活、需要高级功能(如安全、拦截器),强烈推荐使用 Apache CXF
  2. 如果服务是 RESTful 风格的

    • 不要使用 JAX-WS/CXF
    • 使用 OkHttpApache HttpClient 发送 HTTP 请求,并配合 JacksonGson 库来解析 JSON 响应,这是目前最主流和最高效的方式。
分享:
扫描分享到社交APP
上一篇
下一篇