CXF是Apache公司下的项目,CXF=Celtix+Xfire;它支持soap1.一、soap1.2,并且可以和spring进行快速无缝整合。html
另外jax-ws是Sun公司发布的一套开发WebService服务的标准。早期的标准如jax-rpc已经不多使用,而cxf就是在新标准jax-ws下开发出来的WebService,jax-ws也内置到了jdk1.6当中。java
CXF官方下载地址:http://cxf.apache.org/download.htmlweb
下载完成以后,解压开压缩文件,能够发现有一个samples文件夹,在该文件夹中给出了很是多的例子用于研究CXF的使用方法。在CXF2.4.0中提供了Ant的配置运行方法,因此若是想要快速运行示例程序,就须要安装Ant环境,固然Tomcat环境、CXF环境确定也是必不可少的。spring
Ant、Tomcat都是Apache公司的项目:apache
Ant下载地址:http://ant.apache.org/浏览器
设置环境变量:tomcat
JAVA_HOME CXF_HOME ANT_HOME CATALINA_HOME Path = %JAVA_HOME%\bin;%CXF_HOME%\bin;%CATALINA_HOME%\bin;%ANT_HOME%\bin CLASSPATH=.;%CXF_HOME%\lib\cxf-manifest.jar;.\build\classes
使用Ant运行第一个CXF示例(以2.4.0为例),打开samples/java_first_pojo文件夹,并在该文件夹中打开两个命令行窗口,分别输入mybatis
ant server
和app
ant client
便可将示例运行起来,并看到服务端和客户端的控制台打印结果;可是注意jdk版本问题,最好使用jdk1.6,在jdk1.8的环境下运行不起来,jdk1.7没试过。框架
将lib文件夹下全部的jar包都拷贝到工程中,并添加到classpath,jar包有不少,里面包括了之后须要的springjar包。
CXF发布WebService服务的方式有两种,一种是“简单服务发布”,另一种是“复杂服务发布”
使用ServerFactoryBean类实现,该类是核心类。
1 package com.kdyzm.cxf.ws.server; 2 3 import org.apache.cxf.frontend.ServerFactoryBean; 4 5 public class CXFOneServer { 6 public String sayHello(String hello){ 7 System.out.println("接收到了请求的参数:"+hello); 8 return hello; 9 } 10 public static void main(String[] args) { 11 ServerFactoryBean bean=new ServerFactoryBean(); 12 bean.setAddress("http://localhost:9090/hello"); 13 //设置服务接口,若是没有接口,则为服务类 14 bean.setServiceClass(CXFOneServer.class); 15 //设置服务实现类 16 bean.setServiceBean(new CXFOneServer()); 17 bean.create(); 18 System.out.println("服务发布成功!"); 19 } 20 }
使用该类的特色就是:
能够看出来在CXF环境下发布服务和在JDK环境下发布服务的特色是大相径庭的。
复杂服务发布使用的核心类是JaxWsServerFactoryBean类,该类是ServerFactoryBean类的子类,同时也是功能扩展类,推荐使用该类发布服务,由于使用该类发布的服务生成的wsdsl文件更加规范。
1 package com.kdyzm.cxf.ws.server; 2 3 import javax.jws.WebService; 4 import javax.xml.ws.BindingType; 5 import javax.xml.ws.soap.SOAPBinding; 6 7 import org.apache.cxf.interceptor.LoggingInInterceptor; 8 import org.apache.cxf.interceptor.LoggingOutInterceptor; 9 import org.apache.cxf.jaxws.JaxWsServerFactoryBean; 10 11 /** 12 * 发布服务的第二种方法,这种方式必须加上WebService注解,不然服务类中的方法不能暴露出来 13 * @author kdyzm 14 *最好使用SOAP1.2,这样就算是SOAP1.1的客户端也可以正常访问服务 15 */ 16 @WebService 17 @BindingType(value=SOAPBinding.SOAP12HTTP_BINDING) 18 public class CXFTwoServer { 19 public String sayHello(String hello){ 20 System.out.println("获取请求参数:"+hello); 21 return hello; 22 } 23 public String calculate(int input){ 24 return input*input+""; 25 } 26 public static void main(String[] args) { 27 JaxWsServerFactoryBean bean=new JaxWsServerFactoryBean(); 28 bean.setAddress("http://localhost:9000/helloworld"); 29 bean.setServiceClass(CXFTwoServer.class); 30 bean.setServiceBean(new CXFTwoServer()); 31 //加上日志选项,可以清楚的查看到请求和相应的代码。 32 bean.getInInterceptors().add(new LoggingInInterceptor()); 33 bean.getOutInterceptors().add(new LoggingOutInterceptor()); 34 bean.create(); 35 System.out.println("第二种方式服务发布成功!"); 36 } 37 }
使用JaxWsServerFactoryBean类发布服务的方式的特色是:
强烈建议使用注解@BindingType(value=SOAPBinding.SOAP12HTTP_BINDING)将服务声明为符合SOAP1.2规范的服务。
这样就可以很是清楚的查看请求头信息、请求体信息、响应头信息和响应体信息了。
bean.getInInterceptors().add(new LoggingInInterceptor()); bean.getOutInterceptors().add(new LoggingOutInterceptor());
其实这种事情不须要赘述,毕竟webService最大的卖点就是这点。
可是须要注意的是,wsimport命令只识别SOAP1.1,因此若是服务是SOAP1.2的,那么使用wsimport命令就无论用了。解决方法就是使用CXF框架提供的
wsdl2java命令,该命令的功能和wsimport命令类似,可是比wsimport命令的功能更增强大,它支持SOAP1.2。
使用方式:
wsdl2java -d 参数,指定代码生成的目录 -p 参数,指定生成的新的包结构。
使用方式举例:
wsdlwjava -d . -p com.kdyzm.ws.cxf.server http://localhost:9090/ws?wsdl
如今是明白了,啥啥都要和sprig整合,hibernate能够不用,由于有不少相似的框架可以使用,好比mybatis;struts2框架也能够不用,可是惟独这spring是必需要使用的。因而可知spring的地位是多么重要了。
jar包和以前的相同,将/lib目录下的全部jar包都拷贝到WEB-INF/lib文件夹下就能够了。整合步骤:
<servlet> <servlet-name>cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>cxf</servlet-name> <url-pattern>/cxf/*</url-pattern> </servlet-mapping>
注意黑色背景部分的代码,拦截规则就是这样,以后的spring配置文件中配置的"address"属性部分是/cxf/后面的部分,而不是所有,这点是须要特别注意的。
该cxf配置文件实际上就是spring的配置文件,上一步配置的servlet默认读取的配置文件是WEB-INF/cxf-servlet.xml配置文件,因此若是将文件命名为cxf-servlet.xml,而且正好放置到了WEB-INF目录下,那么就不须要另外指定配置文件的地址了,可是咱们通常将配置文件放置到classpath路径中,而且名字也不是这样的名字,我我的的习惯是使用config结尾的配置文件名字,因此我给该配置文件起名为:cxf-config.xml,而且放置到了classpath根路径下,则就须要给Servlet显式配置声明该配置文件的路径:
<servlet> <servlet-name>cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <init-param> <param-name>config-location</param-name> <param-value>classpath:cxf-servlet.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>cxf</servlet-name> <url-pattern>/cxf/*</url-pattern> </servlet-mapping>
可是咱们通常让spring容器随着tomcat的启动而启动起来,因此咱们通常会context参数,这样就没必要在servlet中指定配置文件的位置了:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:cxf-servlet.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
这样Servlet就不能经过默认位置或者指定的位置"config-location"获取到配置文件了,在这种状况下为了可以拿到配置文件,必须在接下来的spring配置文件中声明三处很要紧的地方:
<!-- 若是自定义了配置文件的放置位置,就必须加上这三句代码了,不然不能自动加载配置文件 --> <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" />
若是自定义了配置文件的位置,必须加上该三句配置,不然Servlet没法找到配置文件。
这里的命名空间须要配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core" xsi:schemaLocation="http://www.springframework.org/schema/beans file:///D:/程序/java/Spring/spring-framework-4.2.1/spring-framework-4.2.1.RELEASE/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop file:///D:/程序/java/Spring/spring-framework-4.2.1/spring-framework-4.2.1.RELEASE/schema/aop/spring-aop-2.5.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd"> </beans>
这里加入了三个CXF须要的命名空间,另外须要beans的命名空间,固然这是必须的;最后必定要加上AOP的命名空间,虽然好像不须要,可是实际上AOP是Spring的核心,并且若是不声明该配置那么必定就会报错,提示找不到beans标签的定义,这个错误很是难以排查,实际上只须要加上AOP的声明便可。
<jaxws:endpoint id="one" address="/one" implementor="com.kdyzm.cxf.ws.server.OneServer"> <jaxws:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean> </jaxws:inInterceptors> <jaxws:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean> </jaxws:outInterceptors> </jaxws:endpoint>
address属性的值能够任意写,可是在访问的时候须要加上Servlet配置的拦截url前缀。
implementor属性值是服务类名,注意这种方式没有使用接口,也没法配置。
package com.kdyzm.cxf.ws.server; import javax.jws.WebService; @WebService public class OneServer{ public String calculate(int input){ return input*input+""; } }
接下来是输入拦截器和输出拦截器,使用这两个拦截器的做用和以前提到过的做用彻底相同,不赘述。
访问wsdl的方法就是在浏览器上输入:http://localhost:8080/cxf_server_web/cxf/one?wsdl,注意背景色部分,实际上该url由两部分组成,一部分是Servlet配置的拦截url,另一部分是spring文件中配置的address属性部分。
实际上这种发布方式只是可以使用接口了而已,推荐使用这种方式发布服务。
<jaxws:server id="two" address="/two" serviceClass="com.kdyzm.cxf.ws.server.inf.TwoServer"> <jaxws:serviceBean> <bean class="com.kdyzm.cxf.ws.server.TwoServerImpl"></bean> </jaxws:serviceBean> <jaxws:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean> </jaxws:inInterceptors> <jaxws:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean> </jaxws:outInterceptors> </jaxws:server>
以上两部分是对接口的声明和实现类的声明,address属性的意义同上。
接口:
1 package com.kdyzm.cxf.ws.server.inf; 2 3 import javax.jws.WebService; 4 import javax.xml.ws.BindingType; 5 import javax.xml.ws.soap.SOAPBinding; 6 7 @WebService 8 @BindingType(value=SOAPBinding.SOAP12HTTP_BINDING) 9 public interface TwoServer { 10 public String sayHello(String hello); 11 }
实现类:
1 package com.kdyzm.cxf.ws.server; 2 3 import com.kdyzm.cxf.ws.server.inf.TwoServer; 4 5 public class TwoServerImpl implements TwoServer{ 6 7 @Override 8 public String sayHello(String hello) { 9 return "你好,hello"; 10 } 11 12 }
能够经过在浏览器上输入:http://localhost:8080/cxf_server_web/cxf的方式查看发布的全部服务,内容以下:
配置的两个服务都会罗列出来。
能够单击上面的超连接查看,也能够直接输入地址查看,地址形式:http://localhost:8080/cxf_server_web/cxf/one?wsdl
效果以下图所示:
对于SOAP1.1来讲,可使用wsimport命令建立,可是对于SOAP1.2来讲,wsimport命令没法解析,必须使用wsdl2java命令建立本地调用代码。
调用的形式和方法和以前的方法如出一辙,只须要查看wsdl文件一步一步的来就能够了,可是须要注意的是,CXF提供了它本身的一套客户端调用方法,可是很是麻烦,甚至还须要依赖于Spring的环境,因此不推荐使用这种方法,若是非要使用这种方法,还不如使用Spring的远程调用了。
另外,CXF支持传输对象,使用方式和基本数据类型的使用方式如出一辙,略。