【Spring Boot】Spring Boot调用 WebService 接口的两种方式:动态调用 vs 静态调用 亲测有效

文章目录


前言

在企业级系统开发中,Web Service 是一种常见的跨平台通信方式。尤其是在与旧系统对接时,我们经常需要通过 SOAP 协议调用远程 WebService 接口。

本文将详细介绍如何在 Spring Boot 项目中使用 Apache CXF 实现 WebService 的 动态调用静态调用,并附上完整的示例代码和操作步骤。

✅ 支持返回 String[]byte[] 等复杂类型
✅ 提供 WSDL 文件处理流程
✅ 包含常见问题解决方案

0、前提准备,添加依赖(Spring Boot + CXF)

这个maven依赖是动态调用方法和静态调用方法都需要使用的。添加后更新maven。

<dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-spring-boot-starter-jaxws</artifactId><version>3.4.10</version></dependency>
💡 使用 cxf-spring-boot-starter-jaxws 可以自动配置 CXF,无需额外 XML 配置。

一、 方法一:动态调用 WebService(推荐用于调试)

动态调用不依赖生成的 Java 类,直接通过 URL 和方法名调用,灵活性高,适合快速测试。

1. 添加依赖(Spring Boot + CXF)

<dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-spring-boot-starter-jaxws</artifactId><version>3.4.10</version></dependency>
💡 使用 cxf-spring-boot-starter-jaxws 可以自动配置 CXF,无需额外 XML 配置。

2、调用示例代码

