Apache CXF学习笔记一

41 篇文章 1 订阅

标题:Apache CXF学习笔记一
作者:kagula
最后更新日期:2016-09-05

 

环境:
 [1]JDK 1.7.x
 [2]Eclipse Mars.2 J2EE Version
 [3]Spring 3.1.2.RELEASE
 [4]CXF 3.0.9
 

概述:
 测试Spring+CXF实现Webservice服务端和客户端的技术可行性。 
 

正文
服务端
Step1:新建maven工程后,配置pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.nuoke</groupId>
  <artifactId>WSServerTest</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>WCServerTestMavenWebapp</name>
  <url>http://maven.apache.org</url>
  
  <properties>
    <spring.version>3.1.2.RELEASE</spring.version>
    <cxf.version>3.0.9</cxf.version>  
  </properties> 
  
  <dependencies>
    <dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context</artifactId>
		<version>${spring.version}</version>
	</dependency>	
	
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-web</artifactId>
		<version>${spring.version}</version>
	</dependency>
	
    <dependency>
	  <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-frontend-jaxws</artifactId>
      <version>${cxf.version}</version>      
   	</dependency>
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-transports-http</artifactId>
      <version>${cxf.version}</version>
    </dependency>
    
    <dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>
  </dependencies>
  <build>
    <finalName>WCServerTest</finalName>
     <plugins>  
            <plugin>  
                <groupId>org.apache.maven.plugins</groupId>  
                <artifactId>maven-compiler-plugin</artifactId>  
                <configuration>  
                    <source>1.7</source>  
                    <target>1.7</target>  
                    <encoding>UTF-8</encoding>  
                </configuration>  
            </plugin>  
            <plugin>  
                <groupId>org.apache.maven.plugins</groupId>  
                <artifactId>maven-surefire-plugin</artifactId>  
                <configuration>  
                    <!-- 跳过测试单元 -->  
                    <skip>true</skip>  
                </configuration>  
            </plugin>  
        </plugins>  
  </build>
</project>


 

