杰瑞科技汇

Java如何调用Webservices?

  1. JAX-WS (Java API for XML Web Services):Java 官方标准,是目前最主流、最推荐的方式,它简化了 WebService 的创建和调用过程。
  2. Axis2 / Apache CXF:功能强大的第三方框架,提供了比 JAX-WS 更多的企业级特性,如 REST 支持、WS-Security 等。
  3. 手动调用 (HttpClient + XML/JSON 解析):不依赖 WebService 框架,通过通用的 HTTP 客户端发送 SOAP 请求或 RESTful API 请求,这种方式最灵活,但代码量也最大。

JAX-WS (推荐)

JAX-WS 是 Java EE 的标准部分,现在也包含在 Java SE 中,它允许你通过注解来描述 WebService,并提供了工具来自动生成客户端代码。

Java如何调用Webservices?-图1
(图片来源网络,侵删)

通过 WSDL 文件生成客户端并调用

这是最常见的情况,你拥有一个服务的 WSDL (Web Services Description Language) 文件。

步骤 1:生成客户端代码

JDK 自带了 wsimport 工具,可以根据 WSDL 文件生成 Java 客户端代码。

  1. 打开命令行(CMD 或 PowerShell)。

    Java如何调用Webservices?-图2
    (图片来源网络,侵删)
  2. 执行以下命令:

    # 格式:wsimport -keep -d <输出目录> -p <生成的包名> <WSDL文件URL或路径>
    wsimport -keep -d .\src\main\java -p com.example.client http://www.webxml.com.cn/webservices/weatherwebservice.asmx?wsdl
    • -keep: 生成源代码文件。
    • -d: 指定编译后的 .class 文件存放目录。
    • -p: 指定生成的 Java 包名。
    • WSDL URL: WebService 的 WSDL 地址。

    执行成功后,会在你指定的目录下生成一堆 Java 文件,包括一个 Service 类和一个(或多个)Port 接口。

步骤 2:调用生成的客户端

在你的 Java 项目中,引入生成的代码,然后像调用普通 Java 接口一样调用服务。

