用CXF开发SOAP接口

本文详细介绍了如何使用Apache CXF发布接口和客户端调用,并提供了与Spring框架的整合示例。通过使用CXF提供的各种功能,如拦截器、复杂数据类型传递等,实现了WebService的高效开发。此外,文章还展示了如何根据WSDL生成客户端和服务端代码,以及如何在客户端添加和解析SOAP消息头。最后,提供了示例代码和配置,以便读者能够轻松地在自己的项目中应用这些知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

请参照:apache-cxf-2.5.1、jdk1.6.0_10

 

1.如何基于CXF发布接口以及客户端调用请参照下面的网址:

  http://www.cnblogs.com/hoojo/tag/WebService/

 

  这里面说了关于CXF的拦截器、与spring的整合以及复杂数据类型的传递。

 

2.从官方下载的CXF包里面,有个samples文件夹,这里面有各种应用的例子。

 

3.CXF本身自带的lib包里面就已经包含了spring的包,如下:



 

如果你的工程师已经是spring平台,这些包是不需要的。

关于具体每个包的作用以及要不要请结合lib文件夹下面的WHICH_JARS文件,这个文件里面有说明。

 

4.关于如何根据现有的wsdl生成客户端与服务端:

  

生成客户端命令

wsdl2java -d [数据绑定的类型] -wv [指定wsdl版本] -p [指定生成的包名] -sn [指定wsdl具体的service name] -client [wsdl文件路径]



 

 

整个黑线框里就是我根据wsdl生成的客服端代码,有一个报错的类,你只需要把报错方法里面super第三个参数删除就可以了。

PlatformServiceType_PlatformServiceType_Client生成的这个类主要是一个远程调用的测试类(它需要在当前路径下存放wsdl文件)

PlatformServiceType生成的这个接口包括了所有的方法。

其它的都是一些实体bean对象。

 

一般我们不用它生成的远程测试类方式,而是用一下方式实现:

/**
 * 
 */
package com.ml.sns.ws.cxf.remote;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Properties;
import java.util.logging.Logger;

import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

import com.ml.sns.ws.cxf.BabyHealthInfoBean;
import com.ml.sns.ws.cxf.BabyInfoBean;
import com.ml.sns.ws.cxf.PlatformServiceType;
import com.ml.sns.ws.cxf.ResultInfo;
import com.ml.sns.ws.cxf.UserInfoBean;
import com.ml.sns.ws.cxf.interceptor.AddSoapHeader;

/**
 * @author minglei
 * 
 */
public class RemoteClient {

	/**
	 * 日志打印
	 */
	private static final Logger LOG = null;//Logger.getLogger(RemoteClient.class);
	private static RemoteClient remoteClient = null;
	private static JaxWsProxyFactoryBean factory = null;
	private static PlatformServiceType service = null;
	private static String platformAddress = null;
	
	//鉴权属性
	public static String authAccount = null;
	public static String authPassword = null;
	public static String appID = null;

	static {
		init();
	}

	/**
	 * 初始化参数
	 */
	private static void init() {

		try {
			// 解析配置文件,获取接口配置信息
			InputStream is = RemoteClient.class
					.getResourceAsStream("/application.properties");
			Properties p = new Properties();
			p.load(is);
			//远程服务地址http://127.0.0.1:8088/services/snsService
			platformAddress = p.getProperty("ws.platform.address");
			authAccount = p.getProperty("ws.auth.account");
			authPassword = p.getProperty("ws.auth.password");
			appID = p.getProperty("ws.platform.appid");

			factory = new JaxWsProxyFactoryBean();//创建代理工厂
			factory.setServiceClass(PlatformServiceType.class);//服务的接口类----生成的
			factory.setAddress(platformAddress);//设置远程服务地址

			//构造拦截器列表
			ArrayList<Interceptor<?>> list = new ArrayList<Interceptor<?>>();
			// 添加soap header
			list.add(new AddSoapHeader());
			// 添加soap消息日志打印
			list.add(new org.apache.cxf.interceptor.LoggingOutInterceptor());

			factory.setOutInterceptors(list);

			service = (PlatformServiceType) factory.create();//通过代理工厂获得服务的实现调用类

		} catch (Exception e) {
			if (true) {
				LOG.info("Failed initialization webservice information."
						+ e.getMessage());
			}
		}
	}
	
	//下面的获得服务的实现调用类,来调用远程的方法
	public ResultInfo addBabyInfo(BabyInfoBean babyInfo) {
		return service.addBabyInfo(babyInfo);
	}
	public ResultInfo addUserInfo(UserInfoBean userinfo) {
		return service.addUserInfo(userinfo);
	}
	public ResultInfo addBabyHealthInfo(BabyHealthInfoBean babyHealthInfo) {
		return service.addBabyHealthInfo(babyHealthInfo);
	}
	/**
	 * 获得远程调用接口实例
	 * @return RemoteClient
	 */
	public static RemoteClient getRCInstance()
	{
		if(remoteClient ==null)
		{
			remoteClient = new RemoteClient();
		}
		
		return remoteClient;
	}
}

 

 

 

 

 

生成服务端命令

wsdl2java -d [数据绑定的类型] -wv [指定wsdl版本] -p [指定生成的包名] -sn [指定wsdl具体的service name] -impl -server[wsdl文件路径]



  

上图是根据wsdl生成的服务端

生成的PlatformServiceType_PlatformServiceType_Server类是用来启服务的,一般都web程序都不这么用,而是通过容器启动。

蓝线框里面的两个类,一个是接口,一个是接口的实现类这种正好和我们前通过接口发布服务一致,只需要在xml配置就可以了,在这里就不多说了。

 所以,我们的业务可以在接口的实现类里面调用。

 

 