Step2:web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 version="2.5"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>WSServerTest</display-name>	
	<!-- CXF -->
    <servlet>
        <description>Apache CXF Endpoint</description>
        <display-name>cxf</display-name>
        <servlet-name>cxf</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>cxf</servlet-name>
        <url-pattern>/services/*</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>60</session-timeout>
    </session-config>
</web-app>


 

Step3:cxf-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements. See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership. The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License. You may obtain a copy of the License at
 
  http://www.apache.org/licenses/LICENSE-2.0
 
  Unless required by applicable law or agreed to in writing,
  software distributed under the License is distributed on an
  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  KIND, either express or implied. See the License for the
  specific language governing permissions and limitations
  under the License.
-->
<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:jaxws="http://cxf.apache.org/jaxws" 
       xmlns:soap="http://cxf.apache.org/bindings/soap" 
       xsi:schemaLocation=" http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd 
       http://cxf.apache.org/bindings/soap 
       http://cxf.apache.org/schemas/configuration/soap.xsd 
       http://cxf.apache.org/jaxws 
       http://cxf.apache.org/schemas/jaxws.xsd">
    <jaxws:server id="jaxwsService" serviceClass="com.kagula.IService" address="/hello">
        <jaxws:serviceBean>
            <bean class="com.kagula.ServiceImpl"/>
        </jaxws:serviceBean>
    </jaxws:server>
</beans>


 

Step4:要传递的数据类型

package com.kagula.datatype;

public class MyPackage {
	private String strDirection;
	private MyPub pub;
	
	public MyPackage(String sd,MyPub mp)
	{
		strDirection = sd;
		pub = mp;
	}
	
	public MyPackage() {
		// TODO Auto-generated constructor stub
	}

	public MyPub getPub() {
		return pub;
	}

	public void setPub(MyPub pub) {
		this.pub = pub;
	}

	public String getStrDirection() {
		return strDirection;
	}

	public void setStrDirection(String strDirection) {
		this.strDirection = strDirection;
	}
}


 

package com.kagula.datatype;

import java.util.Date;

import javax.xml.bind.annotation.XmlType;

@XmlType  
public class MyPub implements java.io.Serializable {
	private String strTypeInstance;
	private int intTypeInstance;
	private float floatTypleInstance;
	private Date dateTypeInstance;
	
	public MyPub(String sV,int nV,float fV,Date dateV)
	{
		setStrTypeInstance(sV);
		setIntTypeInstance(nV);
		setFloatTypleInstance(fV);
		dateTypeInstance =dateV;
	}

	public MyPub() {
		// TODO Auto-generated constructor stub
	}

	public String getStrTypeInstance() {
		return strTypeInstance;
	}

	public void setStrTypeInstance(String strTypeInstance) {
		this.strTypeInstance = strTypeInstance;
	}

	public int getIntTypeInstance() {
		return intTypeInstance;
	}

	public void setIntTypeInstance(int intTypeInstance) {
		this.intTypeInstance = intTypeInstance;
	}

	public float getFloatTypleInstance() {
		return floatTypleInstance;
	}

	public void setFloatTypleInstance(float floatTypleInstance) {
		this.floatTypleInstance = floatTypleInstance;
	}

	public Date getDateTypeInstance() {
		return dateTypeInstance;
	}

	public void setDateTypeInstance(Date dateTypeInstance) {
		this.dateTypeInstance = dateTypeInstance;
	}
}


 

Step5:定义WS接口

package com.kagula;

import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;

import com.kagula.datatype.MyPackage;

@WebService  
public interface IService {	
	//如果没有@WebParam的话,参数名称为arg0, arg1...
	String sayHi(@WebParam(name="name") String text);
	
	MyPackage sayHi2(@WebParam(name="package") MyPackage mp);
}


 

Step6:实现WS接口

package com.kagula;

import javax.jws.WebService;

import org.apache.cxf.interceptor.InInterceptors;
import org.apache.cxf.interceptor.OutInterceptors;

import com.kagula.datatype.MyPackage;
import com.kagula.datatype.MyPub;

@WebService(endpointInterface = "com.kagula.ServiceImpl",
serviceName = "ServiceImpl")
@InInterceptors(interceptors="com.kagula.ArtifactInInterceptor")//Request拦截
@OutInterceptors(interceptors="com.kagula.ArtifactOutInterceptor")//Response拦截
public class ServiceImpl implements IService {
	//最基本测试
	@Override
    public String sayHi(String text)
    {
		return "Hello " + text + "!";
    }
	
	//复合数据类型传递测试
	@Override
	public MyPackage sayHi2(MyPackage mypackageReq)
	{
		MyPackage mypackageReturn = new MyPackage();
		mypackageReturn.setStrDirection("s2c");
		
		MyPub mypubReturn = mypackageReq.getPub();		
		mypubReturn.setStrTypeInstance(">>>"+mypubReturn.getStrTypeInstance());
		mypubReturn.setIntTypeInstance(mypubReturn.getIntTypeInstance()+1000);
		mypubReturn.setFloatTypleInstance(mypubReturn.getFloatTypleInstance()+10000.0f);
		
		mypackageReturn.setPub(mypubReturn);
		
		return mypackageReturn;
	}
}  


 

Step7: 输入输出拦截

package com.kagula;

import java.io.InputStream;

import org.apache.commons.io.IOUtils;
import org.apache.cxf.message.Message;  
import org.apache.cxf.phase.AbstractPhaseInterceptor;  
import org.apache.cxf.phase.Phase;

public class ArtifactInInterceptor extends AbstractPhaseInterceptor<Message>{
	public ArtifactInInterceptor() {
		//这儿使用receive,接收的意思
		super(Phase.RECEIVE);
	}
	
	public void handleMessage(Message message){
		try {
			InputStream is = message.getContent(InputStream.class);  
            //这里可以对流做处理,从流中读取数据,然后修改为自己想要的数据  
              
            //处理完毕,写回到message中  
            //在这里需要注意一点的是,如果修改后的soap消息格式不符合webservice框架格式,比如:框架封装后的格式为  
            //<soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope" <soap:Body>  
            //<这里是调用服务端方法的命名空间><这是参数名称>   
            //这里才是真正的消息
            //</这里是调用服务端方法的命名空间></这是参数名称>  
            //</soap:Body>
            //</soap:Envelope>  
            //如果是以上这种格式,在暴露的接口方法里才会真正接收到消息,而如果请求中在body里边,没有加方法命名空间和参数名称,直接就是消息体  
            //那接口方法里是接收不到消息的,因为cxf是按照上面的这种格式去解析的,所以如果不符合上面的格式,就应该在这里做处理  
            //……………………处理代码……………………
			
			
			//下面两行代码会导致“com.ctc.wstx.exc.WstxEOFException: Unexpected EOF in prolog”异常。
//            String xml = IOUtils.toString(is);
//            System.out.println("Input xml" + xml);

			if(is != null)
			{
				message.setContent(InputStream.class, is);
			}  
	    } 
		catch (Exception e) {
			System.out.println(e.getMessage());
		}//end catch
	}//end function
}//end class


 

package com.kagula;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.io.IOUtils;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;

public class ArtifactOutInterceptor extends AbstractPhaseInterceptor<Message>{
	 public ArtifactOutInterceptor() {  
	        //这儿使用pre_stream,意思为在流关闭之前  
	        super(Phase.PRE_STREAM);  
	    }  
	  
	    public void handleMessage(Message message) {
	    	try {
	    		OutputStream os = message.getContent(OutputStream.class);	    		
	            
	    		CachedStream cs = new CachedStream();  	  
	            message.setContent(OutputStream.class, cs); 
	            message.getInterceptorChain().doIntercept(message);  
	  
	            CachedOutputStream csnew = (CachedOutputStream) message.getContent(OutputStream.class);  
	            InputStream in = csnew.getInputStream();  
	              
	            String xml = IOUtils.toString(in);
	            System.out.println("Response xml>>>\n" + xml);
	              
	            //这里对xml做处理,处理完后同理,写回流中  
	            IOUtils.copy(new ByteArrayInputStream(xml.getBytes()), os);  
	              
	            cs.close();  
	            os.flush();  
	  
	            message.setContent(OutputStream.class, os);  
	        } catch (Exception e) {
	        	System.out.println("Error when split original inputStream. CausedBy : " + "\n" + e);  
	        }  
	    }  
	  
	    private class CachedStream extends CachedOutputStream {  
	  
	        public CachedStream() {  
	  
	            super();  
	  
	        }  
	  
	        protected void doFlush() throws IOException {  
	  
	            currentStream.flush();  
	  
	        }  
	  
	        protected void doClose() throws IOException {  
	  
	        }  
	  
	        protected void onWrite() throws IOException {  
	  
	        }  
	  
	    }  
}


 


客户端
是一个Java Application可以直接运行
源代码清单如下

package com.kagula;

import java.util.Date;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;

import com.kagula.datatype.MyPackage;
import com.kagula.datatype.MyPub;

public class Client {
	/*
	 * QName的第一个参数是namespace可以在
	 * http://localhost:8080/WSServerTest/services/hello?wsdl
	 * xmlns:tns属性中查看
	 * 或服务端源码package的名称倒一下。
	 * 第二个参数,是提供WS服务的接口名
	 * PORT_NAME的第二个参数,是提供WS服务的接口名+"Port"
	 */
	private static final QName SERVICE_NAME	= new QName("http://kagula.com/", "IService");
	private static final QName PORT_NAME = new QName("http://kagula.com/", "IServicePort");
	
	public static void main(String[] args) throws Exception
	{
		Service service = Service.create(SERVICE_NAME);
		String endpointAddress = "http://localhost:8080/WSServerTest/services/hello";

		// Add a port to the Service
		service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING, endpointAddress);
	       
	    IService is = service.getPort(IService.class);
	    System.out.println(is.sayHi("inuyasha"));
	    
	    //
	    MyPub mypub = new MyPub("Hello,Everybody!",1,2,new Date());
	    MyPackage mypackage = new MyPackage("c2s",mypub);
	    is.sayHi2(mypackage);
	}//end function
}//end class


