關於Webservice介面對接相關總結

寒水易兮蕭蕭風發表於2021-01-10

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介面的方式,請多指教!
 

 

相關文章