附件中附带页面jsp、js,还有dwr的action,service以及util,我的环境是spring、dwr、ext、jquery。由于整个工具牵扯的比较多,所以没有将完整的可运行的代码整理出来,只将所有核心的代码贴了出来,如果需要运行还需要解决些小问题
近段时间,需要为公司的QA测试人员提供一个Webservice的测试工具,具体要求为:测试人员提供webservice的url,测试工具根据url得到webservice发布的方法及方法的参数,然后测试人员在页面输入参数,并点击运行,工具运行后,在页面上显示返回的结果。其实测试人员可以用现成在测试框架soapui来测试webservice,不过测试人员仍觉得麻烦,Team Leader还要求工具不能用wsdl2java生成webservice的客户端代码。我想可能是不想在项目中存放过多的无用的临时文件吧。
测试工具支持参数和返回值的类型有:数组、List、java基本数据类型、java对象以及这些类型的相互嵌套。工具截图如下
下面说说工具的实现思路:
- 用wsdl4j工具根据webservice的url解析出wsdl文件中包含的方法
- 利用dom解析wsdl的schema部分,手动解析出方法的参数
- 利用soapui获得发送soap请求消息的模板
- 将参数填入发送的soap请求消息
- 获得返回的soap消息
- 解析返回的soap消息中的返回值,显示到页面
在看实现代码前,不懂wsdl和schema的朋友们可以根据以下网址,先熟悉一下wsdl和schema文件的结构,和各个属性字段
- wsdl:http://www.w3school.com.cn/wsdl/index.asp
- schema:http://www.w3school.com.cn/schema/index.asp
代码讲解:
用于在页面显示方法和方法参数的实体bean
/**
* @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 children = new ArrayList();
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 getChildren() {
return children;
}
public void setChildren(List 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);
}
}
获取webservice发布的方法
public List getAllMethodByServiceUrl(String webserviceUrl) throws Exception {
// 结果
List list = new ArrayList();
try {
// 将url修正为合法的url,即带wsdl后缀的
webserviceUrl = getWebserviceUrl(webserviceUrl);
if (StringUtils.isNotEmpty(webserviceUrl)) {
List 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 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 operationList = new ArrayList();
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;
}
得到方法的参数
/**
* 根据方法名称和webserviceUrl得到参数
*
* @param methodName
* @param webserviceUrl
* @return
* @throws Exception
*/
public List getParamByMethodNameAndWsUrl(String methodName, String webserviceUrl) throws Exception {
try {
Document document = WsdlUtil.getDefinitionDocument(webserviceUrl);
// 返回结果
List inputParamList = new ArrayList();
// 解析参数
StringBuilder xpathBuilder = new StringBuilder();
WsdlUtil.getInputParam(inputParamList, document, methodName, xpathBuilder, null, false);
return inputParamList;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
解析输入参数的核心方法
/**
* 得到输入参数
*
* @param inputParamList
* @param document
* @param operationName
* @param xpathBuilder
* @param parentParam
* @param isSelfDefinition
* @throws Exception
*/
public static void getInputParam(List 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 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);
}
}
}
当页面输入完参数后,执行方法
/**
* 执行方法
*
* @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
List paramList = convertStrToListParam(paramStr);
List resultList = new SoapUtil().sendRequest(methodName, paramList, webserviceUrl);
result = JSONArray.fromObject(resultList).toString();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return result;
}
发送soap请求,然后获得返回的soap消息
/**
* 发送请求
*
* @param operation
* @param params
* @param wsdlUrl
* @return
* @throws Exception
*/
public List sendRequest(String operation, List 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 outPutParamList = new ArrayList();
List
将参数解析成发送的soap消息核心方法
/**
* 构建soap消息
*
* @param wsdlDocument
* @param soapDocument
* @param operationInst
* @param paramList
* @param parentNode
* @throws Exception
*/
private void buildSOAPMessage(Document wsdlDocument, Document soapDocument, Operation operationInst, List 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 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 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 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);
}
}
}
}
}
将返回的soap消息解析成页面参数核心方法
/**
* 解析返回的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> wsdlMapSoapList, List outPutParamList, ParameterInfo parent) throws Exception {
// 得到返回的参数
List outPutNodeList = WsdlUtil.getSequenceElementOfComplexType(wsdlDocument, complextTypeName);
for (int i = 0; i < outPutNodeList.size(); i++) {
Map wsdlMapSoap = new HashMap();
// 组装参数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);
}
}
- webserviceTest.rar (8.1 MB)
- 下载次数: 1246
- 大小: 63.9 KB
- 大小: 69.1 KB
- 大小: 69.1 KB
- 大小: 87.3 KB
- 大小: 71.2 KB
- 大小: 90.7 KB