杰瑞科技汇

Java如何调用C语言开发的WebService?

下面我将从核心原理详细步骤常见问题代码示例四个方面,为你详细讲解如何实现 Java 调用 C# WebService。

Java如何调用C语言开发的WebService?-图1
(图片来源网络,侵删)

核心原理:为什么可以互通?

Java 和 C# 虽然是两种不同的语言,但它们都支持业界标准的 WebService 技术。

  1. WSDL (Web Services Description Language)

    • 无论服务端是 C# 还是 Java,它们都会将自身的接口(提供了哪些方法、方法有哪些参数、参数是什么类型、返回值是什么类型)描述成一个标准的 XML 文件,这个文件就是 WSDL。
    • WSDL 就像一个“说明书”或“地图”,客户端(Java 程序)可以通过它来了解如何调用服务。
  2. SOAP (Simple Object Access Protocol)

    • 这是一种基于 XML 的协议,用于在 Web 上交换结构化的信息,当 Java 客户端调用 C# WebService 的一个方法时,它会将请求信息(方法名、参数等)打包成一个符合 SOAP 规范的 XML 消息,然后通过 HTTP 发送给 C# 服务端。
    • C# 服务端收到这个 SOAP 消息后,会解析它,执行对应的方法,然后将结果再打包成一个 SOAP 响应 XML 消息,返回给 Java 客户端。
  3. 标准化工具

    Java如何调用C语言开发的WebService?-图2
    (图片来源网络,侵删)
    • C# (/.NET Framework):使用 ASMXWCFASP.NET Core 等技术栈来创建 WebService,这些框架能自动生成标准的 WSDL 文件和处理 SOAP 消息。
    • Java:使用 JAX-WS (Java API for XML Web Services) 框架,这个框架提供了强大的工具,可以根据 WSDL 文件自动生成客户端调用代码(通常称为 "Stub" 或 "Proxy" 代码),从而让开发者可以像调用本地方法一样调用远程的 WebService。

总结一下流程:

  1. C# 服务端 发布一个 WebService,并提供一个 WSDL 地址。
  2. Java 客户端 获取这个 WSDL 文件。
  3. Java 客户端 使用 JAX-WS 工具(如 wsimport)根据 WSDL 生成客户端代理类。
  4. Java 客户端 代码中实例化这个代理类,并直接调用其方法。
  5. JAX-WS 框架在底层自动完成 SOAP 请求的构建、发送和 SOAP 响应的解析,并将结果返回给调用者。

详细步骤(以最常用的 JAX-WS 为例)

假设你已经有一个 C# 编写的 WebService,并且你知道它的 WSDL 地址(http://your-csharp-service.com/MyService.asmx?wsdl)。

第 1 步:获取 WSDL 文件

在浏览器中访问 C# WebService 的 WSDL 地址(URL 后面加上 ?wsdl),你应该能看到一个 XML 文件,这就是你的 Java 客户端需要使用的“地图”。

第 2 步:使用 wsimport 生成客户端代码

wsimport 是 JDK 自带的一个命令行工具,它的作用是根据 WSDL 文件生成 Java 客户端代码。

Java如何调用C语言开发的WebService?-图3
(图片来源网络,侵删)
  1. 打开命令行(CMD 或 PowerShell)。

  2. 执行以下命令:

    wsimport -p com.example.client -keep -d src http://your-csharp-service.com/MyService.asmx?wsdl

    参数解释:

    • -p com.example.client:指定生成的 Java 包名。
    • -keep:生成代码后,保留 .java 源文件,方便查看。
    • -d src:指定编译后的 .class 文件存放目录(需要确保 src 目录已存在)。
    • http://...wsdl:你的 C# WebService 的 WSDL 地址。

    执行成功后,src/com/example/client 目录下会生成一堆 Java 文件,其中最重要的是:

    • MyService.java:服务的服务接口。
    • MyServiceService.java:服务的工厂类,用于获取服务接口的实例。
    • 以及一些用于映射 SOAP 消息中数据类型的类(如 MyRequestType.java, MyResponseType.java 等)。

