soap+wsimport的webservice接口客户端实现

一个自定义实现的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;
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值