前言
在企业级系统开发中,Web Service 是一种常见的跨平台通信方式。尤其是在与旧系统对接时,我们经常需要通过 SOAP 协议调用远程 WebService 接口。
本文将详细介绍如何在 Spring Boot 项目中使用 Apache CXF 实现 WebService 的动态调用和静态调用,并附上完整的示例代码和操作步骤。
前提准备,添加依赖(Spring Boot + CXF)
这个 Maven 依赖是动态调用方法和静态调用方法都需要使用的。添加后更新 Maven。
Spring Boot 项目使用 Apache CXF 集成 WebService 接口,提供动态调用与静态调用两种方案。动态调用基于 JaxWsDynamicClientFactory 直接请求 WSDL,灵活但类型不安全,适合调试;静态调用通过 wsimport 生成 Java 类,编译期检查强,易维护,推荐生产使用。需添加 cxf-spring-boot-starter-jaxws 依赖,处理 WSDL 文件并导入生成的类至项目包中。
在企业级系统开发中,Web Service 是一种常见的跨平台通信方式。尤其是在与旧系统对接时,我们经常需要通过 SOAP 协议调用远程 WebService 接口。
本文将详细介绍如何在 Spring Boot 项目中使用 Apache CXF 实现 WebService 的动态调用和静态调用,并附上完整的示例代码和操作步骤。
这个 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 配置。
动态调用不依赖生成的 Java 类,直接通过 URL 和方法名调用,灵活性高,适合快速测试。
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.4.10</version>
</dependency>
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
public class WebServiceDynamicClient {
public String[] 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();
}
return null;
}
}
client.invoke() 返回的是 Object[],第一个元素是实际返回值。静态调用通过 WSDL 文件生成 Java 类,然后像调用本地方法一样调用远程服务,类型安全、易维护。
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.4.10</version>
</dependency>
在浏览器中访问:
http://127.0.0.1/Service.asmx?wsdl
可以看到如下内容,说明 URL 有效。页面显示 WSDL 内容 → 右键另存为 → 保存为 service.wsdl。
注意:必须以 .wsdl 结尾。
打开命令行,输入:
wsimport -version
如果提示找不到命令,请安装 JDK 并确保 JAVA_HOME 配置正确。
wsimport -keep -d . -p com.example.wsclient service.wsdl
注意这里如果提示 wsdl 文件中有错误,那么就打开这个文件修改不对的地方,重新生成即可。
例如我有个报错:
报错的节点:
<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>
当时是这句报错了:
<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(数组包装类)。
将所有生成的 .java 文件复制到你的项目中指定包下,例如:
src/main/java/com/example/webservice/
这里注意,只需要.java 类型的文件,.class 类型的文件可以删除。
手动修改所有类的第一行包名,确保一致(可使用 Ctrl+Shift+R 全局替换)。
import com.AllProcess.process.webservice.Service; // 通讯类
import com.AllProcess.process.webservice.ServiceSoap; // 调用接口
import com.AllProcess.process.webservice.ArrayOfString;
import org.springframework.stereotype.Component;
import javax.xml.namespace.QName;
import java.net.URL;
import java.util.Arrays;
@Component
public class WebServiceStaticClient {
private static final String WEBSERVICE_WSDL_URL = "http://127.0.0.1/Service.asmx?wsdl";
private static final String LOCAL_WSDL_PATH = "file:/D:/文件夹/service.wsdl";
public String[] callFuc1(String flag, String mac, String psw) {
try {
// 1. 创建 URL 对象(远程或本地)
URL wsdlURL = new URL(WEBSERVICE_WSDL_URL);
// 2. 创建服务实例
Service service = new Service(wsdlURL, new QName("http://www.xxx/", "Service"));
// 3. 获取端口代理
ServiceSoap port = service.getServiceSoap();
// 4. 调用方法
ArrayOfString resultGetData = port.fuc1(flag, mac, psw);
// 5. 转为 String[]
String[] result = resultGetData.getString().toArray(new String[0]);
System.out.println("Response: " + Arrays.toString(result));
return result;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
| 维度 | 动态调用 | 静态调用 |
|---|---|---|
| 开发效率 | 快 | 慢(需生成类) |
| 类型安全 | 弱(运行时异常) | 强(编译期检查) |
| 易维护性 | 差 | 好 |
| 生产建议 | ❌ 不推荐 | ✅ 推荐 |
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 动态调用 | 灵活、无需生成类 | 类型不安全、不支持复杂对象 | 快速测试、临时调用 |
| 静态调用 | 类型安全、易维护 | 需要生成类、流程繁琐 | 生产环境、长期使用 |

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online