CXF是在xfire的基础上实现的,所以我们学习它会比较简单点。如果需要在现有的java程序(包括web应用)中增加webservice支持,应该使用CXF。如果希望以一种一致的方式实现webservice,特别是有跨语言的需求时,应该使用Axis2。下面我们看看实例。
一:首先还是有关包的问题,创建一个Maven项目,在pom.xml中加入依赖包,根据Apache CXF说明(http://cxf.apache.org/docs/using-cxf-with-maven.html),CXF中是有依赖spring的jar包,和XFire一样。
所以pom.xml中是:
<properties> <cxf.version>2.2.3</cxf.version> </properties>
<dependencies> <dependency> <groupId>com.hikvision.finance</groupId> <artifactId>finance-util</artifactId> </dependency> <!-- servlet api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <scope>provided</scope> </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>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-jetty</artifactId> <version>${cxf.version}</version> </dependency> </dependencies>
二:在编写之前先了解几个标注:
@WebService:将 Java 类标记为实现 Web Service,或者将 Java 接口标记为定义 Web Service 接口
参数:serviceName对外发布的服务名,指定 Web Service 的服务名称,缺省值为 Java 类的
简单名称 + Service。(字符串)。
endpointInterface服务接口全路径, 指定做SEI(Service EndPoint Interface)服务端点接口。
@WebMethod :定制Web Service方法
@WebParam :定制Web Service方法的参数
@WebResult : 定制Web Service方法的返回值
@SOAPBinding :指定WebService的SOAP映射样式
具体可参看:http://yufenfei.iteye.com/blog/1685249
三:编写一个JAVABEAN类
package com.cxf.model; public class CXFModel { private String name; private Integer age; public CXFModel(){ }; public CXFModel(Integer age, String name){ this.age = age; this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
四:编写接口类:
package com.cxf.impl; import java.util.List; import javax.jws.WebParam; import javax.jws.WebService; import com.cxf.model.CXFModel; @WebService public interface ICXFService { //这里的WebParam的name必须和后面参数名称一致 public String getCXFString(@WebParam(name="name")String name); public List<CXFModel> getCXFList(); }
五:编写实现类:
package com.cxf.impl; import java.util.ArrayList; import java.util.List; import javax.jws.WebService; import com.cxf.model.CXFModel; @WebService(endpointInterface="com.cxf.impl.ICXFService",serviceName="icxfService") public class CXFServiceImpl implements ICXFService{ @Override public String getCXFString(String name) { return "CXF Test getCXFString:" + name; } @Override public List<CXFModel> getCXFList() { List<CXFModel> list = new ArrayList<CXFModel>(); Integer[] ageArr = new Integer[]{21,22,22}; String[] nameArr = new String[]{"小明","小红","小亮"}; for(int i=0; i<3; i++){ list.add(new CXFModel(ageArr[i],nameArr[i])); } return list; } }
之前一直不明白这个serviceName有什么用,好像没用的,后来第六步测试的时候了解到,原来作用于这里:
六:接下来测试一下,我们可以利用CXF自带的容器服务来测试我们有没有成功,只要publish地址就可以了,这地址可以任意写,然后只要普通的run一下就行了。在地址上输入http://localhost:80/AAA?wsdl就可得到wsdl文件,下面是测试代码和测试结果。
package com.cxf.test; import javax.xml.ws.Endpoint; import com.cxf.impl.CXFServiceImpl; public class Test { public static void main(String[] args) { System.out.println("Server is starting..."); CXFServiceImpl service = new CXFServiceImpl(); Endpoint.publish("http://localhost:80/AAA",service); System.out.println("Server is started..."); } }
七:当然,我们是要实行客户端和服务器分离的,所以还是按正规来操作,那么我们需要在web.xml编写,注意,这里需要用到spring来定义文件,指定了spring的监听器和相应的配置文件路径,并且指定了CXF的拦截方式。
同时,配置文件applicationConfig.xml中设置了我们要访问的访问路径。下面是web.xml
<context-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/applicationConfig.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping>
applicationConfig.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <!--通过jaxws:endpoint定义了一个webservice,implementor是webservice的处理类 address是它的访问路径,部署后通过访问: http://localhost:80/CXFDemo/services/cxfServiceAddress?wsdl就可直接访问了 --> <jaxws:endpoint id="cxfServiceId" implementor="com.cxf.impl.CXFServiceImpl" address="/cxfServiceAddress" /> </beans>
八:最后我们和XFire一样,创建一个客户端项目去测试,只需要将接口类ICXFService和model中CXFModel类打成jar包引入即可。
package com.test; import java.util.List; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; import com.cxf.impl.ICXFService; import com.cxf.model.CXFModel; public class Client { public static void main(String[] args) { JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean(); factoryBean.setServiceClass(ICXFService.class); //这里的url地址是根据CXFDemo中applicationConfig得到的 factoryBean.setAddress("http://localhost:80/CXFDemo/services/cxfServiceAddress"); ICXFService service = (ICXFService)factoryBean.create(); //测试getCXFString方法 System.out.println(service.getCXFString("Client")); List<CXFModel> list = service.getCXFList(); for(CXFModel model : list){ System.out.println("model name:"+model.getName()+",age:"+model.getAge()); } } }
客户端运行结果: