上一篇
在Java中调用WCF可通过JAX-WS规范实现:添加Web服务引用生成客户端桩代码,配置端点地址与绑定参数,通过SOAP协议发送XML请求并接收响应,需引入相应依赖库
以下是关于 Java 调用 WCF 服务的完整技术实现方案,涵盖原理、工具链、代码示例及常见问题解决方案:
核心概念解析
1 WCF 的本质特征
| 特性 | 说明 |
|---|---|
| 跨平台性 | 基于 SOAP/HTTP 标准协议栈,天然支持异构系统交互 |
| 服务端形态 | 可发布为 .NET Remoting/TCP/HTTP/NamedPipes 等多种通信模式 |
| 元数据暴露 | 通过 ?wsdl 端点提供 WSDL 描述文件,供客户端自动生成调用代码 |
| 数据契约优先 | 强类型校验机制,需严格匹配服务端定义的数据结构和命名空间 |
2 Java 调用的核心挑战
协议转换:将 .NET 特有的二进制编码转换为 Java 可识别的文本格式(SOAP XML)
类型映射:复杂对象(如 DataTable、自定义类)需手动构建 Java POJO 对应关系
上下文维护:会话状态(Session)、事务边界等需显式控制
实施步骤详解
1 前置条件准备
| 序号 | 项目 | 具体要求 |
|---|---|---|
| 1 | 有效 WSDL 地址 | 确保可通过浏览器访问 http://<server>/MyService.svc?wsdl |
| 2 | JDK 版本 | 推荐 Java 8+(支持 JAX-WS 2.x 规范) |
| 3 | 构建工具 | Maven/Gradle 用于管理依赖项 |
| 4 | IDE 插件 | IntelliJ IDEA/Eclipse + Web Services Explorer 插件辅助调试 |
2 关键步骤分解
▶ Step 1: 获取并分析 WSDL 文档
curl "http://localhost:8733/Design_Time_Addresses/MyService/Service1.svc?wsdl" -o service.wsdl
重点检查项:
<wsdl:types>节点确认数据类型定义<wsdl:binding>查看传输协议(默认 HTTP/SOAP)<wsdl:service>提取端口地址池
▶ Step 2: 使用 wsimport 生成客户端桩代码
wsimport -keep -p com.example.client
-b customBinding.xml
-XautoNameResolution
http://localhost:8733/Design_Time_Addresses/MyService/Service1.svc?wsdl
参数说明:
| 参数 | 作用 |
|——————–|———————————————————————-|
| -keep | 保留原始 WSDL 文件 |
| -p <package> | 指定生成类的包路径 |
| -b <bindingFile> | 自定义绑定文件(可选) |
| -XautoNameRes | 自动解决名称冲突(推荐启用) |
▶ Step 3: Maven 依赖配置(pom.xml)
<dependencies>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-transport-http</artifactId>
<version>1.7.9</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.1</version>
</dependency>
</dependencies>
▶ Step 4: 编写调用代码(典型示例)
import javax.xml.ws.BindingProvider;
import com.example.client.Service1;
import com.example.client.Service1Soap;
public class WcfClient {
public static void main(String[] args) {
try {
// 1. 创建服务实例
Service1 service = new Service1();
// 2. 获取SOAP端口(关键步骤)
Service1Soap port = service.getBasicHttpBindingIService1();
// 3. 强制类型转换获取底层HandlerResolver
BindingProvider bp = (BindingProvider) port;
bp.getRequestContext().put("SOAPAction", "http://tempuri.org/IService1/MethodName");
// 4. 构造请求参数(注意类型匹配)
ParameterType parameter = new ParameterType();
parameter.setFieldA("TestValue");
// 5. 执行方法调用
ReturnType result = port.methodName(parameter);
System.out.println("Response: " + result.getResultField());
} catch (Exception e) {
e.printStackTrace();
// 特殊处理:捕获SOAPFaultDetail元素中的错误详情
if (e instanceof javax.xml.ws.soap.SOAPFaultException) {
System.err.println("SOAP Fault Code: " + ((javax.xml.ws.soap.SOAPFaultException)e).getFault().getFaultCode());
}
}
}
}
️ 关键注意事项:
- 命名空间一致性:生成的 SEI(Service Endpoint Interface)必须与 WSDL 完全一致
- 集合类型处理:ArrayOfXXX 类需使用 List
