杰瑞科技汇

Java如何调用WebService?

目录

  1. 核心概念区分:SOAP vs RESTful
  2. 使用 JDK 内置的 javax.xml.ws (JAX-WS) - 最传统
    • 适用于:标准的 SOAP WebService。
    • 优点:无需额外依赖,JDK 自带。
    • 缺点:配置相对繁琐,功能有限。
  3. 使用 Apache Axis2 / CXF - 最强大灵活
    • 适用于:复杂的 SOAP WebService,需要更多控制和高级功能。
    • 优点:功能强大,生态成熟,支持 WS-Security 等标准。
    • 缺点:需要引入第三方库,学习曲线稍陡。
  4. 使用 Spring Boot RestTemplate - 现代 RESTful API
    • 适用于:现代的 RESTful WebService (本质上不是传统 WebService,但常被混为一谈)。
    • 优点:Spring 生态核心,代码简洁,易于集成。
    • 缺点:仅适用于 RESTful 风格。
  5. 使用 Spring Boot WebClient - 最现代的 RESTful API
    • 适用于:异步、非阻塞的 RESTful API 调用。
    • 优点:响应式编程,性能更高,是 RestTemplate 的现代化替代品。
    • 缺点:学习曲线比 RestTemplate 陡峭。
  6. 总结与选择建议

核心概念区分:SOAP vs RESTful

在开始之前,必须明确你要调用的服务类型,因为它们的技术栈和调用方式完全不同。

Java如何调用WebService?-图1
(图片来源网络,侵删)
特性 SOAP (Simple Object Access Protocol) RESTful (Representational State Transfer)
协议 严格基于 HTTP,但也可用于 SMTP、TCP 等。 基于 HTTP/HTTPS 协议。
数据格式 强制使用 XML 灵活,常用 JSON,也支持 XML、HTML、纯文本等。
标准 有严格的国际标准(W3C)。 没有官方标准,更像是设计风格和约束。
接口描述 使用 WSDL (Web Services Description Language) 文件来描述服务接口、方法、参数等。 使用 OpenAPI (Swagger)API Blueprint 等文档来描述。
操作 通过 <soap:Body> 中的 XML 标签定义操作(如 getWeather)。 通过 HTTP 动词(GET, POST, PUT, DELETE)来操作资源。
安全性 内置了 WS-Security 等标准,安全性更高、更复杂。 通常依赖 HTTPS 和 OAuth、JWT 等标准。

简单判断:

  • 如果拿到一个 .wsdl 文件,那几乎可以肯定是 SOAP 服务。
  • 如果拿到的是一个 API 文档,里面描述了 URL 和 JSON 数据交互,那很可能是 RESTful 服务。

方法一:使用 JDK 内置的 javax.xml.ws (JAX-WS)

这是最传统、最简单的方式,无需任何外部库,适合快速调用简单的 SOAP 服务。

步骤:

  1. 获取 WSDL 文件:从服务提供方拿到 WSDL 文件的地址。
  2. 生成客户端代码:使用 JDK 自带的 wsimport 工具,根据 WSDL 文件生成 Java 客户端代码(接口和类)。
  3. 调用服务:在 Java 代码中创建服务实例,调用接口方法。

示例:

假设我们要调用一个天气预报的 SOAP 服务,其 WSDL 地址为:http://www.webxml.com.cn/WebServices/WeatherWS.asmx?wsdl

生成客户端代码

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

打开命令行,执行以下命令:

# -p: 指定生成的包名
# -keep: 生成源代码文件
# -d: 指定 class 文件输出目录
wsimport -p com.example.weather.client -keep -d src/main/java http://www.webxml.com.cn/WebServices/WeatherWS.asmx?wsdl

执行成功后,你的 src/main/java/com/example/weather/client 目录下会生成一堆 Java 文件。

编写调用代码

