Webservice的wsdl文件解析与Soap消息的发送、接收(不生成java客户端代码)

本文介绍了一款专为公司QA测试人员设计的Webservice测试工具,该工具能够通过提供的Webservice URL自动获取服务的方法及其参数,并支持多种参数类型,如数组、List等。测试人员可在界面上填写参数并执行方法,查看返回结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[b][color=red]附件中附带页面jsp、js,还有dwr的action,service以及util,我的环境是spring、dwr、ext、jquery。由于整个工具牵扯的比较多,所以没有将完整的可运行的代码整理出来,只将所有核心的代码贴了出来,如果需要运行还需要解决些小问题[/color][/b]

近段时间,需要为公司的QA测试人员提供一个Webservice的测试工具,具体要求为:测试人员提供webservice的url,测试工具根据url得到webservice发布的方法及方法的参数,然后测试人员在页面输入参数,并点击运行,工具运行后,在页面上显示返回的结果。其实测试人员可以用现成在测试框架soapui来测试webservice,不过测试人员仍觉得麻烦,Team Leader还要求工具不能用wsdl2java生成webservice的客户端代码。我想可能是不想在项目中存放过多的无用的临时文件吧。

[b][color=blue]测试工具支持参数和返回值的类型有:数组、List、java基本数据类型、java对象以及这些类型的相互嵌套。工具截图如下[/color][/b]
[img]http://dl.iteye.com/upload/attachment/550194/a97dc599-146a-3a93-923e-9dc70f3bb5e1-thumb.jpg[/img]
[img]http://dl.iteye.com/upload/attachment/550196/888d1cc4-ae8c-33c5-b0ae-590b883d37dc.jpg[/img]
[img]http://dl.iteye.com/upload/attachment/550198/856a9cba-a41c-39a0-822a-fd80f995922c.jpg[/img]
[img]http://dl.iteye.com/upload/attachment/550200/b466374a-9ca8-324c-9310-9c577dda577c.jpg[/img]
[img]http://dl.iteye.com/upload/attachment/550202/a3d8cf7e-eada-3c84-a8b0-9a544c1d85d8.jpg[/img]
[img]http://dl.iteye.com/upload/attachment/550204/fa346a7b-81bb-3cc8-8c2b-da89f8ef2da3.jpg[/img]

[b]下面说说工具的实现思路:[/b]
[list]
[*]用wsdl4j工具根据webservice的url解析出wsdl文件中包含的方法
[*]利用dom解析wsdl的schema部分,手动解析出方法的参数
[*]利用soapui获得发送soap请求消息的模板
[*]将参数填入发送的soap请求消息
[*]获得返回的soap消息
[*]解析返回的soap消息中的返回值,显示到页面
[/list]

[b]在看实现代码前,不懂wsdl和schema的朋友们可以根据以下网址,先熟悉一下wsdl和schema文件的结构,和各个属性字段[/b]
[list]
[*][b]wsdl[/b]:[url]http://www.w3school.com.cn/wsdl/index.asp[/url]
[*][b]schema[/b]:[url]http://www.w3school.com.cn/schema/index.asp[/url]
[/list]

[b]代码讲解:[/b]
[b]用于在页面显示方法和方法参数的实体bean[/b]
/**
* @author zhengtian
*
* @date 2011-8-4 下午11:21:50
*/
@SuppressWarnings("all")
public class WebServiceMethod {
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

}



import java.util.ArrayList;
import java.util.List;

