本例應用場景:要做一個webService測試功能,不局限於任何一種固定格式的webService,所以像axis,cxf等框架就不好用了。只有深入到webService的原理,通過發收soap報文,來調用服務返回結果。
發送請求:
/** * 通過httpClient發送soap報文 * @param requestSoap 請求報文 * @param serviceAddress 請求地址 * @param charSet 字符集 * @param contentType 返回的contentType * @return 響應報文 * @throws WebServiceModuleRuntimeException */ public String sendRequestSoap(String requestSoap, String serviceAddress, String charSet, String contentType) throws WebServiceModuleRuntimeException { String resultSoap = ""; PostMethod postMethod = new PostMethod(serviceAddress); byte[] b = new byte[0]; try { b = requestSoap.getBytes(charSet); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } InputStream is = new ByteArrayInputStream(b, 0, b.length); RequestEntity re = new InputStreamRequestEntity(is, b.length, contentType); postMethod.setRequestEntity(re); HttpClient httpClient = new HttpClient(); int statusCode = 0; try { statusCode = httpClient.executeMethod(postMethod); System.out.println("statusCode = " + statusCode); } catch (IOException e) { throw new WebServiceModuleRuntimeException("執行http請求失敗", e); } if (statusCode == 200) { try { resultSoap = postMethod.getResponseBodyAsString(); } catch (IOException e) { throw new WebServiceModuleRuntimeException("獲取請求返回報文失敗", e); } } else { throw new WebServiceModuleRuntimeException("請求失敗:" + statusCode); } return resultSoap; }
//調用請求方法,發送報文 String responseSoap = ""; try{ responseSoap = webServiceService.sendRequestSoap(requestSoap,struct.getWebAddress(),"utf-8","text/xml; charset=utf-8"); }catch (WebServiceModuleRuntimeException ex){ throw new ModuleException("發動請求失敗",ex); }
解析返回報文:
因沒有固定格式,所以無法通過jaxb工具來xml轉bean,更沒有客戶端代碼可以用。所以只有解析返回報文中,可以標識返回結果的值,比如成功、success、ok等。
此處考慮兩種情況:第一種狀態碼放在標簽的屬性值中,第二種狀態作為標簽的內容:
<result ResultCode="0" ResultCodeDesc="成功"> <result_code>0</result_code>
System.out.println(parseResponseSoap("result_code", "", responseSoap)); /** * 解析返回報文 * @param node 標記所在節點 * @param attr 標記所在屬性 * @param soap 報文 * @return 標記值 * @throws WebServiceModuleRuntimeException */ public static String parseResponseSoap(String node, String attr, String soap) throws WebServiceModuleRuntimeException { //然后用SOAPMessage 和 SOAPBody Document personDoc; try { personDoc = new SAXReader().read(new StringReader(soap)); Element rootElt = personDoc.getRootElement(); // 獲取根節點 Iterator body = rootElt.elementIterator("Body"); while (body.hasNext()) { Element recordEless = (Element) body.next(); return nextSubElement(node,attr,recordEless); } } catch (DocumentException e) { throw new WebServiceModuleRuntimeException("解析返回報文失敗", e); } return ""; }
/** * 遞歸方法,查找本節點是否有標記信息,如果沒有就查找下一層, * 在下一層里同樣查找本層節點,只要找到值,就層層返回。 * @param node 節點標簽名 * @param attr 節點屬性值 * @param el 當前節點對象 * @return 目標值 */ public static String nextSubElement(String node, String attr, Element el) { if (el.getName().equals(node)) { //說明 找到了目標節點 //屬性值為空說明取標簽內容 if (attr.equals("")) { Iterator sub2 = el.elementIterator(); //有子節點說明標簽內容不是單一值,需要拿到查詢結果 if (sub2.hasNext()) { while (sub2.hasNext()) { Element s2 = (Element) sub2.next(); //如果返回的不是單一的標記值,而是查詢結果,有些麻煩, //查詢結果應當是list<map>格式,但是map的key值不好確定,是標簽名作為key還是屬性值作為key //todo } } else { return el.getText(); } } else { Attribute attrbute = el.attribute(attr); return attrbute.getText(); } } else { Iterator sub2 = el.elementIterator(); while (sub2.hasNext()) { Element sub = (Element) sub2.next(); return nextSubElement(node, attr, sub); } } return ""; }
后記:本篇代碼滿足我自己的需求,但是看官的需求各異,本篇僅提供部分參考。