webservice技术之巅峰对决(httpclient远程调用通用技术详解)

原创
2018/07/11 00:32
阅读数 1.7W

    在工作中,经常会遇到不同公司系统之间的远程服务调用。远程调用技术非常多,如rmi、netty、mina、hessian、dubbo、Motan、springcloud、webservice等等。虽然在互联网的今天,可能大多数公司使用的都是些高大上的分布式rpc调用技术,在多数程序员眼里都觉得webservice技术非常的low,但博主不得不说它是公司与公司之间进行系统对接的最佳推荐技术。

推荐原因:

    1.webservice技术是建立在http+xml基础之上的,非常的轻量级。

    2.webservice技术可通过wsdl来定义调用关系,双方系统可根据wsdl快速的进行开发对接。

    3.webservice是一种标准,有各种语言对它的实现,支持异构系统之间的对接。

    4.必要情况下,还可以使用httpclient作为客户端进行调用,以降低依赖。

一、webservice原理:

客户端——> 阅读WSDL文档 (根据文档生成SOAP请求) ——>通过http调用发送到Web服务器——>交给WebService请求处理器 (ISAPI Extension)——>处理SOAP请求——> 调用WebService接口——>生成SOAP应答 ——> Web服务器通过http的方式返回客户端

二、webservice通用调用技术httpclient(JAVA版)

工具类:

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,而且域名有三套,三套域名对应的系统代码居然不一样,相当于做一个功能就要整三套,博主这天都被折磨瘦了几斤,故不得已亲自动手解决问题。

    大家如果觉得文章不错,请为博主点一个赞,并持续关注博主定期干货分享。

展开阅读全文
打赏
6
13 收藏
分享
加载中
更多评论
打赏
0 评论
13 收藏
6
分享
返回顶部
顶部