public class ParameterInfo {
private String name;// 参数名
private String value;// 参数值
private String type;// 参数类型
private String childType;// 如果是数组,那么该字段为数组元素的类型
private List<ParameterInfo> children = new ArrayList<ParameterInfo>();

public ParameterInfo() {

}

public ParameterInfo(String name, String type) {
this.name = name;
this.type = type;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

public List<ParameterInfo> getChildren() {
return children;
}

public void setChildren(List<ParameterInfo> children) {
this.children = children;
}

public String getChildType() {
return childType;
}

public void setChildType(String childType) {
this.childType = childType;
}

/**
* 增加子参数
*
* @param param
*/
public void addChild(ParameterInfo param) {
children.add(param);
}
}


[b]获取webservice发布的方法[/b]

public List<WebServiceMethod> getAllMethodByServiceUrl(String webserviceUrl) throws Exception {
// 结果
List<WebServiceMethod> list = new ArrayList<WebServiceMethod>();
try {
// 将url修正为合法的url,即带wsdl后缀的
webserviceUrl = getWebserviceUrl(webserviceUrl);
if (StringUtils.isNotEmpty(webserviceUrl)) {
List<String> methodList = WsdlUtil.getOperationList(webserviceUrl);
for (String methodName : methodList) {
WebServiceMethod webServiceMethod = new WebServiceMethod();
webServiceMethod.setName(methodName);

list.add(webServiceMethod);
}
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return list;
}



/**
* 得到wsdl中所有的方法
*
* @param wsdlUrl
* @return
* @throws Exception
*/
public static List<String> getOperationList(String wsdlUrl) throws Exception {
Document document = getDefinitionDocument(wsdlUrl);
XPath xpath = getXpath(document);

NodeList operations = DOMUtil.findNodeList(document, "wsdl:definitions/wsdl:portType/wsdl:operation");

// 返回的结果集list
List<String> operationList = new ArrayList<String>();
for (int i = 0; i < operations.getLength(); i++) {
Node operation = operations.item(i);
String operationName = DOMUtil.getNodeName(operation);
if (operationName != null && !"".equals(operationName)) {
log.debug("解析" + wsdlUrl + "中的方法:" + operationName);
operationList.add(operationName);
}
}
return operationList;
}



[b]得到方法的参数[/b]

/**
* 根据方法名称和webserviceUrl得到参数
*
* @param methodName
* @param webserviceUrl
* @return
* @throws Exception
*/
public List<ParameterInfo> getParamByMethodNameAndWsUrl(String methodName, String webserviceUrl) throws Exception {
try {
Document document = WsdlUtil.getDefinitionDocument(webserviceUrl);
// 返回结果
List<ParameterInfo> inputParamList = new ArrayList<ParameterInfo>();
// 解析参数
StringBuilder xpathBuilder = new StringBuilder();
WsdlUtil.getInputParam(inputParamList, document, methodName, xpathBuilder, null, false);
return inputParamList;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}


[b]解析输入参数的核心方法[/b]


/**
* 得到输入参数
*
* @param inputParamList
* @param document
* @param operationName
* @param xpathBuilder
* @param parentParam
* @param isSelfDefinition
* @throws Exception
*/
public static void getInputParam(List<ParameterInfo> inputParamList, Document document, String operationName, StringBuilder xpathBuilder,
ParameterInfo parentParam, boolean isSelfDefinition) throws Exception {
// 得到complexTypeName
String complexTypeName = "";
if (parentParam == null) {
complexTypeName = operationName;
} else {
if (parentParam.getType().equals(SchemaDefaulyType.type_array.type)) {
complexTypeName = parentParam.getChildType();
} else {
complexTypeName = parentParam.getType();
}
}

// 得到所有的element结点
List<Node> children = getSequenceElementOfComplexType(document, parentParam, complexTypeName, xpathBuilder, isSelfDefinition);
for (int i = 0; i < children.size(); i++) {
// 子结点
Node child = children.get(i);
String name = DOMUtil.getNodeName(child);

// 参数
ParameterInfo param = new ParameterInfo();
param.setName(name);

// 是否存在type属性(判断其type是引用还是自身定义)
if (DOMUtil.assertNodeAttributeExist(child, "type")) {//type存在
String type = DOMUtil.getNodeType(child);

if (DOMUtil.isArray(child)) {
param.setType(SchemaDefaulyType.type_array.type);
param.setChildType(type);

// 如果是简单的数组,则为数组增加一个子参数
ParameterInfo childParam = new ParameterInfo("", type);
param.addChild(childParam);

// 复杂类型数组
if (!DOMUtil.isDefaultType(child)) {
getInputParam(inputParamList, document, operationName, xpathBuilder, childParam, false);
}
} else {
param.setType("anyType".equals(type) ? "object" : type);

// 复杂类型
if (!DOMUtil.isDefaultType(child)) {
StringBuilder complextXpath = new StringBuilder("wsdl:definitions/wsdl:types/xs:schema");
getInputParam(inputParamList, document, operationName, complextXpath, param, false);
}
}
} else {// 如果type属性不存在,说明该结点的类型在其子结点中定义
String currentAppendStr = "/xs:complexType[@name='" + parentParam.getType() + "']/xs:sequence/xs:element[@name='" + name + "']";
xpathBuilder.append(currentAppendStr);
Node inner = DOMUtil.findNode(document, xpathBuilder.toString() + "/xs:complexType/xs:sequence/xs:element[position()=1]");

if (DOMUtil.isArray(inner)) {
// 得到数组的类型
String type = getSequenceElementType(document, inner);
param.setType(SchemaDefaulyType.type_array.type);
param.setChildType(type);

// 为数组增加一个子参数
ParameterInfo childParam = new ParameterInfo("", type);
param.addChild(childParam);

if (!DOMUtil.isDefaultType(type)) {// 复杂类型数组
getInputParam(inputParamList, document, operationName, xpathBuilder, childParam, true);
}
} else {
param.setType(name);
// 遍历其子结点xs:element
getInputParam(inputParamList, document, operationName, xpathBuilder, param, true);
}

// 将xpath还原
xpathBuilder.delete(xpathBuilder.length() - currentAppendStr.length(), xpathBuilder.length());
}

if (parentParam == null) {
inputParamList.add(param);
} else {
parentParam.addChild(param);
}
}
}


[b]当页面输入完参数后,执行方法[/b]

/**
* 执行方法
*
* @param webserviceUrl
* @param methodName
* @param paramStr
* @return
* @throws Exception
*/
public String executionMethod(String webserviceUrl, String methodName, String paramStr) throws Exception {
String result = "";
try {
// 将json参数转换为List<ParameterInfo>
List<ParameterInfo> paramList = convertStrToListParam(paramStr);

List<ParameterInfo> resultList = new SoapUtil().sendRequest(methodName, paramList, webserviceUrl);

result = JSONArray.fromObject(resultList).toString();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return result;
}


[b]发送soap请求,然后获得返回的soap消息[/b]

/**
* 发送请求
*
* @param operation
* @param params
* @param wsdlUrl
* @return
* @throws Exception
*/
public List<ParameterInfo> sendRequest(String operation, List<ParameterInfo> paramList, String wsdlUrl) throws Exception {
// 获取操作
Operation operationInst = getOperation(wsdlUrl, operation, null);
// 组装请求消息
String message = buildRequest(wsdlUrl, operationInst, paramList);
// 发送请求,得到返回的soap消息
String address = wsdlUrl.substring(0, wsdlUrl.indexOf("?wsdl"));
String responseStr = sendRequest(address, message, operationInst.getAction());
Document soapDocument = getResponseDocument(responseStr);
// 判断返回的soap消息是否为soap:Fault
if (isFaultResponseSoap(soapDocument)) {
processFaultResponseSoap(soapDocument);
}
// 解析返回结果
List<ParameterInfo> outPutParamList = new ArrayList<ParameterInfo>();
List<Map<String, Object>> wsdlMapSoapList = new ArrayList<Map<String, Object>>();
String complextTypeName = operation + "Response";

getOutPutParam(WsdlUtil.getDefinitionDocument(wsdlUrl), soapDocument, complextTypeName, complextTypeName, wsdlMapSoapList, outPutParamList,
null);

return outPutParamList;
}


[b]将参数解析成发送的soap消息核心方法[/b]

/**
* 构建soap消息
*
* @param wsdlDocument
* @param soapDocument
* @param operationInst
* @param paramList
* @param parentNode
* @throws Exception
*/
private void buildSOAPMessage(Document wsdlDocument, Document soapDocument, Operation operationInst, List<ParameterInfo> paramList,
Node parentNode, ParameterInfo parentParam) throws Exception {
// 操作名称
String operationName = operationInst.getName();
// 如果是操作方法的根节点,则清空其子节点
if (parentNode == null) {
parentNode = getOperationNodeInRequestSoapDom(soapDocument, operationName);
parentNode.setTextContent("");
}

for (int i = 0; i < paramList.size(); i++) {
// 得到参数的name、type、value
ParameterInfo param = paramList.get(i);
String value = param.getValue();
String name = param.getName();
String type = param.getType();

// 判断是否为基本类型
if (DOMUtil.isDefaultType(type) || (StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(type))
|| ("entry".equals(type) || "JsonEntry".equals(type))) {
if (StringUtils.isEmpty(name)) {
if (i > 0) {
Element ele = soapDocument.createElement(parentNode.getNodeName());
Text text = soapDocument.createTextNode(value);
ele.appendChild(text);

Node grandParentNode = parentNode.getParentNode();
grandParentNode.appendChild(ele);
} else {
if ("entry".equals(type) || "JsonEntry".equals(type)) {
Element ele = soapDocument.createElement(type);
parentNode.appendChild(ele);

// 组装子结点
if (param.getChildren().size() > 0) {
List<Node> childList = DOMUtil.getChildElementNodes(parentNode);
Node lastChildNode = childList.get(childList.size() - 1);
buildSOAPMessage(wsdlDocument, soapDocument, operationInst, param.getChildren(), lastChildNode, param);
}
} else {
Text text = soapDocument.createTextNode(value);
parentNode.appendChild(text);
}
}
} else {
Element ele = soapDocument.createElement(name);
Text text = soapDocument.createTextNode(value);
ele.appendChild(text);
parentNode.appendChild(ele);

// 组装子结点
if (param.getChildren().size() > 0) {
List<Node> childList = DOMUtil.getChildElementNodes(parentNode);
Node lastChildNode = childList.get(childList.size() - 1);
buildSOAPMessage(wsdlDocument, soapDocument, operationInst, param.getChildren(), lastChildNode, param);
}
}
} else {// 如果不是基本类型,则直接组装该节点的子结点
if (i > 0) {
Element ele = soapDocument.createElement(parentNode.getNodeName());
Node grandParentNode = parentNode.getParentNode();
grandParentNode.appendChild(ele);
// 组装子结点
if (param.getChildren().size() > 0) {
List<Node> childList = DOMUtil.getChildElementNodes(grandParentNode);
Node lastChildNode = childList.get(childList.size() - 1);
buildSOAPMessage(wsdlDocument, soapDocument, operationInst, param.getChildren(), lastChildNode, param);
}
} else {
// 组装子结点
if (param.getChildren().size() > 0) {
buildSOAPMessage(wsdlDocument, soapDocument, operationInst, param.getChildren(), parentNode, param);
}
}
}

}
}


[b]将返回的soap消息解析成页面参数核心方法[/b]

/**
* 解析返回的soap消息,然后将结果填充到outPutParamList中
*
* @param wsdlDocument
* @param soapDocument
* @param operationResponseName
* @param complextTypeName
* @param wsdlMapSoapList
* @param outPutParamList
* @throws Exception
*/
public void getOutPutParam(Document wsdlDocument, Document soapDocument, String operationResponseName, String complextTypeName,
List<Map<String, Object>> wsdlMapSoapList, List<ParameterInfo> outPutParamList, ParameterInfo parent) throws Exception {
// 得到返回的参数
List<Node> outPutNodeList = WsdlUtil.getSequenceElementOfComplexType(wsdlDocument, complextTypeName);

for (int i = 0; i < outPutNodeList.size(); i++) {
Map<String, Object> wsdlMapSoap = new HashMap<String, Object>();
// 组装参数param
Node outPutNode = outPutNodeList.get(i);
String name = DOMUtil.getNodeName(outPutNode);
String type = DOMUtil.getNodeType(outPutNode);

ParameterInfo currentParam = new ParameterInfo();
currentParam.setName(name);

if (DOMUtil.isDefaultType(outPutNode)) {// 该参数为基本类型
if (DOMUtil.isArray(outPutNode)) {// 数组
currentParam.setType(WsdlUtil.SchemaDefaulyType.type_array.getType());
currentParam.setChildType(type);

// 组装映射关系
wsdlMapSoap.put("name", name);
wsdlMapSoap.put("index", new Integer(-1));
wsdlMapSoapList.add(wsdlMapSoap);

// 得到该数组在返回soap消息中的个数
int arrayLength = getArrayLengthFromResponseSoap(soapDocument, operationResponseName, wsdlMapSoapList);

// 从soap消息中取出值
for (int j = 1; j <= arrayLength; j++) {
ParameterInfo param = new ParameterInfo();
param.setName(name);
param.setType(type);

wsdlMapSoap.put("index", new Integer(j));

String value = getValueFromResponseSoap(soapDocument, wsdlMapSoapList, operationResponseName);
param.setValue(value);

currentParam.addChild(param);
}
} else {// 不是数组
currentParam.setType(type);
// 根据映射关系,从返回的soap消息中取值
wsdlMapSoap.put("name", name);
wsdlMapSoap.put("index", new Integer(-1));

wsdlMapSoapList.add(wsdlMapSoap);
String value = getValueFromResponseSoap(soapDocument, wsdlMapSoapList, operationResponseName);
currentParam.setValue(value);
}
} else {// 该参数为复杂类型
if (DOMUtil.isArray(outPutNode)) {// 数组
currentParam.setType(WsdlUtil.SchemaDefaulyType.type_array.getType());
currentParam.setChildType(type);

// 组装映射关系
wsdlMapSoap.put("name", name);
wsdlMapSoap.put("index", new Integer(-1));
wsdlMapSoapList.add(wsdlMapSoap);

// 得到该数组在返回soap消息中的个数
int arrayLength = getArrayLengthFromResponseSoap(soapDocument, operationResponseName, wsdlMapSoapList);

// 从soap消息中取出值
for (int j = 1; j <= arrayLength; j++) {
ParameterInfo param = new ParameterInfo();
param.setType(type);

wsdlMapSoap.put("index", new Integer(j));

// 继续查找
getOutPutParam(wsdlDocument, soapDocument, operationResponseName, type, wsdlMapSoapList, outPutParamList, param);

currentParam.addChild(param);
}
} else {// 不是数组
currentParam.setType(type);
// 根据映射关系,从返回的soap消息中取值
wsdlMapSoap.put("name", name);
wsdlMapSoap.put("index", new Integer(-1));

wsdlMapSoapList.add(wsdlMapSoap);

// 继续查找
getOutPutParam(wsdlDocument, soapDocument, operationResponseName, type, wsdlMapSoapList, outPutParamList, currentParam);
}
}
// 增加参数
if (parent == null) {
outPutParamList.add(currentParam);
} else {
parent.addChild(currentParam);
}
// 在映射关系中除去当前的结点
wsdlMapSoapList.remove(wsdlMapSoapList.size() - 1);
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值