在 Web 服务开发中,WSDL(Web Services Description Language)是描述服务接口的核心规范。它定义了服务的输入输出、数据类型、调用方式等关键信息。本文将通过对比两段 WSDL 片段,详细解析其结构差异,并深入探讨对应的 Java 调用方法及响应解析方式的不同,帮助开发者在实际开发中准确理解和使用 WSDL。
一、WSDL 片段核心差异解析
1.1 两段 WSDL 片段的原始内容
<wsdl:message name="ZXDCenterController">
<wsdl:part name="strUSER" type="xsd:string"> </wsdl:part>
<wsdl:part name="strPSW" type="xsd:string"> </wsdl:part>
<wsdl:part name="strXZDM" type="xsd:string"> </wsdl:part>
<wsdl:part name="strZXDJson" type="xsd:string"> </wsdl:part>
<wsdl:part name="sign" type="xsd:string"> </wsdl:part>
</wsdl:message>
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/">
<s:element name="ZXDCenterController">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="strUSER" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="strPSW" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="strXZDM" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="strZXDJson" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="dataType" type="s:string"/>
</s:sequence>
</s:complexType>
</s:element>
<s:element name="ZXDCenterControllerResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="ZXDCenterControllerResult" type="s:string"/>
</s:sequence>
</s:complexType>
</s:element>
<!-- 其他元素定义... -->
</s:schema>
</wsdl:types>
1.2 核心差异对比
对比维度 |
|
|
作用 | 定义消息的组成部分(数据单元) | 定义消息的数据类型(基于 XML Schema 的结构约束) |
内容重点 | 声明消息包含的参数列表( | 用 XML Schema 定义请求 / 响应的具体结构( |
参数差异 | 包含 | 包含 |
约束能力 | 仅声明参数名称和类型,无结构约束(如出现顺序) | 明确参数的出现顺序( |
命名空间 | 未显式定义命名空间(依赖上下文) | 定义了 |
1.3 为何会有这些差异?
<wsdl:message>
专注于 "传递哪些数据",是服务交互的 "数据单元清单";<wsdl:types>
专注于 "数据应遵循什么结构规则",是服务交互的 "数据格式规范"。
二、Java 调用方法的差异
2.1 基于<wsdl:message>
的 Java 调用
2.1.1 生成的客户端代码示例
// 服务接口
public interface ZXDCenterService {
// 方法签名:参数与<wsdl:message>中的part一一对应
String zXDCenterController(
String strUSER,
String strPSW,
String strXZDM,
String strZXDJson,
String sign
);
}
2.1.2 调用示例
public class MessageBasedClient {
public static void main(String[] args) {
// 1. 创建服务客户端(CXF生成的工厂类)
ZXDCenterService service = new ZXDCenterServiceService().getZXDCenterServicePort();
// 2. 准备参数(需包含sign,无需dataType)
String strUSER = "testUser";
String strPSW = "testPsw";
String strXZDM = "123456";
String strZXDJson = "{\"key\":\"value\"}";
String sign = "a1b2c3d4"; // 签名参数
// 3. 调用服务
String result = service.zXDCenterController(strUSER, strPSW, strXZDM, strZXDJson, sign);
// 4. 处理结果
System.out.println("调用结果:" + result);
}
}
2.1.3 特点总结
- 方法参数直接对应
<wsdl:message>
中的part
,数量和名称一致; - 必须显式传递
sign
参数,无需考虑dataType
; - 适合参数较少的简单服务,调用方式直观。
2.2 基于<wsdl:types>
的 Java 调用
2.2.1 生成的实体类与接口示例
// 1. 生成的请求实体类(对应<s:element name="ZXDCenterController">)
public class ZXDCenterController {
private String strUSER;
private String strPSW;
private String strXZDM;
private String strZXDJson;
private String dataType; // 包含dataType字段,无sign
// getter和setter方法
public String getStrUSER() { return strUSER; }
public void setStrUSER(String strUSER) { this.strUSER = strUSER; }
// 其他getter/setter...
}
// 2. 生成的响应实体类(对应<s:element name="ZXDCenterControllerResponse">)
public class ZXDCenterControllerResponse {
private String zXDCenterControllerResult;
public String getZXDCenterControllerResult() {
return zXDCenterControllerResult;
}
public void setZXDCenterControllerResult(String result) {
this.zXDCenterControllerResult = result;
}
}
// 3. 服务接口
public interface ZXDCenterService {
ZXDCenterControllerResponse zXDCenterController(ZXDCenterController request);
}
2.2.2 调用示例
public class TypesBasedClient {
public static void main(String[] args) {
// 1. 创建服务客户端
ZXDCenterService service = new ZXDCenterServiceService().getZXDCenterServicePort();
// 2. 构建请求实体(需设置dataType,无需sign)
ZXDCenterController request = new ZXDCenterController();
request.setStrUSER("testUser");
request.setStrPSW("testPsw");
request.setStrXZDM("123456");
request.setStrZXDJson("{\"key\":\"value\"}");
request.setDataType("json"); // 数据类型参数
// 3. 调用服务
ZXDCenterControllerResponse response = service.zXDCenterController(request);
// 4. 处理结果
String result = response.getZXDCenterControllerResult();
System.out.println("调用结果:" + result);
}
}
2.2.3 特点总结
- 方法参数为实体对象,参数通过对象的 setter 方法设置;
- 必须传递
dataType
参数,无需考虑sign
; - 适合参数较多或结构复杂的服务,符合面向对象设计;
- 自动处理参数的顺序和约束(如
minOccurs
),减少手动错误。
2.3 调用方式核心差异对比
对比项 | 基于 | 基于 |
参数形式 | 多个独立的基本类型参数 | 单个实体对象参数 |
必须传递的特殊参数 |
|
|
代码可读性 | 简单直观,但参数多时分不清关联 | 结构清晰,参数关联明确 |
维护成本 | 参数增减需修改方法签名 | 只需修改实体类,方法签名不变 |
工具依赖 | 低(可手动构造调用) | 高(依赖工具生成实体类) |
三、响应解析的差异
3.1 基于<wsdl:message>
的响应解析
3.1.1 响应 XML 示例
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ZXDCenterControllerResponse xmlns="http://tempuri.org/">
<ZXDCenterControllerResult>{"ISSuccess":true,"MessageInfo":"操作成功"}</ZXDCenterControllerResult>
</ZXDCenterControllerResponse>
</soap:Body>
</soap:Envelope>
3.1.2 解析代码示例(手动 DOM 解析)
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
public class MessageResponseParser {
public static String parseResult(String soapResponse) throws Exception {
// 1. 创建文档解析工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 关键:启用命名空间感知(因响应包含xmlns="http://tempuri.org/")
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
// 2. 解析XML响应
Document doc = builder.parse(new ByteArrayInputStream(soapResponse.getBytes()));
// 3. 查找目标节点(需指定命名空间)
NodeList nodeList = doc.getElementsByTagNameNS("http://tempuri.org/", "ZXDCenterControllerResult");
// 4. 提取节点内容
if (nodeList.getLength() > 0) {
return nodeList.item(0).getTextContent();
}
return null;
}
// 测试
public static void main(String[] args) throws Exception {
String soapResponse = "..."; // 上述响应XML
String result = parseResult(soapResponse);
System.out.println("解析结果:" + result);
// 输出:{"ISSuccess":true,"MessageInfo":"操作成功"}
}
}
3.2 基于<wsdl:types>
的响应解析
3.2.1 解析代码示例(基于生成的响应对象)
public class TypesResponseParser {
public static void main(String[] args) {
// 1. 调用服务(代码同2.2.2中的调用部分)
ZXDCenterService service = new ZXDCenterServiceService().getZXDCenterServicePort();
ZXDCenterController request = new ZXDCenterController();
// 设置请求参数...
ZXDCenterControllerResponse response = service.zXDCenterController(request);
// 2. 直接通过getter方法获取结果(无需手动解析XML)
String result = response.getZXDCenterControllerResult();
System.out.println("解析结果:" + result);
// 输出:{"ISSuccess":true,"MessageInfo":"操作成功"}
}
}
3.3 响应解析核心差异对比
对比项 | 基于 | 基于 |
解析方式 | 手动解析 XML(DOM/SAX 等) | 调用实体对象的 getter 方法 |
命名空间处理 | 需手动指定命名空间 | 工具自动处理 |
代码复杂度 | 高(需处理 XML 解析细节) | 低(直接调用方法) |
容错性 | 低(XML 结构变化会导致解析失败) | 高(工具自动适配结构变化) |
依赖 | 仅依赖 JDK 标准库 | 依赖工具生成的实体类 |
四、实际开发建议
wsdl2java -d src/main/java http://example.com/service?wsdl