附件中附带页面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对象以及这些类型的相互嵌套。工具截图如下
下面说说工具的实现思路:
在看实现代码前,不懂wsdl和schema的朋友们可以根据以下网址,先熟悉一下wsdl和schema文件的结构,和各个属性字段
代码讲解:
用于在页面显示方法和方法参数的实体bean
获取webservice发布的方法
得到方法的参数
解析输入参数的核心方法
当页面输入完参数后,执行方法
发送soap请求,然后获得返回的soap消息
将参数解析成发送的soap消息核心方法
将返回的soap消息解析成页面参数核心方法
近段时间,需要为公司的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,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,operationName,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,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,true); } } else { param.setType(name); // 遍历其子结点xs:element getInputParam(inputParamList,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,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,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,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,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,param); } } else { // 组装子结点 if (param.getChildren().size() > 0) { buildSOAPMessage(wsdlDocument,parentNode,param); } } } } }
将返回的soap消息解析成页面参数核心方法
/** * 解析返回的soap消息,然后将结果填充到outPutParamList中 * * @param wsdlDocument * @param soapDocument * @param operationResponseName * @param complextTypeName * @param wsdlMapSoapList * @param outPutParamList * @throws Exception */ public void getoutPutParam(Document wsdlDocument,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,operationResponseName); param.setValue(value); currentParam.addChild(param); } } else {// 不是数组 currentParam.setType(type); // 根据映射关系,从返回的soap消息中取值 wsdlMapSoap.put("name",new Integer(-1)); wsdlMapSoapList.add(wsdlMapSoap); String value = getValueFromresponseSoap(soapDocument,operationResponseName); currentParam.setValue(value); } } else {// 该参数为复杂类型 if (DOMUtil.isArray(outPutNode)) {// 数组 currentParam.setType(WsdlUtil.SchemaDefaulyType.type_array.getType()); currentParam.setChildType(type); // 组装映射关系 wsdlMapSoap.put("name",wsdlMapSoapList); // 从soap消息中取出值 for (int j = 1; j <= arrayLength; j++) { ParameterInfo param = new ParameterInfo(); param.setType(type); wsdlMapSoap.put("index",new Integer(j)); // 继续查找 getoutPutParam(wsdlDocument,type,param); currentParam.addChild(param); } } else {// 不是数组 currentParam.setType(type); // 根据映射关系,从返回的soap消息中取值 wsdlMapSoap.put("name",new Integer(-1)); wsdlMapSoapList.add(wsdlMapSoap); // 继续查找 getoutPutParam(wsdlDocument,currentParam); } } // 增加参数 if (parent == null) { outPutParamList.add(currentParam); } else { parent.addChild(currentParam); } // 在映射关系中除去当前的结点 wsdlMapSoapList.remove(wsdlMapSoapList.size() - 1); } }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。