第 3 步:在 Java 项目中编写调用代码

你可以在你的 Java 项目(例如一个 Maven 或 Gradle 项目)中编写调用代码了。

  1. 将第 2 步生成的所有 .class 文件(或者直接将 .java 文件也放进项目)添加到你的 Java 项目的类路径中。
  2. 创建一个 Java 类来调用服务。
package com.example.client;
public class CSharpWebServiceClient {
    public static void main(String[] args) {
        try {
            // 1. 创建服务实例(通过工厂类)
            // MyServiceService 是 wsimport 生成的工厂类
            MyServiceService service = new MyServiceService();
            // 2. 获取服务端口(即服务的接口)
            // MyService 是 wsimport 生成的服务接口
            MyService port = service.getMyServicePort();
            // 3. 调用 WebService 提供的方法
            // 假设 C# WebService 有一个名为 "HelloWorld" 的方法,接受一个字符串参数
            String request = "Java Client";
            String response = port.helloWorld(request);
            // 4. 处理返回结果
            System.out.println("调用 C# WebService 成功!");
            System.out.println("请求参数: " + request);
            System.out.println("返回结果: " + response);
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("调用 C# WebService 失败: " + e.getMessage());
        }
    }
}

第 4 步:处理常见问题(认证、超时等)

在实际项目中,你很可能需要处理更复杂的情况,HTTP Basic/Digest 认证、设置超时等,这通常需要通过设置 BindingProvider 的上下文来实现。

// ... 在获取 port 之后,调用方法之前 ...
// 假设 port 是 MyService 类型
BindingProvider bindingProvider = (BindingProvider) port;
// 1. 设置 HTTP 认证信息 (如果服务需要)
// 假设用户名是 "user",密码是 "password"
Map<String, Object> requestContext = bindingProvider.getRequestContext();
requestContext.put(BindingProvider.USERNAME_PROPERTY, "user");
requestContext.put(BindingProvider.PASSWORD_PROPERTY, "password");
// 2. 设置连接和读取超时 (单位:毫秒)
// 防止因网络问题导致程序长时间阻塞
requestContext.put(BindingProviderProperties.CONNECT_TIMEOUT, 5000); // 5秒连接超时
requestContext.put(BindingProviderProperties.REQUEST_TIMEOUT, 10000); // 10秒读取超时
// 3. 调用方法
String response = port.helloWorld("Java Client");

常见问题与解决方案

数据类型映射问题

这是最常见的问题,C# 和 Java 的数据类型不是一一对应的,WSDL 规范定义了它们之间的映射关系。

C# / .NET 类型 XML Schema 类型 Java (JAX-WS) 类型 说明
string xs:string java.lang.String 无问题
int, Int32 xs:int int 无问题
bool, Boolean xs:boolean boolean 无问题
double xs:double double 无问题
DateTime xs:dateTime XMLGregorianCalendar 注意:Java 端需要使用 XMLGregorianCalendar,而不是 java.util.Datejava.time.LocalDateTime,工具类可以方便转换。
DataSet xs:complexType (复杂) List<YourCustomObject> .NET 的 DataSet 是一个非常灵活的结构,Java 端通常会将其映射成一个或多个自定义的 Java 对象列表。
enum xs:restriction java.lang.Stringenum 如果枚举值是固定的,wsimport 可能会生成一个 Java enum,如果更灵活,则可能映射为 String

解决方案:

  • 检查 wsimport 生成的 JavaBean 类,了解它期望的输入和输出类型。
  • C# 端使用 DataSet,请与 C# 开发人员确认其内部结构,然后在 Java 端创建对应的 POJO (Plain Old Java Object)。
  • 对于 DateTime
分享:
扫描分享到社交APP
上一篇
下一篇