在工作中,经常会遇到不同公司系统之间的远程服务调用。远程调用技术非常多,如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,而且域名有三套,三套域名对应的系统代码居然不一样,相当于做一个功能就要整三套,博主这天都被折磨瘦了几斤,故不得已亲自动手解决问题。
大家如果觉得文章不错,请为博主点一个赞,并持续关注博主定期干货分享。
来源:oschina
链接:https://my.oschina.net/u/2371923/blog/1843961