importorg.apache.cxf.endpoint.Client;importorg.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;publicclassWebServiceDynamicClient{publicString[]callFuc1(String flag,String mac,String psw){try{// 创建动态客户端JaxWsDynamicClientFactory dcf =JaxWsDynamicClientFactory.newInstance();Client client = dcf.createClient("http://127.0.0.1/Service.asmx?wsdl");// 调用方法,返回 Object[]Object[] objects = client.invoke("fuc1", flag, mac, psw);// 如果返回的是数组,转换为 String[]if(objects !=null&& objects.length >0){return(String[]) objects[0];// 注意:返回值可能在 objects[0]}}catch(Exception e){ e.printStackTrace();}returnnull;}

这里我调用的时候,在创建客户端对象的时候报错了,仅供参考。

3、注意事项

  • client.invoke() 返回的是 Object[],第一个元素是实际返回值。
  • 动态调用不支持复杂的对象类型(如自定义类),仅适用于基本类型或数组。
  • 不推荐用于生产环境,但非常适合快速验证接口是否可用。

二、方法二:静态调用 WebService(推荐用于生产)

静态调用通过 WSDL 文件生成 Java 类,然后像调用本地方法一样调用远程服务,类型安全、易维护。

1. 添加依赖(Spring Boot + CXF)

<dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-spring-boot-starter-jaxws</artifactId><version>3.4.10</version></dependency>
💡 使用 cxf-spring-boot-starter-jaxws 可以自动配置 CXF,无需额外 XML 配置。

2、获取 WSDL 文件

在浏览器中访问:

http://127.0.0.1/Service.asmx?wsdl 

可以看到如下内容,说明URL有效。

在这里插入图片描述

页面显示 WSDL 内容 → 右键另存为 → 保存为 service.wsdl

👉 注意:必须以 .wsdl 结尾
在这里插入图片描述

3、使用 wsimport 生成 Java 类

1. 检查 wsimport 是否存在

打开命令行,输入:

wsimport -version 
在这里插入图片描述

如果提示找不到命令,请安装 JDK 并确保 JAVA_HOME 配置正确。

2. 进入存放 service.wsdl 的目录,执行:
wsimport -keep -d . -p com.example.wsclient service.wsdl 
在这里插入图片描述

注意这里如果提示wsdl文件中有错误,那么就打开这个文件修改不对的地方,重新生成即可。

例如我有个报错:

在这里插入图片描述

我是将284行这个地方,报错的节点修改了一下,重新保存生成就可以了。

报错的节点:

<s:element name="GetDataResponse"> <s:complexType> <s:sequence> <s:element minOccurs="0" maxOccurs="1" name="GetDataResult"> <s:complexType> <s:sequence> <s:element ref="s:schema"/> <s:any/> </s:sequence> </s:complexType> </s:element> </s:sequence> </s:complexType> 

当时是这句报错了:

<s:element ref="s:schema"/> <s:any/> 

修改后的节点:

 <s:element name="GetDataResponse"> <s:complexType> <s:sequence> <s:element minOccurs="0" maxOccurs="1" name="GetDataResponse"> <s:complexType> <s:sequence> <!-- 替换非法引用为任意 XML --> <s:any minOccurs="0" maxOccurs="unbounded" processContents="lax" /> </s:sequence> </s:complexType> </s:element> </s:sequence> </s:complexType> </s:element> 

参数说明:

参数说明
-keep保留生成的源文件
-d .输出目录为当前目录
-p com.example.wsclient指定包名(替换为你自己的包)
✅ 成功后会生成多个 Java 类,包括:Service.java(服务类)ServiceSoap.java(端口接口)ArrayOfString.java(数组包装类)
在这里插入图片描述

4、将生成的类导入项目

将所有生成的 .java 文件复制到你的项目中指定包下,例如:

src/main/java/com/example/webservice/ 
这里注意,只需要.java类型的文件,.class类型的文件可以删除
在这里插入图片描述
  1. 手动修改所有类的第一行包名,确保一致(可使用 Ctrl+Shift+R 全局替换)。
在这里插入图片描述

5、示例代码:静态调用

importcom.AllProcess.process.webservice.Service;// 通讯类importcom.AllProcess.process.webservice.ServiceSoap;// 调用接口importcom.AllProcess.process.webservice.ArrayOfString;importorg.springframework.stereotype.Component;importjavax.xml.namespace.QName;importjava.net.URL;@ComponentpublicclassWebServiceStaticClient{privatestaticfinalString WEBSERVICE_WSDL_URL ="http://127.0.0.1/Service.asmx?wsdl";privatestaticfinalString LOCAL_WSDL_PATH ="file:/D:/文件夹/service.wsdl";publicString[]callFuc1(String flag,String mac,String psw){try{// 1. 创建 URL 对象(远程或本地)URL wsdlURL =newURL(WEBSERVICE_WSDL_URL);// 2. 创建服务实例Service service =newService(wsdlURL,newQName("http://www.xxx/","Service"));// 3. 获取端口代理ServiceSoap port = service.getServiceSoap();// 4. 调用方法ArrayOfString resultGetData = port.fuc1(flag, mac, psw);// 5. 转为 String[]String[] result = resultGetData.getString().toArray(newString[0]);System.out.println("Response: "+Arrays.toString(result));return result;}catch(Exception e){ e.printStackTrace();returnnull;}}}

最后我在用静态调用方法后,接收到webservice服务写的数据啦~~!

亲测有效。可以读取到webservice服务中的数据!

三、动态调用和静态调用哪个更好?

维度动态调用静态调用
开发效率慢(需生成类)
类型安全弱(运行时异常)强(编译期检查)
易维护性
生产建议❌ 不推荐✅ 推荐

总结

方法优点缺点适用场景
动态调用灵活、无需生成类类型不安全、不支持复杂对象快速测试、临时调用
静态调用类型安全、易维护需要生成类、流程繁琐生产环境、长期使用

📚 参考资料


🎯 建议:开发阶段用 动态调用 快速验证接口上线前用 静态调用 替换,保证稳定性

📌 欢迎点赞、收藏、转发!

Read more

深入理解强化学习:近端策略优化(PPO)算法详解

深入理解强化学习:近端策略优化(PPO)算法详解

深入理解强化学习:近端策略优化(PPO)算法详解 近端策略优化(Proximal Policy Optimization, PPO)是强化学习领域最具影响力和应用最广泛的算法之一。自2017年由OpenAI提出以来,它凭借其出色的稳定性、高效的性能和相对简单的实现,成为了许多复杂决策任务的首选算法。本文将带你深入剖析PPO的每一个细节,从算法的起源、核心数学原理,到公式的详细推导和广泛的实际应用。 1. 算法的由来:为什么我们需要PPO? 在PPO诞生之前,策略梯度(Policy Gradient, PG)方法是解决强化学习问题的主流选择。然而,传统的PG方法存在两个棘手的问题: 1. 更新步长敏感性:策略网络的更新步长(即学习率)极难选择。如果步长太大,一次糟糕的更新就可能让策略性能急剧下降,甚至“万劫不复”;如果步长太小,训练过程又会变得异常缓慢,难以收敛。 2. 数据利用率低:大多数基础的PG算法(如REINFORCE)是On-policy的,这意味着它们只能使用当前策略采样的数据进行学习。一旦策略更新,所有旧数据都将被丢弃,导致采样效率极低。

By Ne0inhk
数据结构:双向链表(2)

数据结构:双向链表(2)

目录  前言  一、实现双向链表 1.双向链表查找  2.双向链表在指定位置插入 双向链表在指定位置之后插入 双向链表在指定位置之前插入  3.双向链表指定位置删除 4.总代码展示:(加入了测试代码) 二、顺序表与链表的分析 一、相同点 二、不同点(核心差异) 三、关键结论 三、链表算法题 一、移除链表元素  二、反转链表     总结  前言    上一篇文章讲解了双向链表概念与结构,实现双向链表(双向链表的初始化,双向链表的尾插,双向链表的头插,双向链表的尾删,双向链表的头删)等知识的相关内容,其中实现双向链表其余部分,顺序表与链表的分析,链表算法题为本章节知识的内容。 一、实现双向链表 1.双向链表查找 双向链表的查找操作与单链表类似,但可利用创建一个暂时的指针实现遍历。 函数形式:

By Ne0inhk
Flutter 组件 easter 适配鸿蒙 HarmonyOS 实战:天文学节气算法,构建全球化复活节周期与民俗历法治理架构

Flutter 组件 easter 适配鸿蒙 HarmonyOS 实战:天文学节气算法,构建全球化复活节周期与民俗历法治理架构

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 easter 适配鸿蒙 HarmonyOS 实战:天文学节气算法,构建全球化复活节周期与民俗历法治理架构 前言 在鸿蒙(OpenHarmony)生态迈向全球化部署、涉及跨区域文化适配(I18n)及复杂变动日期计算的背景下,如何精确推演具备“阴阳历混合特性”的全球性节日(如复活节),已成为决定跨国类应用“运营确定性”的核心技术难点。在鸿蒙设备这类强调 AOT 极致性能与低功耗常驻服务(AOD)的环境下,如果应用依然依赖手动配置的“节日死表”,由于由于复活节日期在全球范围内的复杂游移性,极易由于由于配置滞后导致海外营销活动的时序错乱。 我们需要一种能够实现高精度天文学推演、支持百年尺度计算且具备纯 Dart 离线运作能力的历法预判方案。 easter 为 Flutter 开发者引入了基于高斯算法(Gauss's algorithm)或曼氏算法(Meeus&

By Ne0inhk
从零破局:LeetCode 1 & 2 超详细解剖 - 算法思维的第一块敲门砖

从零破局:LeetCode 1 & 2 超详细解剖 - 算法思维的第一块敲门砖

前言:         “各位老铁,好久不见。是的,博客又双叒叕长草了。这次停更的理由,简单到令人发指:纯粹是因为懒。不是没想法,不是没选题,就是单纯的……不想动。那种下班后只想‘葛优躺’、周末只想‘游戏宅’的状态,懂的都懂。每次打开编辑器,感觉手指头有千斤重。         但心里总有个声音在嘀咕:再懒下去,脑子怕是要生锈得更快了。是时候重启一下了!思来想去,决定回归最基础、也最经典的起点——LeetCode上的‘两数之和’(第1题)和‘两数相加’(第2题)。别小看这两道题,它们就像算法世界的‘Hello World’,看似简单,却是理解哈希、链表、模拟等核心思想的绝佳入口。今天就让我们从这‘最初的记忆’开始,一起重新找回敲代码的节奏和乐趣吧!” 1.两数之和 1.1.题目来源

By Ne0inhk