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

附件中附带页面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文件的结构,和各个属性字段


代码讲解:
用于在页面显示方法和方法参数的实体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<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);
	}
}


获取webservice发布的方法

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;
	}



得到方法的参数

	/**
	 * 根据方法名称和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);
		}
	}


解析输入参数的核心方法


/**
	 * 得到输入参数
	 * 
	 * @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);
			}
		}
	}


当页面输入完参数后,执行方法

/**
	 * 执行方法
	 * 
	 * @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;
	}


发送soap请求,然后获得返回的soap消息

/**
	 * 发送请求
	 * 
	 * @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;
	}


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

/**
	 * 构建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);
					}
				}
			}

		}
	}


将返回的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<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);
		}
	}

  • 大小: 63.9 KB
  • 大小: 69.1 KB
  • 大小: 69.1 KB
  • 大小: 87.3 KB
  • 大小: 71.2 KB
  • 大小: 90.7 KB
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值