备注
[1]在“http://mvnrepository.com/artifact”下可以查询依赖库是否存在。
[2]CXF3.0.9的示例代码可以通过下面的地址下载
http://www.apache.org/dyn/closer.lua/cxf/3.0.9/apache-cxf-3.0.9.zip
 
常见问题
Q
启动报错:java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
A
maven项目,tomcat在发布项目的时候没有同时发布maven依赖所添加的jar包,
你需要设置一下eclipse:
项目—>属性->Deployment Assembly->Add->Java Build Path Entries->选择Maven Dependencies->Finish->OK
把对应的Maven依赖包也发布到tomcat,调试时会自动把那些jar发布到指定目录下,tomcat也能找到那些jar了。

Q
No bean named cxf'is defined怎么解决
A
参考下面的网址
http://zhidao.baidu.com/link?url=IibpNztpqNOz5kWehXLnIX3nEr_wGGKFiz0tGu653iYqqIgcqRJfNMTLmCUTHnuG7XGDOmZ--Ey9XAnAyNpqI57WzFNSfGQZd6vA4p0stHm

Q Cannot change version of project facet Dynamic Web Module to 2.5
参考下面url
http://www.cnblogs.com/yezhenhan/archive/2011/10/17/2215279.html
然后更新maven工程即可。

Q Web App好像没有运行。
弄个index.jsp试试看,是不是真的没运行,如果是,启动以“Web App”方式运行试试看。

 

参考资料
[1]Apache CXF Official Site
http://cxf.apache.org/
[2]《Unofficial JAXB Guide》
https://jaxb.java.net/guide/

 

补充资料
[1]《Spring mvc 和 CXF 搭建SOAP环境》
http://my.oschina.net/long0419/blog/192788
[2]《Making Spring MVC and CXF play well together》
https://ayax79.wordpress.com/2009/02/19/making-spring-mvc-and-cxf-play-well-together/#comment-110
[3]《使用CXF为Web Service添加拦截器,自定义拦截器》
http://blog.csdn.net/a9529lty/article/details/8437599
[4]《CXF对java type与xml其间的marshall,unmarshall》
http://www.myexception.cn/xml-soap/668610.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kagula086

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值