5.换SOAP消息头添加与解析:

 

   在远程客服端添加消息头,通过拦截器;在前面4节的代码中已经实现了添加消息头功能。

/**
 * 
 */
package other.interceptor;

import java.util.List;

import javax.xml.namespace.QName;

import org.apache.cxf.binding.soap.SoapHeader;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import other.Utils;


/**
 * @author minglei
 * 
 */
public class AddSoapHeader extends AbstractSoapInterceptor {
	private static String nameURI = "http://webservice.iBaby.huawei.com/";

	public AddSoapHeader() {
		super(Phase.WRITE);
	}

	/**
	 * 在发送报文前,添加消息头鉴权
	 */
	public void handleMessage(SoapMessage message) throws Fault {

		/**
		 * 在消息投头中添加复杂对象节点,多层嵌套
		 * <soap:Header>
		 * <tns:RequestSOAPHeader xmlns:tns="http://webservice.iBaby.huawei.com/">
		 *		<tns:timestamp xmlns="http://webservice.iBaby.huawei.com/">20120118162416</tns:timestamp>
		 *		<tns:account xmlns="http://webservice.iBaby.huawei.com/">ming</tns:account>
		 *		<tns:authenToken xmlns="http://webservice.iBaby.huawei.com/">......</tns:authenToken>
		 * </tns:RequestSOAPHeader>
		 * </soap:Header>
		 */
		addSoapHeader1(message);
		
		/**
		 * 在消息投头中添加节点,报文如下:
		 * <soap:Header>
		 *		<timestamp xmlns="http://webservice.iBaby.huawei.com/">20120118162416</timestamp>
		 *		<account xmlns="http://webservice.iBaby.huawei.com/">ming</account>
		 *		<authenToken xmlns="http://webservice.iBaby.huawei.com/">......</authenToken>
		 * </soap:Header>
		 */
		addSoapHeader2(message);
		
		//注意方法同时只能调用一个
	}

	/**
	 * @param message
	 */
	private void addSoapHeader1(SoapMessage message) {
		QName qname = new QName("RequestSOAPHeader");
		Document doc = DOMUtils.createDocument();
		// 自定义节点
		Element timestamp = doc.createElement("tns:timestamp");
		timestamp.setTextContent(Utils.getSystemTime());

		Element account = doc.createElement("tns:account");
		account.setTextContent("uououo");

		//鉴权authenToken
		Element pass = doc.createElement("tns:authenToken");
		pass.setTextContent(Utils.encryptSHA256("123456"));

		Element root = doc.createElementNS(nameURI, "tns:RequestSOAPHeader");
		root.appendChild(timestamp);
		root.appendChild(account);
		root.appendChild(pass);

		SoapHeader head = new SoapHeader(qname, root);
		List<Header> headers = message.getHeaders();
		headers.add(head);
	}

	/**
	 * @param message
	 */
	private void addSoapHeader2(SoapMessage message) {
		//时间戳
		Document doc = DOMUtils.createDocument();
		QName qname = new QName("timestamp");
		Element timestamp = doc.createElementNS(nameURI, "timestamp");
		timestamp.setTextContent(Utils.getSystemTime());
		SoapHeader headTime = new SoapHeader(qname, timestamp);

		//账号
		QName qname2 = new QName("account");
		Element account = doc.createElementNS(nameURI, "account");
		account.setTextContent("mlmlml");
		SoapHeader headaAccount = new SoapHeader(qname2, account);

		// 鉴权authenToken
		QName qname3 = new QName("authenToken");
		Element pass = doc.createElementNS(nameURI, "authenToken");
		pass.setTextContent(Utils.encryptSHA256("123456"));
		SoapHeader headPass = new SoapHeader(qname3, pass);

		List<Header> headers = message.getHeaders();
		headers.add(headTime);
		headers.add(headaAccount);
		headers.add(headPass);
	}
}

 

 

在服务端添加解析消息头的拦截器,然后添加到配置文件中,结合1节网址里面的内容

/**
 * 
 */
package other.interceptor;

import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.saaj.SAAJInInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.NodeList;

/** */
/**
 * 
 * @Title:获取soap头信息
 * 
 * @Description:
 * 
 * @Copyright:
 * 
 * @author minglei
 * @version 1.00.000
 * 
 */
public class ReadSoapHeader extends AbstractPhaseInterceptor<SoapMessage> {

	private SAAJInInterceptor saa = new SAAJInInterceptor();

	public ReadSoapHeader() {
		super(Phase.PRE_PROTOCOL);
		getAfter().add(SAAJInInterceptor.class.getName());
	}

	public void handleMessage(SoapMessage message) throws Fault {
		SOAPMessage mess = message.getContent(SOAPMessage.class);
		if (mess == null) {
			saa.handleMessage(message);
			mess = message.getContent(SOAPMessage.class);
		}
		SOAPHeader head = null;
		try {
			head = mess.getSOAPHeader();
		} catch (SOAPException e) {
			e.printStackTrace();
		}
		if (head == null) {
			return;
		}
		try {
			// 读取自定义的节点
			NodeList nodes = head.getElementsByTagName("tns:account");
			NodeList nodepass = head.getElementsByTagName("tns:authenToken");
			// 获取节点值,简单认证
			if (nodes.item(0).getTextContent().equals("wdw")) {
				if (nodepass.item(0).getTextContent().equals("wdwsb")) {
					System.out.println("认证成功");
				}
			} else {
				SOAPException soapExc = new SOAPException("认证错误");
				throw new Fault(soapExc);
			}

		} catch (Exception e) {
			SOAPException soapExc = new SOAPException("认证错误");
			throw new Fault(soapExc);
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值