Java如何调用Webservices?-图3
(图片来源网络,侵删)
import com.example.client.WeatherWS;
import com.example.client.WeatherWSLocator;
import com.example.client.WeatherWSSoap;
public class JaxwsClientExample {
    public static void main(String[] args) {
        try {
            // 1. 创建服务定位器 (Service Locator)
            // WSDL 中的 <service name="..."> 对应这个类
            WeatherWS service = new WeatherWSLocator();
            // 2. 获取服务端点 (Port)
            // WSDL 中的 <port name="..."> 对应这个接口
            // 注意:这里我们使用 getWeatherWSSoap(),因为 WSDL 中定义了 soap 绑定
            WeatherWSSoap port = service.getWeatherWSSoap();
            // 3. 调用 WebService 方法
            // 直接调用接口中定义的方法
            String result = port.getWeatherbyCityName("北京");
            // 4. 处理结果
            System.out.println("WebService 返回结果:");
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

动态调用 (无需生成代码)

如果你不想生成客户端代码,可以使用 JAX-WS 的 Dispatch API 进行动态调用。

import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import java.net.URL;
public class DynamicJaxwsClientExample {
    public static void main(String[] args) {
        try {
            // 1. 创建服务
            URL wsdlUrl = new URL("http://www.webxml.com.cn/webservices/weatherwebservice.asmx?wsdl");
            QName serviceName = new QName("http://WebXml.com.cn/", "WeatherWS");
            Service service = Service.create(wsdlUrl, serviceName);
            // 2. 创建 Dispatch 实例 (使用 SOAPMessage 模式)
            // QName portName = new QName("http://WebXml.com.cn/", "WeatherWSSoap");
            // Dispatch<SOAPMessage> dispatch = service.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE);
            // 或者使用 PAYLOAD 模式 (只处理 SOAP Body)
            QName portName = new QName("http://WebXml.com.cn/", "WeatherWSSoap");
            Dispatch<SOAPMessage> dispatch = service.createDispatch(portName, SOAPMessage.class, Service.Mode.PAYLOAD);
            // 3. 创建 SOAP 请求消息
            MessageFactory messageFactory = MessageFactory.newInstance();
            SOAPMessage soapRequest = messageFactory.createMessage();
            SOAPEnvelope envelope = soapRequest.getSOAPPart().getEnvelope();
            SOAPBody body = envelope.getBody();
            // 添加请求元素
            // <soap:Body>
            //   <getWeatherbyCityName xmlns="http://WebXml.com.cn/">
            //     <theCityName>北京</theCityName>
            //   </getWeatherbyCityName>
            // </soap:Body>
            QName bodyName = new QName("http://WebXml.com.cn/", "getWeatherbyCityName");
            body.addBodyElement(bodyName).addTextNode("北京");
            // 4. 发送请求并获取响应
            System.out.println("发送 SOAP 请求...");
            SOAPMessage soapResponse = dispatch.invoke(soapRequest);
            // 5. 处理响应
            System.out.println("收到 SOAP 响应:");
            soapResponse.writeTo(System.out);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

使用 Apache CXF

CXF 是一个功能非常全面的开源 WebService 框架,它同时支持 JAX-WS 和 JAX-RS (REST) 标准。

步骤 1:添加 Maven 依赖

在你的 pom.xml 文件中添加 CXF 的依赖。

<dependencies>
    <!-- CXF 核心依赖 -->
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-core</artifactId>
        <version>3.5.5</version> <!-- 使用最新稳定版 -->
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxws</artifactId>
        <version>3.5.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http</artifactId>
        <version>3.5.5</version>
    </dependency>
    <!-- CXF 内置了 Jetty,可以方便地测试服务端 -->
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http-jetty</artifactId>
        <version>3.5.5</version>
    </dependency>
</dependencies>

步骤 2:生成客户端并调用

CXF 提供了 cxf-codegen-plugin Maven 插件来生成客户端,与 wsimport 类似。

  1. 生成代码 (在 pom.xml 中配置插件,或在命令行使用 cxf-codegen-frontend-maven-plugin)。
  2. 调用代码:CXF 生成的客户端代码与 JAX-WS 生成的在调用方式上几乎完全相同。
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import com.example.client.WeatherWSSoap; // 假设这是 CXF 生成的接口
public class CxfClientExample {
    public static void main(String[] args) {
        // 1. 使用 JaxWsProxyFactoryBean 创建客户端代理
        // 无需 WSDL 文件生成代码,直接通过接口和地址创建
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass(WeatherWSSoap.class);
        factory.setAddress("http://www.webxml.com.cn/webservices/weatherwebservice.asmx");
        // 2. 获取客户端代理对象
        WeatherWSSoap weatherWS = (WeatherWSSoap) factory.create();
        // 3. 直接调用方法
        String result = weatherWS.getWeatherbyCityName("上海");
        // 4. 处理结果
        System.out.println("CXF 调用结果:");
        System.out.println(result);
    }
}

CXF 的优势:配置更灵活,支持更多的 WS-* 标准(如安全、事务),并且可以非常方便地与 Spring 集成。


手动调用 (HttpClient + XML/JSON)

这种方式不依赖于任何 WebService 特定框架,适用于调用 RESTful API 或者需要手动构造 SOAP 请求的场景。

场景:调用一个简单的 RESTful WebService (返回 JSON)

步骤 1:添加 HttpClient 依赖

<dependencies>
    <!-- Apache HttpClient -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.14</version>
    </dependency>
    <!-- JSON 解析库,Jackson -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.15.2</version>
    </dependency>
</dependencies>

步骤 2:编写调用代码

假设有一个 RESTful API:http://api.example.com/users/1,返回一个 JSON 对象 {"id":1, "name":"John", "email":"john@example.com"}

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class ManualRestClientExample {
    public static void main(String[] args) {
        // 1. 创建 HttpClient 实例
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            // 2. 创建 HTTP GET 请求
            String apiUrl = "http://api.example.com/users/1";
            HttpGet request = new HttpGet(apiUrl);
            // 3. 发送请求并获取响应
            try (CloseableHttpResponse response = httpClient.execute(request)) {
                // 4. 检查响应状态码
                System.out.println("Response Code: " + response.getStatusLine().getStatusCode());
                // 5. 获取响应实体 (JSON 字符串)
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String jsonString = EntityUtils.toString(entity);
                    System.out.println("JSON Response: " + jsonString);
                    // 6. 使用 Jackson 解析 JSON
                    ObjectMapper mapper = new ObjectMapper();
                    User user = mapper.readValue(jsonString, User.class);
                    System.out.println("\nParsed User Object:");
                    System.out.println("ID: " + user.getId());
                    System.out.println("Name: " + user.getName());
                    System.out.println("Email: " + user.getEmail());
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // 定义一个与 JSON 结构对应的 Java 类
    static class User {
        private int id;
        private String name;
        private String email;
        // Getters and Setters (必须有)
        public int getId() { return id; }
        public void setId(int id) { this.id = id; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getEmail() { return email; }
        public void setEmail(String email) { this.email = email; }
    }
}

总结与对比

特性 JAX-WS (wsimport) Apache CXF 手动调用
易用性 ,标准流程,生成代码后调用简单 JaxWsProxyFactoryBean 无需生成代码 ,需要手动处理 HTTP 和 XML/JSON
依赖 仅 JDK 需要 CXF 库 需要 HttpClient 和 JSON/XML 解析库
灵活性 低,严格遵循 WSDL ,支持多种标准和协议 极高,可控制所有细节
适用场景 调用基于 SOAP 协议的传统 WebService 企业级应用,需要 WS-* 安全、事务等特性 调用 RESTful API,或 SOAP 协议非常特殊/复杂
性能 取决于 HTTP 客户端和解析库的性能

如何选择?

  • 如果你调用的是一个标准的、有 WSDL 文件的 SOAP WebService,并且希望快速实现,请选择 JAX-WS。 这是业界最标准的做法。
  • 如果你的项目已经使用了 Spring,或者你需要用到 JAX-RS (REST) 以及 WS-Security 等高级特性,请选择 Apache CXF。 它的生态更强大,集成更方便。
  • 如果你调用的是 RESTful API,或者 SOAP 请求非常特殊,无法通过标准工具生成客户端,请选择手动调用。 这虽然麻烦,但最可控。
分享:
扫描分享到社交APP
上一篇
下一篇