【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类型的文件可以删除

- 手动修改所有类的第一行包名,确保一致(可使用
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服务中的数据!
三、动态调用和静态调用哪个更好?
| 维度 | 动态调用 | 静态调用 |
|---|---|---|
| 开发效率 | 快 | 慢(需生成类) |
| 类型安全 | 弱(运行时异常) | 强(编译期检查) |
| 易维护性 | 差 | 好 |
| 生产建议 | ❌ 不推荐 | ✅ 推荐 |
总结
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 动态调用 | 灵活、无需生成类 | 类型不安全、不支持复杂对象 | 快速测试、临时调用 |
| 静态调用 | 类型安全、易维护 | 需要生成类、流程繁琐 | 生产环境、长期使用 |
📚 参考资料
🎯 建议:开发阶段用 动态调用 快速验证接口上线前用 静态调用 替换,保证稳定性
📌 欢迎点赞、收藏、转发!