一个自定义实现的soap接口客户端调用工具,已在实际项目中使用过,且经过了生产环境检验。
使用方法:
(1)先用jdk自带的wsdl工具导出接口java源码:wsimport -s . xxx.wsdl,且将接口源码导入到项目中。
(2)比如要调用一个Hello接口,soap的头部定义类为HelloHead,soap请求主体定义类为HelloReq,soap响应主体类为HelloResp,则调用hello接口为:
//request对象初始化
SoapEntity<HelloHead,HelloReq> request = SoapEntity.createInstance(HelloHead.class,HelloReq.class);
//request head
HelloHead helloHead = new HelloHead();
//... helloHead对象初始化赋值, helloHead一般是接口权限设置,比如appid和appkey(账号密码)
request.setHead(helloHead);
//request body
HelloReq reqBody = new HelloReq();
//...reqBody对象初始化赋值,reqBody一般是接口具体的业务请求参数
request.setBody(reqBody);
//简单的创建一个response对象,注意这里是 HelloResp.class
SoapEntity<HelloHead,HelloResp> response = SoapEntity.createInstance(HelloHead.class,HelloResp.class);
//请求接口并自动封装响应结果
String wsdlUrl="http://...";//wsdl接口地址
SoapClient.execute(wsdlUrl,request,response);
//这里response已经封装了接口的响应结果,现在取出具体的响应对象helloResp
HelloResp helloResp = response.getBody();
//helloResp的各种取值处理,或者直接返回这个对象
//...
SoapEntity.class
package org.sky.iboot.common.util.soap;
import java.lang.annotation.Annotation;
import java.util.List;
import javax.xml.bind.annotation.XmlNsForm;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
/**
* soap 实体类
*
* @author gaofu
*
* @param <HeadClass>
* @param <BodyClass>
*/
public class SoapEntity<HeadClass, BodyClass> {
private static Logger logger = LoggerFactory.getLogger(SoapEntity.class);
/** soap头部类 */
private Class<HeadClass> headClass;
/** soap头部bean */
private HeadClass head;
/** soap主体类 */
private Class<BodyClass> bodyClass;
/** soap主体bean */
private BodyClass body;
/** soap错误消息 */
private SoapFault fault;
/** bean to xml 头部xml子元素是否添加命名空间 */
private boolean headEleNs = false;
/**
* 构造方法
*
* @param headClass
* @param bodyClass
*/
public SoapEntity(Class<HeadClass> headClass, Class<BodyClass> bodyClass) {
this.headClass = headClass;
this.bodyClass = bodyClass;
}
/**
* 创建新实例
*
* @param headClass
* @param bodyClass
* @return
*/
public static <Head, Body> SoapEntity<Head, Body> createInstance(Class<Head> headClass, Class<Body> bodyClass) {
return new SoapEntity<Head, Body>(headClass, bodyClass);
}
/**
* 通过 soap Xml 初始化
*
* @param soapXml
* @throws Exception
*/
public void init(String soapXml) throws Exception {
Document document = DocumentHelper.parseText(soapXml);
Element root = document.getRootElement();
//
Element headEle = root.element("Header");
if (headEle != null) {
this.head = XmlUtil.xmlToBean(headEle.asXML(), headClass);
}
//
Element body = root.element("Body");
List<Element> elements = (List<Element>) body.elements();
for (Element bodyChild : elements) {
if (bodyChild != null) {
if ("Fault".equals(bodyChild.getName())) {
this.fault = XmlUtil.xmlToBean(bodyChild.asXML(), SoapFault.class);
} else {
this.body = XmlUtil.xmlToBean(bodyChild.asXML(), bodyClass);
}
}
}
}
/**
* 获得 soap xml
*
* @return
* @throws Exception
*/
public String soapXml() throws Exception {
javax.xml.bind.annotation.XmlSchema xmlSchema = packageInfo();
if (xmlSchema == null) {
StringBuffer error = new StringBuffer();
error.append(bodyClass.getPackage().getName());
error.append(".package-info.class not found! ");
logger.error(error.toString());
throw new Exception(error.toString());
}
String nameSpaceUrl = xmlSchema.namespace();
Namespace soapNs = new Namespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
Namespace tns = new Namespace("tns", nameSpaceUrl);
//
Element root = DocumentHelper.createElement("Envelope");
root.setQName(new QName("Envelope", soapNs));
root.add(tns);
//
if (this.head != null) {
javax.xml.namespace.QName qname = new javax.xml.namespace.QName("Header");
String headerXml = XmlUtil.beanToXml(qname, this.head);
Document headerDoc = DocumentHelper.parseText(headerXml);
Element headeRoot = headerDoc.getRootElement();
headeRoot.setQName(new QName("Header", soapNs));
//
if (headEleNs && XmlNsForm.QUALIFIED.equals(xmlSchema.elementFormDefault())) {
List<Element> elements = (List<Element>) headeRoot.elements();
for (Element ele : elements) {
ele.setQName(new QName(ele.getName(), tns));
}
}
//
root.add(headeRoot);
}
//
Element bodyEle = DocumentHelper.createElement("Body");
bodyEle.setQName(new QName("Body", soapNs));
if (this.body != null) {
String operateName = xmlNodeName(bodyClass);
javax.xml.namespace.QName qname = new javax.xml.namespace.QName(operateName);
String bodyXml = XmlUtil.beanToXml(qname, this.body);
Document bodyDoc = DocumentHelper.parseText(bodyXml);
Element bodyRoot = bodyDoc.getRootElement();
bodyRoot.setQName(new QName(operateName, tns));
bodyEle.add(bodyRoot);
}
if (this.fault != null) {
javax.xml.namespace.QName qname = new javax.xml.namespace.QName("Fault");
String faultXml = XmlUtil.beanToXml(qname, this.fault);
Document faultDoc = DocumentHelper.parseText(faultXml);
Element faultRoot = faultDoc.getRootElement();
faultRoot.setQName(new QName("Fault", soapNs));
bodyEle.add(faultRoot);
}
root.add(bodyEle);
Document doucment = DocumentHelper.createDocument(root);
return doucment.asXML().replaceAll("[\\t\\n\\r]", "");
}
/**
* 读取 package-info 信息
*/
private javax.xml.bind.annotation.XmlSchema packageInfo() {
javax.xml.bind.annotation.XmlSchema xmlSchema = null;
Package pkg = bodyClass.getPackage();
for (Annotation annotation : pkg.getAnnotations()) {
if (annotation instanceof javax.xml.bind.annotation.XmlSchema) {
xmlSchema = (javax.xml.bind.annotation.XmlSchema) annotation;
break;
}
}
return xmlSchema;
}
/**
* 获取xml节点的名称
*
* @param clazz
* @return
*/
private String xmlNodeName(Class<?> clazz) {
String xmlNodeName = null;
for (Annotation annotation : clazz.getAnnotations()) {
if (annotation instanceof javax.xml.bind.annotation.XmlRootElement) {
javax.xml.bind.annotation.XmlRootElement xmlRoot = (javax.xml.bind.annotation.XmlRootElement) annotation;
if (!StringUtils.isEmpty(xmlRoot.name()) && !xmlRoot.name().contains("#")) {
xmlNodeName = xmlRoot.name();
break;
}
}
if (annotation instanceof javax.xml.bind.annotation.XmlType) {
javax.xml.bind.annotation.XmlType xmlType = (javax.xml.bind.annotation.XmlType) annotation;
if (!StringUtils.isEmpty(xmlType.name()) && !xmlType.name().contains("#")) {
xmlNodeName = xmlType.name();
break;
}
}
}
return xmlNodeName;
}
public Class<HeadClass> getHeadClass() {
return headClass;
}
public void setHeadClass(Class<HeadClass> headClass) {
this.headClass = headClass;
}
public HeadClass getHead() {
return head;
}
public void setHead(HeadClass head) {
this.head = head;
}
public Class<BodyClass> getBodyClass() {
return bodyClass;
}
public void setBodyClass(Class<BodyClass> bodyClass) {
this.bodyClass = bodyClass;
}
public BodyClass getBody() {
return body;
}
public void setBody(BodyClass body) {
this.body = body;
}
public SoapFault getFault() {
return fault;
}
public void setFault(SoapFault fault) {
this.fault = fault;
}
public boolean isHeadEleNs() {
return headEleNs;
}
public void setHeadEleNs(boolean headEleNs) {
this.headEleNs = headEleNs;
}
}
package org.sky.iboot.common.util.soap;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* soap 客户端
*
* @author gaofu
*
*/
public class SoapClient {
private static Logger logger = LoggerFactory.getLogger(SoapClient.class);
/**
* 发送soap请求, 并封装响应内容
*
* @param wsdlUrl 请求Webservice地址(?wsdl)
* @param request 请求内容
* @param response 响应内容
* @throws Exception
*/
public static <QH, QB, PH, PB> void execute(String wsdlUrl, SoapEntity<QH, QB> request, SoapEntity<PH, PB> response)
throws Exception {
logger.info("发送地址: " + wsdlUrl);
String xml = request.soapXml();
logger.info("发送内容: " + xml);
String responseXml = httpPostXml(wsdlUrl, xml);
responseXml = responseXml.replaceAll("[\\t\\n\\r]", "");
logger.info("接收内容: " + responseXml);
//
response.init(responseXml);
// 判断是否有错误消息
if (response.getFault() == null) {
logger.info("接口正常! ");
} else {
SoapFault fault = response.getFault();
StringBuffer err = new StringBuffer();
err.append("接口错误: ");
err.append(fault.getFaultcodeInfo());
err.append(": {'faultcode' : '");
err.append(fault.getFaultcode());
err.append("', 'faultstring' : '");
err.append(fault.getFaultstring());
err.append("'}");
logger.info(err.toString());
}
}
/**
* http请求
*
* @param request
* @return
*/
public static String httpExecute(HttpRequestBase request) {
String responseXml = "";
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
// 配置
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(60000).setConnectTimeout(60000)
.build();
request.setConfig(requestConfig);
HttpResponse httpResponse = httpClient.execute(request);
HttpEntity responseEntity = httpResponse.getEntity();
responseXml = EntityUtils.toString(responseEntity);
} catch (Exception e) {
request.abort();
logger.error("httpExecute request error", e);
} finally {
try {
request.releaseConnection();
} catch (Exception e) {
logger.error("httpExecute releaseConnection fail", e);
}
try {
httpClient.close();
} catch (Exception e) {
logger.error("httpExecute close error", e);
}
}
return responseXml;
}
/**
* http post xml请求
*
* @param url
* @param xml
* @return
*/
public static String httpPostXml(String url, String xml) {
String responseXml = "";
HttpPost httpPost = new HttpPost(url);
StringEntity requestEntity = new StringEntity(xml, "UTF-8");
httpPost.setEntity(requestEntity);
httpPost.setHeader("Content-Type", "text/xml; charset=UTF-8");
responseXml = httpExecute(httpPost);
return responseXml;
}
}
package org.sky.iboot.common.util.soap;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
public class XmlUtil {
private static Map<String, JAXBContext> jaxbContextMap = new HashMap<String, JAXBContext>();
/**
* xml转换为bean
*
* @param xml
* @param clazz
* @return
* @throws JAXBException
* @throws XMLStreamException
*/
public static <T> T xmlToBean(String xml, Class<T> clazz) throws JAXBException, XMLStreamException {
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
XMLStreamReader reader = xmlInputFactory.createXMLStreamReader(new StringReader(xml));
Unmarshaller unmarshaller = getUnmarshaller(clazz);
JAXBElement<T> jaxbElement = unmarshaller.unmarshal(reader, clazz);
return jaxbElement.getValue();
}
/**
* bean转换为xml
*
* @param obj
* @return
* @throws JAXBException
*/
public static String beanToXml(Object obj) throws JAXBException {
String className = obj.getClass().getName();
className = className.substring(className.lastIndexOf(".") + 1);
className = Character.toLowerCase(className.charAt(0)) + className.substring(1);
QName qname = new QName(className);
return beanToXml(qname, obj);
}
/**
* bean转换为xml
*
* @param obj
* @return
* @throws JAXBException
*/
public static String beanToXml(QName qname, Object obj) throws JAXBException {
StringWriter stringWriter = new StringWriter();
@SuppressWarnings({ "rawtypes", "unchecked" })
JAXBElement jaxbElement = new JAXBElement(qname, obj.getClass(), obj);
Marshaller marshaller = getMarshaller(obj.getClass());
marshaller.marshal(jaxbElement, stringWriter);
return stringWriter.toString();
}
private static JAXBContext getJAXBContext(Class<?> clazz) throws JAXBException {
JAXBContext jaxbContext = null;
if (!jaxbContextMap.containsKey(clazz.getName())) {
jaxbContext = JAXBContext.newInstance(clazz);
jaxbContextMap.put(clazz.getName(), jaxbContext);
} else {
jaxbContext = jaxbContextMap.get(clazz.getName());
}
return jaxbContext;
}
private static Unmarshaller getUnmarshaller(Class<?> clazz) throws JAXBException {
Unmarshaller unmarshaller = null;
JAXBContext jaxbContext = getJAXBContext(clazz);
unmarshaller = jaxbContext.createUnmarshaller();
return unmarshaller;
}
private static Marshaller getMarshaller(Class<?> clazz) throws JAXBException {
Marshaller marshaller = null;
JAXBContext jaxbContext = getJAXBContext(clazz);
marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
return marshaller;
}
}