Webservice的wsdl檔案解析與Soap訊息的發送、接收(不產生java用戶端代碼)

來源:互聯網
上載者:User
附件中附帶頁面jsp、js,還有dwr的action,service以及util,我的環境是spring、dwr、ext、jquery。由於整個工具牽扯的比較多,所以沒有將完整的可啟動並執行代碼整理出來,只將所有核心的代碼貼了出來,如果需要運行還需要解決些小問題

近段時間,需要為公司的QA測試人員提供一個Webservice的測試載入器,具體要求為:測試人員提供webservice的url,測試載入器根據url得到webservice發布的方法及方法的參數,然後測試人員在頁面輸入參數,並點擊運行,工具運行後,在頁面上顯示返回的結果。其實測試人員可以用現成在測試架構soapui來測試webservice,不過測試人員仍覺得麻煩,Team Leader還要求工具不能用wsdl2java產生webservice的用戶端代碼。我想可能是不想在項目中存放過多的無用的臨時檔案吧。

測試載入器支援參數和傳回值的類型有:數組、List、java基礎資料型別 (Elementary Data Type)、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<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");// 返回的結果集listList<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 {// 得到complexTypeNameString 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:elementgetInputParam(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:Faultif (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、valueParameterInfo 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>();// 組裝參數paramNode 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 查看圖片附件
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.