Webservice介面對接
因為近期處理了很多關於Webservice的介面對接,所以這篇文章是對近期自己的學習做一個簡單的總結。
一:
對於介面對接,建議首先需要了解一下WSDL檔案,以及入參的SOAP報文的閱讀,各節點的含義。有時候對接的開發直接扔給你一個wsdl服務檔案,或者一串soap報文讓你呼叫,這種情況下,如果不瞭解如何閱讀該檔案包括相關節點的含義,就會很尷尬;其次,需要問清楚介面提供方,對方的介面有沒有訪問認證等,如果沒有,可以採用自動生成客戶端的形式處理,這種方式不再贅述,網上有一大堆的資料。我這裡介紹一下我遇到的需要介面認證的方式,廢話少說直接看程式碼:
//直接AXIS呼叫
public class WebserviceUtil { public static String getResult(ServiceInfoDto serviceInfoDto, String jsoninfo) throws ServiceException, MalformedURLException, RemoteException, SOAPException { //呼叫介面//標識Web Service的具體路徑 String endpoint = serviceInfoDto.getEndpoint(); String namespace = serviceInfoDto.getNamespace(); String soapaction = serviceInfoDto.getSoapaction(); String username = new String("***"); String password = new String("***"); String HU_SENDR = new String("***"); String HU_JSON = jsoninfo; String result = ""; try { // 建立 Service例項 Service service = new Service(); QName qname = new QName(namespace, serviceInfoDto.getLocalPart()); // 通過Service例項建立Call的例項 Call call = (Call) service.createCall(); //為Call設定服務的位置 call.setTargetEndpointAddress(endpoint); call.setOperationName(qname); call.setEncodingStyle("UTF-8"); call.setSOAPActionURI(soapaction); call.setUsername(username); call.setPassword(password); call.addParameter(new QName("HU_JSON"), org.apache.axis.encoding.XMLType.XSD_STRING, javax.xml.rpc.ParameterMode.IN); call.addParameter(new QName("HU_SENDR"), org.apache.axis.encoding.XMLType.XSD_STRING, javax.xml.rpc.ParameterMode.IN); call.setReturnType(XMLType.XSD_STRING); // 返回值型別:String Object[] obj = {HU_JSON, HU_SENDR}; result = (String) call.invoke(obj);// 遠端呼叫 // System.out.println("result is " + result); } catch (Exception e) { e.printStackTrace(); } return result; } }
public class ServiceInfoDto { private String endpoint; private String namespace; private String soapaction; private String localPart; public String getEndpoint() { return endpoint; } public void setEndpoint(String endpoint) { this.endpoint = endpoint; } public String getNamespace() { return namespace; } public void setNamespace(String namespace) { this.namespace = namespace; } public String getSoapaction() { return soapaction; } public void setSoapaction(String soapaction) { this.soapaction = soapaction; } public String getLocalPart() { return localPart; } public void setLocalPart(String localPart) { this.localPart = localPart; } }
解讀一下入參和幾個重要的引數: ServiceInfoDto物件:是對相關節點入參的彙總,這裡的endpoint,namespace,soapaction,localPart在對方提供的wsdl檔案中都可查到; jsoninfo:介面方要求的入參物件(轉成json字串形式入參) String username = new String("***"); 介面方提供的認證登入名(不需要可忽略) String password = new String("***"); 介面方提供的認證登入密碼(不需要可忽略) String HU_SENDR = new String("***"); HU_SENDR需要按對方要求的欄位名稱處理,入參值介面方提供(不需要可忽略); String HU_JSON = jsoninfo;HU_JSON;需要按對方要求的欄位名稱處理,入參值是前面處理過的json物件;
二:
第二種對接是拼接SOAP報文入參,並且解析返回的SOAP報文,獲取返回資訊;
這種方式必須要清楚的知道對方入參的soap報文格式,相關節點一定要清晰,拿到對方的報文資訊進行拼接即可:
soap報文拼接,由於我用到的地方比較多,所以提取的程式碼塊處理
public class SoapAppendXml { public static StringBuffer soapXml(String arg2,String arg4,String method,String id) { StringBuffer sendSoapString = new StringBuffer(); sendSoapString.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:web=\"http://webservice.**.com/\">"); sendSoapString.append(" <soapenv:Header/>"); sendSoapString.append(" <soapenv:Body>"); sendSoapString.append(" <web:"+method+">"); sendSoapString.append(" <arg0>*</arg0>"); sendSoapString.append(" <arg1>false</arg1>"); sendSoapString.append(" <arg2>"+arg2+"</arg2>"); sendSoapString.append(" <arg3>[]</arg3>"); sendSoapString.append(" <arg4>"+arg4+"</arg4>"); sendSoapString.append(" </web:"+method+">"); sendSoapString.append(" </soapenv:Body>"); sendSoapString.append("</soapenv:Envelope>"); return sendSoapString; } }
入參可根據實際介面的需要進行修改,各節點可檢視介面的soap入參要求,動態處理或者寫死都行;
由於我的呼叫服務只有一個,並且有多個方法,所以入參method需要動態處理;
下面是介面呼叫:
public class SoapUtil { public static String getWebServiceAndSoap(String url,String isClass,String isMethod,StringBuffer sendSoapString) throws IOException { String result = ""; String soap = sendSoapString.toString(); if (soap == null) { return null; } URL soapUrl = new URL(url); URLConnection conn = soapUrl.openConnection(); conn.setUseCaches(false); conn.setDoInput(true); conn.setDoOutput(true); conn.setRequestProperty("Content-Length", Integer.toString(soap.length())); conn.setRequestProperty("Content-Type", "text/xml; charset=utf-8"); // 呼叫的介面方法是 conn.setRequestProperty(isClass,isMethod); OutputStream os = conn.getOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(os, "utf-8"); osw.write(soap); osw.flush(); osw.close(); // 獲取webserivce返回的流 InputStream is = conn.getInputStream(); if (is!=null) { byte[] bytes = new byte[0]; bytes = new byte[is.available()]; is.read(bytes); String str = new String(bytes); return str; }else { return null; } }
}
解讀一下上面的工具類:
url:是對接服務地址,以"?wsdl"結尾的地址;
isClass:介面類名,在對方提供的wsdl檔案中可以查到,我這裡的是"LvYunkangWebservice";
isMethod:呼叫方法名
sendSoapString:拼接好的soap報文
該工具類在實際測試中,發現最終返回的報文,會出現亂碼現象,查閱得知,應該是跟InputStream按位元組解析有關。所以,對上述工具類進行簡單的修改,也就是對返回結果部分做一下修改(標紅的部分)
public class SoapUtil {
public static String getWebServiceAndSoap(String url,String isClass,String isMethod,StringBuffer sendSoapString) throws IOException {
String result = "";
String soap = sendSoapString.toString();
if (soap == null) {
return null;
}
URL soapUrl = new URL(url);
URLConnection conn = soapUrl.openConnection();
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Length",
Integer.toString(soap.length()));
conn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
// 呼叫的介面方法是
conn.setRequestProperty(isClass,isMethod);
OutputStream os = conn.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os, "utf-8");
osw.write(soap);
osw.flush();
osw.close();
// 獲取webserivce返回的流
InputStream is = conn.getInputStream();
if (is != null) {
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
BufferedReader br = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String temp = null;
while(null != (temp = br.readLine())) {
sb.append(temp);
}
result = sb.toString();
is.close();
isr.close();
br.close();
}
return result;
}
}
解析返回的報文:
這裡先給大家看一下,我的拿到的報文返回示例:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <ns2:getResultResponse xmlns:ns2="http://webservice.taikang.com/"> <return> <message>訪問成功</message> <result>true</result>
</return>
</ns2:getResultResponse >
</soap:Body>
</soap:Envelope>
按節點分級解析的方式,返回Map即可
public static Map<String,String> XMLtoData(String xml) throws DocumentException { Map map = new HashMap(); List<Data> dataList = new ArrayList<>(); Document doc = DocumentHelper.parseText(xml); //獲取根元素,準備遞迴解析這個XML樹 Element root = doc.getRootElement(); //獲取到data的集合 List<Element> mzList = root.element("Body").element("getResultResponse").elements("return"); //遍歷data集合 for (Element e : mzList) { List<Element> elements = e.elements(); //遍歷將元素中的key和value存到map中 for (Element item : elements) { if (!StringUtils.isEmpty(item.getText())) { map.put(item.getName(), item.getText()); } } } return map; }
注意:
List<Element> mzList = root.element("Body").element("getResultResponse").elements("return");
節點可以按需求獲取,即:root.element("**").element("**")................elements("**")
上述是兩種工具類呼叫Webservice介面的方式,請多指教!