webservice技術之巔峯對決(httpclient遠程調用通用技術詳解)

    在工做中,常常會遇到不一樣公司系統之間的遠程服務調用。遠程調用技術很是多,如rmi、netty、mina、hessian、dubbo、Motan、springcloud、webservice等等。雖然在互聯網的今天,可能大多數公司使用的都是些高大上的分佈式rpc調用技術,在多數程序員眼裏都以爲webservice技術很是的low,但博主不得不說它是公司與公司之間進行系統對接的最佳推薦技術。java

推薦緣由:程序員

    1.webservice技術是創建在http+xml基礎之上的,很是的輕量級。web

    2.webservice技術可經過wsdl來定義調用關係,雙方系統可根據wsdl快速的進行開發對接。spring

    3.webservice是一種標準,有各類語言對它的實現,支持異構系統之間的對接。apache

    4.必要狀況下,還可使用httpclient做爲客戶端進行調用,以下降依賴。服務器

1、webservice原理:app

客戶端——> 閱讀WSDL文檔 (根據文檔生成SOAP請求) ——>經過http調用發送到Web服務器——>交給WebService請求處理器 (ISAPI Extension)——>處理SOAP請求——> 調用WebService接口——>生成SOAP應答 ——> Web服務器經過http的方式返回客戶端dom

2、webservice通用調用技術httpclient(JAVA版)socket

工具類:分佈式

package com.empire.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.xml.internal.messaging.saaj.util.Base64;

/**
 * 類HttpClientCallSoapUtils.java的實現描述:http調用webservice工具類
 * 
 * @author arron 2018年x月xx日 下午x0:0x:33
 */
public class HttpClientCallSoapUtils {
    private static final Logger logger         = LoggerFactory.getLogger(HttpClientCallSoapUtils.class);
    /**
     * 請求超時時間30秒
     */
    private static final int    socketTimeout  = 30000;
    /**
     * 傳輸超時時間30秒
     */
    private static final int    connectTimeout = 30000;