import com.example.weather.client.WeatherWS;
import com.example.weather.client.WeatherWSImplService;
import com.example.weather.client.ArrayOfString;
public class JaxWsClient {
    public static void main(String[] args) {
        // 1. 创建服务 Service 实例
        // WeatherWSImplService 是 wsimport 生成的类
        WeatherWSImplService service = new WeatherWSImplService();
        // 2. 从服务中获取 Port(端口),即服务的实现类
        // WeatherWS 是 wsimport 生成的接口
        WeatherWS weatherWS = service.getWeatherWSImplPort();
        try {
            // 3. 调用接口方法
            // 假设服务有一个 getWeather 方法,接受城市名作为参数
            ArrayOfString result = weatherWS.getWeather("北京", "");
            // 4. 处理返回结果
            // 返回结果是一个字符串数组
            System.out.println("天气预报结果:");
            for (String info : result.getString()) {
                System.out.println(info);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

方法二:使用 Apache CXF (推荐)

CXF 是一个非常流行的开源框架,它对 JAX-WS 和 JAX-RS (REST) 提供了强大的支持,是企业级开发的常用选择。

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

步骤:

  1. 添加依赖:在 pom.xml 中添加 CXF 依赖。
  2. 创建接口:手动或通过工具(如 cxf-codegen-plugin)创建一个与 WSDL 匹配的 Java 接口。
  3. 调用服务:使用 CXF 的 JaxWsProxyFactoryBean 来动态创建服务代理并调用。

示例:

添加 Maven 依赖

<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>

创建客户端接口

这个接口需要和 WSDL 中定义的 PortType 完全一致,为了方便,你可以直接从 wsimport 生成的代码中复制 WeatherWS 接口过来。

// 这个接口内容与 wsimport 生成的接口完全一样
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import com.example.weather.client.ArrayOfString; // 假设也复制了这个类
@WebService(targetNamespace = "http://WebXml.com.cn/", name = "WeatherWS")
public interface WeatherWS {
    @WebMethod
    ArrayOfString getWeather(@WebParam(name = "theCityName") String theCityName, @WebParam(name = "theCount") String theCount);
}

编写调用代码

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
public class CxfClient {
    public static void main(String[] args) {
        // 1. 创建工厂
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        // 2. 设置服务接口
        factory.setServiceClass(WeatherWS.class);
        // 3. 设置 WSDL 地址
        factory.setAddress("http://www.webxml.com.cn/WebServices/WeatherWS.asmx");
        // 4. 创建服务代理
        WeatherWS weatherWS = factory.create(WeatherWS.class);
        try {
            // 5. 调用方法
            ArrayOfString result = weatherWS.getWeather("上海", "");
            // 6. 处理结果
            System.out.println("天气预报结果:");
            for (String info : result.getString()) {
                System.out.println(info);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

CXF 的优势:配置更灵活,可以轻松添加拦截器、SOAP 头、WS-Security 等复杂功能。


方法三:使用 Spring Boot RestTemplate

大部分新开发的“WebService”其实是 RESTful 风格的,使用 Spring Boot 的 RestTemplate 是最简单直接的方式。

步骤:

  1. 添加依赖:确保有 spring-boot-starter-web
  2. 配置 RestTemplate Bean:在 Spring Boot 配置类中声明 RestTemplate
  3. 发起 HTTP 请求:在 Service 中注入 RestTemplate 并调用其方法。

示例:

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

添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

配置 RestTemplate

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

编写调用代码

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
// 假设有一个与返回 JSON 对应的 Java 类 (POJO)
class User {
    private int id;
    private String name;
    private String email;
    // Getters and Setters
    @Override
    public String toString() {
        return "User{" + "id=" + id + ", name='" + name + '\'' + ", email='" + email + '\'' + '}';
    }
}
@Service
public class UserService {
    @Autowired
    private RestTemplate restTemplate;
    public User getUserById(int id) {
        String url = "http://api.example.com/users/" + id;
        // 直接调用 getForObject,它会自动将 JSON 响应映射到 User 对象
        User user = restTemplate.getForObject(url, User.class);
        return user;
    }
    public static void main(String[] args) {
        // 为了方便演示,手动创建上下文
        // 在实际 Spring Boot 应用中,由容器自动注入
        var context = new SpringApplicationBuilder(UserService.class).run();
        UserService userService = context.getBean(UserService.class);
        User user = userService.getUserById(1);
        System.out.println(user);
    }
}

方法四:使用 Spring Boot WebClient (推荐)

WebClient 是 Spring 5 引入的响应式 HTTP 客户端,是 RestTemplate 的现代化替代品,它支持非阻塞 I/O,在性能和资源利用上更具优势。

步骤:

  1. 添加依赖:需要 spring-boot-starter-webflux
  2. 配置 WebClient Bean:在配置类中创建 WebClient 实例。
  3. 发起异步请求:使用 WebClient 的流畅 API 发起请求并处理响应。

示例:

API 同上:GET http://api.example.com/users/1

添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

配置 WebClient

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebClientConfig {
    @Bean
    public WebClient webClient() {
        return WebClient.create();
    }
}

编写调用代码

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
// User POJO 同上
@Service
public class ReactiveUserService {
    @Autowired
    private WebClient webClient;
    public Mono<User> getUserById(int id) {
        String url = "http://api.example.com/users/" + id;
        return webClient.get()
                .uri(url)
                .retrieve() // 获取响应
                .bodyToMono(User.class); // 将响应体解析为 Mono<User>
    }
    public static void main(String[] args) {
        var context = new SpringApplicationBuilder(ReactiveUserService.class).run();
        ReactiveUserService userService = context.getBean(ReactiveUserService.class);
        // 调用方法是异步的,返回一个 Mono
        Mono<User> userMono = userService.getUserById(1);
        // 订阅 Mono 来获取结果
        userMono.subscribe(user -> {
            System.out.println("获取到用户: " + user);
        }, error -> {
            System.err.println("发生错误: " + error.getMessage());
        });
        // 为了让主线程不退出,等待异步操作完成
        // 在实际应用中,通常是在一个 Web 环境中,不需要这个
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

总结与选择建议

场景 推荐技术 理由
调用传统 SOAP 服务 Apache CXF 功能强大,灵活,是企业级标准,JDK 自带的 javax.xml.ws 可用于简单场景,但扩展性差。
调用现代 RESTful API Spring Boot WebClient 最新、最现代的选择,支持响应式编程,性能更好,是 RestTemplate 的未来方向。
快速原型/简单 RESTful API Spring Boot RestTemplate 代码简单直观,易于上手,对于同步阻塞场景足够好用。
无框架的旧项目 JDK javax.xml.ws 无需引入外部依赖,适合快速集成。

最终建议:

  • 如果你的项目是 SOAP 服务,直接使用 Apache CXF
  • 如果你的项目是 Spring Boot 并且调用 RESTful 服务,优先使用 WebClient,如果项目是同步的且不想改动,RestTemplate 仍然是一个可靠的选择。
分享:
扫描分享到社交APP
上一篇
下一篇