    /**
     * 使用SOAP1.1發送消息
     * 
     * @param url 爲訪問的wsdl地址(登錄後wsdl文件中的soap:address)
     * @param soapXml
     * @param soapAction
     * @param userpass 認證用戶密碼格式:username:password(如:admin:123456)
     * @return
     */
    public static String doPostSoap1_1(String url, String soapXml, String soapAction, String userpass) {
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        CloseableHttpClient closeableHttpClient = httpClientBuilder.build();
        HttpPost httpPost = new HttpPost(url);
        //設置請求和傳輸超時時間
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout)
                .setConnectTimeout(connectTimeout).build();
        httpPost.setConfig(requestConfig);
        String result = null;
        CloseableHttpResponse response = null;
        try {
            httpPost.setHeader("Content-Type", "text/xml;charset=UTF-8");
            httpPost.setHeader("SOAPAction", soapAction);
            //httpPost.setHeader("Authorization", "Basic UzAwMTkyNTM4MDU6UDhaPFNdM0c=");
            if (StringUtils.isNotBlank(userpass)) {
                httpPost.addHeader(new BasicHeader("Authorization", "Basic " + new 
String(Base64.encode(userpass.getBytes()))));
                logger.info("加密後內容:{}", new BasicHeader("Authorization", "Basic " + new String(Base64.encode(userpass.getBytes()))));
            }
            StringEntity data = new StringEntity(soapXml, Charset.forName("UTF-8"));
            httpPost.setEntity(data);
            response = closeableHttpClient.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();
            if (httpEntity != null) {
                result = EntityUtils.toString(httpEntity, "UTF-8");
                // 打印響應內容
                logger.info("response:{}", result);
            }
        } catch (Exception e) {
            logger.error("exception in doPostSoap1_1", e);
        } finally {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    /**
     * 使用SOAP1.2發送消息
     * 
     * @param url 爲訪問的wsdl地址(登錄後wsdl文件中的soap:address)
     * @param soapXml
     * @param soapAction
     * @param userpass 認證用戶密碼格式:username:password(如:admin:123456)
     * @return
     */
    public static String doPostSoap1_2(String url, String soapXml, String soapAction, String userpass) {
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        CloseableHttpClient closeableHttpClient = httpClientBuilder.build();
        HttpPost httpPost = new HttpPost(url);
        // 設置請求和傳輸超時時間
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout)
                .setConnectTimeout(connectTimeout).build();
        httpPost.setConfig(requestConfig);
        String result = null;
        CloseableHttpResponse response = null;
        try {
            httpPost.setHeader("Content-Type", "application/soap+xml;charset=UTF-8");
            httpPost.setHeader("SOAPAction", soapAction);
            //httpPost.setHeader("Authorization", "Basic UzAwMTkyNTM4MDU6UDhaPFNdM0c=");
            if (StringUtils.isNotBlank(userpass)) {
                httpPost.addHeader(new BasicHeader("Authorization", "Basic " + new String(Base64.encode(userpass.getBytes()))));
                logger.info("加密後內容:{}", new BasicHeader("Authorization", "Basic " + new String(Base64.encode(userpass.getBytes()))));
            }
            StringEntity data = new StringEntity(soapXml, Charset.forName("UTF-8"));
            httpPost.setEntity(data);
            response = closeableHttpClient.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();
            if (httpEntity != null) {
                // 打印響應內容
                result = EntityUtils.toString(httpEntity, "UTF-8");
                logger.info("response:{}", result);
            }
        } catch (Exception e) {
            logger.error("exception in doPostSoap1_2", e);
        } finally {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    /**
     * 把soap字符串格式化爲SOAPMessage
     * 
     * @param soapString
     * @return
     */
    public static SOAPMessage formartSoapString(String soapString) {
        MessageFactory msgFactory;
        try {
            msgFactory = MessageFactory.newInstance();
            SOAPMessage reqMsg = msgFactory.createMessage(new MimeHeaders(),
                    new ByteArrayInputStream(soapString.getBytes(Charset.forName("UTF-8"))));
            reqMsg.saveChanges();
            return reqMsg;
        } catch (Exception e) {
            logger.error("formartSoapString()", e);
            return null;
        }
    }

    /**
     * @param envPrefix env的前綴,通常設置爲"soapenv"
     * @param isRemoveOldEnvPrefix 是否清楚默認前綴
     * @param nameSpaceMap env中全部聲明的命名空間
     * @param method 調用的webservice方法
     * @param rootParm 傳輸的數據
     * @param soapAction soupui上能夠看到xml上的soapAction
     * @return
     * @throws SOAPException
     */
    public static SOAPMessage buildSoapMessage(String envPrefix, boolean isRemoveOldEnvPrefix,
                                               Map<String, String> nameSpaceMap, SoapElementNode method,
                                               SoapElementNode rootParm, String soapAction) throws SOAPException {
        MessageFactory messageFactory = MessageFactory.newInstance();
        SOAPMessage message = messageFactory.createMessage();
        message.getMimeHeaders().setHeader("SOAPAction", soapAction);
        // 建立soap消息主體==========================================
        SOAPPart soapPart = message.getSOAPPart();// 建立soap部分
        SOAPEnvelope envelope = soapPart.getEnvelope();
        envelope.setPrefix(envPrefix);
        //envelope.setPrefix("soapenv");
        if (isRemoveOldEnvPrefix) {
            envelope.removeNamespaceDeclaration("SOAP-ENV");
        }
        for (Entry<String, String> entry : nameSpaceMap.entrySet()) {
            envelope.addNamespaceDeclaration(entry.getKey(), entry.getValue());
        }
        envelope.getHeader().setPrefix(envPrefix);
        if (isRemoveOldEnvPrefix) {
            envelope.getHeader().removeNamespaceDeclaration("SOAP-ENV");
        }
        SOAPBody body = envelope.getBody();
        //body.setPrefix("soapenv");
        body.setPrefix(envPrefix);
        //  根據要傳給mule的參數,建立消息body內容。具體參數的配置能夠參照應用集成接口技術規範1.1/1.2版本
        SOAPElement bodyElement = null;
        if (StringUtils.isNotBlank(method.getPrefix()) && StringUtils.isNotBlank(method.getNamespace())) {
            bodyElement = body.addChildElement(method.getLocalpart(), method.getPrefix(), method.getNamespace());
        }
        if (StringUtils.isNotBlank(method.getPrefix()) && StringUtils.isBlank(method.getNamespace())) {
            bodyElement = body.addChildElement(method.getLocalpart(), method.getPrefix());
        }
        if (StringUtils.isBlank(method.getPrefix()) && StringUtils.isBlank(method.getNamespace())) {
            bodyElement = body.addChildElement(method.getLocalpart());
        }
        buidParamSOAP(bodyElement, rootParm);
        // Save the message
        message.saveChanges();
        return message;
    }

    private static void buidParamSOAP(SOAPElement soapElement, SoapElementNode rootParm) throws SOAPException {
        if (StringUtils.isNotBlank(rootParm.getLocalpart())) {
            SOAPElement curr = null;
            if (StringUtils.isNotBlank(rootParm.getPrefix()) && StringUtils.isNotBlank(rootParm.getNamespace())) {
                curr = soapElement.addChildElement(rootParm.getLocalpart(), rootParm.getPrefix(),
                        rootParm.getNamespace());
            }
            if (StringUtils.isNotBlank(rootParm.getPrefix()) && StringUtils.isBlank(rootParm.getNamespace())) {
                curr = soapElement.addChildElement(rootParm.getLocalpart(), rootParm.getPrefix());
            }
            if (StringUtils.isBlank(rootParm.getPrefix()) && StringUtils.isBlank(rootParm.getNamespace())) {
                curr = soapElement.addChildElement(rootParm.getLocalpart());
            }

            if (StringUtils.isNotBlank(rootParm.getValue()) && curr != null) {
                curr.addTextNode(rootParm.getValue());
            }
            soapElement = curr;
        }
        List<SoapElementNode> currChildNodeLists = rootParm.getChildNodeLists();
        if (currChildNodeLists != null && currChildNodeLists.size() > 0) {
            for (int i = 0, j = currChildNodeLists.size(); i < j; i++) {
                buidParamSOAP(soapElement, currChildNodeLists.get(i));
            }
        }
    }

   
    public static void main(String[] args) {
        String soapAction = "";
        String postuirl = "http://localhost/empire_wccmass/empire/c4cws";
        SoapElementNode root = new SoapElementNode();
        root.setLocalpart("appointmentC4CInfo");
        List<SoapElementNode> rootChildList = new ArrayList<SoapElementNode>();
        rootChildList.add(new SoapElementNode("appointDate", "2018-01-13"));
        rootChildList.add(new SoapElementNode("appointTime", "1"));
        rootChildList.add(new SoapElementNode("c4cAptId", "20170801"));
        rootChildList.add(new SoapElementNode("dealerNo", "12178"));
        rootChildList.add(new SoapElementNode("getinType", "1"));
        rootChildList.add(new SoapElementNode("miles", "1234"));
        rootChildList.add(new SoapElementNode("status", "1"));
        rootChildList.add(new SoapElementNode("vinCode", "LVVDC11B9EC090288"));
        rootChildList.add(new SoapElementNode("wccMemberId", "10"));
        root.setChildNodeLists(rootChildList);
        Map<String, String> nameSpaceMap = new HashMap<>();
        nameSpaceMap.put("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
        nameSpaceMap.put("dao", "http://dao.interfaces.empire.com/");
        SoapElementNode method = new SoapElementNode();
        method.setLocalpart("syncAppointmentC4C");
        method.setPrefix("dao");
        try {
            SOAPMessage x = buildSoapMessage("soapenv", true, nameSpaceMap, method, root, "");
            TransformerFactory tff = TransformerFactory.newInstance();
            Transformer tf = tff.newTransformer();
            // Get reply content
            Source source = x.getSOAPPart().getContent();
            ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
            StreamResult result = new StreamResult(bos);
            tf.transform(source, result);
            String rqXml = new String(bos.toByteArray());
            logger.info("請求webservice的soap消息:{}", rqXml);
            //將構建的soap的xml打印出來 便於調試
            System.out.println("請求webservice的soap消息:"+ rqXml);
            String respXml = doPostSoap1_2(postuirl, rqXml, soapAction, null);
            logger.info("webservice返回的soap消息:{}", respXml);
            System.out.println("webservice返回的soap消息:"+respXml);
            SOAPMessage a = formartSoapString(respXml);
            org.w3c.dom.Document ax = a.getSOAPBody().extractContentAsDocument();
            String clubAptId = ax.getElementsByTagName("clubAptId").item(0).getTextContent();
            String success = ax.getElementsByTagName("success").item(0).getTextContent();
            logger.info("webservice返回的soap消息中是否成功:{},預定單Id:{}", success, clubAptId);
            System.out.println("webservice返回的soap消息中是否成功:"+success+",預定單Id:"+clubAptId);
        } catch (Exception e) {
            logger.error("", e);
        }
    }
}

本身封裝的soap節點轉換類

package com.empire.util;

import java.io.Serializable;
import java.util.List;
/**
 * 
 * 類SoapElementNode.java的實現描述:soap節點轉換類
 * @author arron 2018年x月xx日 下午x0:0x:33
 */
public class SoapElementNode implements   Serializable{
    /**
     * 節點前綴
     */
    private String prefix="";
    /**
     * 節點名
     */
    private String localpart="";
    /**
     * 節點值
     */
    private String value="";
    /**
     * 節點命名空間
     */
    private String namespace="";
    private List<SoapElementNode> childNodeLists=null;
    public SoapElementNode(){}
    public SoapElementNode( String localpart) {
        super();
        this.localpart = localpart;
    }
    public SoapElementNode( String localpart,String value) {
        super();
        this.localpart = localpart;
        this.value=value;
    }
    public SoapElementNode(String prefix, String localpart,String value, String namespace) {
        super();
        this.prefix = prefix;
        this.localpart = localpart;
        this.value=value;
        this.namespace = namespace;
    }
    public String getPrefix() {
        return prefix;
    }
    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }
    public String getLocalpart() {
        return localpart;
    }
    public void setLocalpart(String localpart) {
        this.localpart = localpart;
    }
    
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
    public String getNamespace() {
        return namespace;
    }
    public void setNamespace(String namespace) {
        this.namespace = namespace;
    }
    
    public List<SoapElementNode> getChildNodeLists() {
        return childNodeLists;
    }
    public void setChildNodeLists(List<SoapElementNode> childNodeLists) {
        this.childNodeLists = childNodeLists;
    }
}

 

調用結果:

 

    最後,博主今天的分享就到這裏,爲何博主要直接使用httpclient呢,由於客戶一個功能整一個wsdl,並且域名有三套,三套域名對應的系統代碼竟然不同,至關於作一個功能就要整三套,博主這天都被折磨瘦了幾斤,故不得已親自動手解決問題。

    你們若是以爲文章不錯,請爲博主點一個贊,並持續關注博主按期乾貨分享。

相關文章
相關標籤/搜索