一、CXF简介

  CXF是Apache公司下的项目,CXF=Celtix+Xfire;它支持soap1.1、soap1.2,而且能够和spring进行快速无缝整合。

  另外jax-ws是Sun公司发布的一套开发WebService服务的标准。早期的标准如jax-rpc已经很少使用,而cxf就是在新标准jax-ws下开发出来的WebService,jax-ws也内置到了jdk1.6当中。

  CXF官方下载地址:http://cxf.apache.org/download.html

  下载完成之后,解压开压缩文件,可以发现有一个samples文件夹,在该文件夹中给出了非常多的例子用于研究CXF的使用方法。在CXF2.4.0中提供了Ant的配置运行方法,所以如果想要快速运行示例程序,就需要安装Ant环境,当然Tomcat环境、CXF环境肯定也是必不可少的。

  Ant、Tomcat都是Apache公司的项目:

  Ant下载地址:http://ant.apache.org/

  设置环境变量:

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文件夹,并在该文件夹中打开两个命令行窗口,分别输入

ant server

  和

ant client

  即可将示例运行起来,并看到服务端和客户端的控制台打印结果;但是注意jdk版本问题,最好使用jdk1.6,在jdk1.8的环境下运行不起来,jdk1.7没试过。

二、Java SE下构建CXF的应用

  1.准备工作

    将lib文件夹下所有的jar包都拷贝到工程中,并添加到classpath,jar包有很多,里面包括了以后需要的springjar包。

  2.拷贝完jar包之后就能够进行测试了

    CXF发布WebService服务的方式有两种,一种是“简单服务发布”,另外一种是“复杂服务发布”

    (1)简单服务发布

    使用ServerFactoryBean类实现,该类是核心类。

 package com.kdyzm.cxf.ws.server;

 import org.apache.cxf.frontend.ServerFactoryBean;

 public class CXFOneServer {
public String sayHello(String hello){
System.out.println("接收到了请求的参数:"+hello);
return hello;
}
public static void main(String[] args) {
ServerFactoryBean bean=new ServerFactoryBean();
bean.setAddress("http://localhost:9090/hello");
//设置服务接口,如果没有接口,则为服务类
bean.setServiceClass(CXFOneServer.class);
//设置服务实现类
bean.setServiceBean(new CXFOneServer());
bean.create();
System.out.println("服务发布成功!");
}
}

    使用该类的特点就是:

      *  服务类可以不使用@WebService注解

      *  就算该服务类没有提供对外服务的方法,该服务也能够发布成功

    可以看出来在CXF环境下发布服务和在JDK环境下发布服务的特点是截然不同的。

    (2)复杂服务发布(推荐使用的服务发布方式)

    复杂服务发布使用的核心类是JaxWsServerFactoryBean类,该类是ServerFactoryBean类的子类,同时也是功能扩展类,推荐使用该类发布服务,因为使用该类发布的服务生成的wsdsl文件更加规范。

 package com.kdyzm.cxf.ws.server;

 import javax.jws.WebService;
import javax.xml.ws.BindingType;
import javax.xml.ws.soap.SOAPBinding; import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean; /**
* 发布服务的第二种方法,这种方式必须加上WebService注解,否则服务类中的方法不能暴露出来
* @author kdyzm
*最好使用SOAP1.2,这样就算是SOAP1.1的客户端也能够正常访问服务
*/
@WebService
@BindingType(value=SOAPBinding.SOAP12HTTP_BINDING)
public class CXFTwoServer {
public String sayHello(String hello){
System.out.println("获取请求参数:"+hello);
return hello;
}
public String calculate(int input){
return input*input+"";
}
public static void main(String[] args) {
JaxWsServerFactoryBean bean=new JaxWsServerFactoryBean();
bean.setAddress("http://localhost:9000/helloworld");
bean.setServiceClass(CXFTwoServer.class);
bean.setServiceBean(new CXFTwoServer());
//加上日志选项,能够清楚的查看到请求和相应的代码。
bean.getInInterceptors().add(new LoggingInInterceptor());
bean.getOutInterceptors().add(new LoggingOutInterceptor());
bean.create();
System.out.println("第二种方式服务发布成功!");
}
}

    使用JaxWsServerFactoryBean类发布服务的方式的特点是:

    *  服务类必须使用@WebService注解,虽然不加上该注解也不会报错,但是服务类中的所有服务方法都不会暴露出来(wsdl文件中找不到对应的方法),这样实际上该服务类就没有什么作用了。

    *  该类和ServerFactoryBean类相同,就算没有对外暴露服务方法,也能够将服务发布成功。

  3.说明

    (1)可以使用相关注解对服务类进行说明

      强烈建议使用注解@BindingType(value=SOAPBinding.SOAP12HTTP_BINDING)将服务声明为符合SOAP1.2规范的服务。

    (2)通过加上一下两句代码可以对请求和响应的过程进行监听

      这样就能够非常清楚的查看请求头信息、请求体信息、响应头信息和响应体信息了。

bean.getInInterceptors().add(new LoggingInInterceptor());
bean.getOutInterceptors().add(new LoggingOutInterceptor());

    

    (3)使用CXF发布的服务可以通过wsimport命令生成调用代码

      其实这种事情不需要赘述,毕竟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    

三、CXF整合Spring

  现在是明白了,啥啥都要和sprig整合,hibernate可以不用,因为有很多类似的框架能够使用,比如mybatis;struts2框架也可以不用,但是唯独这spring是必须要使用的。由此可见spring的地位是多么重要了。

  jar包和之前的相同,将/lib目录下的所有jar包都拷贝到WEB-INF/lib文件夹下就可以了。整合步骤:

  第一步:配置web.xml配置文件

<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配置文件的位置

  该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无法找到配置文件。

  第三步:CXF配置文件的配置

    1.命名空间的配置

      这里的命名空间需要配置

<?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的声明即可

    2.两种发布方式的配置

    (1)简单方式发布,这种方式的发布可以不使用接口

<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+"";
}
}

com.kdyzm.cxf.ws.server.OneServer

      接下来是输入拦截器和输出拦截器,使用这两个拦截器的作用和之前提到过的作用完全相同,不赘述。

    访问wsdl的方法就是在浏览器上输入:http://localhost:8080/cxf_server_web/cxf/one?wsdl,注意背景色部分,实际上该url由两部分组成,一部分是Servlet配置的拦截url,另外一部分是spring文件中配置的address属性部分。

    (2)复杂方式发布

      实际上这种发布方式只是能够使用接口了而已,推荐使用这种方式发布服务。

<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属性的意义同上。

  接口:

 package com.kdyzm.cxf.ws.server.inf;

 import javax.jws.WebService;
import javax.xml.ws.BindingType;
import javax.xml.ws.soap.SOAPBinding; @WebService
@BindingType(value=SOAPBinding.SOAP12HTTP_BINDING)
public interface TwoServer {
public String sayHello(String hello);
}

com.kdyzm.cxf.ws.server.inf.TwoServer

  实现类:

 package com.kdyzm.cxf.ws.server;

 import com.kdyzm.cxf.ws.server.inf.TwoServer;

 public class TwoServerImpl implements TwoServer{

     @Override
public String sayHello(String hello) {
return "你好,hello";
} }

com.kdyzm.cxf.ws.server.TwoServerImpl

  第四步:查看配置结果

    1.查看所有服务的方法

      可以通过在浏览器上输入:http://localhost:8080/cxf_server_web/cxf的方式查看发布的所有服务,内容如下:

    

    配置的两个服务都会罗列出来。

    2.查看wsdl

    可以单击上面的超链接查看,也可以直接输入地址查看,地址形式:http://localhost:8080/cxf_server_web/cxf/one?wsdl

    效果如下图所示:

    

  第五步:根据wsdl生成本地调用代码

    对于SOAP1.1来说,可以使用wsimport命令创建,但是对于SOAP1.2来说,wsimport命令无法解析,必须使用wsdl2java命令创建本地调用代码。

  第六步:使用本地调用代码调用WebService服务

    调用的形式和方法和之前的方法一模一样,只需要查看wsdl文件一步一步的来就可以了,但是需要注意的是,CXF提供了它自己的一套客户端调用方法,但是非常麻烦,甚至还需要依赖于Spring的环境,所以不推荐使用这种方法,如果非要使用这种方法,还不如使用Spring的远程调用了。

    另外,CXF支持传输对象,使用方式和基本数据类型的使用方式一模一样,略。

    

【Java EE 学习 81】【CXF框架】【CXF整合Spring】的更多相关文章

  1. 转载 WebService 的CXF框架 WS方式Spring开发

    WebService 的CXF框架 WS方式Spring开发   1.建项目,导包. 1 <project xmlns="http://maven.apache.org/POM/4.0 ...

  2. WebService 的CXF框架 WS方式Spring开发

    1.建项目,导包. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www ...

  3. Java EE 学习(9):IDEA + maven + spring 搭建 web(5)- 博客文章管理

    转载:Gaussic(一个致力于AI研究却不得不兼顾项目的研究生) . 注:在阅读本文前,请先阅读: Java EE 学习(5):IDEA + maven + spring 搭建 web(1) Jav ...

  4. Java EE 学习(7):IDEA + maven + spring 搭建 web(3)- 配置数据库

    参考: https://my.oschina.net/gaussik/blog/513444 注:在阅读本文前,请先阅读: Java EE 学习(5):IDEA + maven + spring 搭建 ...

  5. Java EE 学习(6):IDEA + maven + spring 搭建 web(2)- 配置 Spring

    参考:https://my.oschina.net/gaussik/blog/513353 注:此文承接上一文:Java EE 学习(5):IDEA + maven + spring 搭建 web(1 ...

  6. Java EE 学习(5):IDEA + maven + spring 搭建 web(1)

    参考:http://www.cnblogs.com/lonelyxmas/p/5397422.html http://www.ctolib.com/docs-IntelliJ-IDEA-c--1590 ...

  7. Java EE 学习(4):IDEA + maven 搭建 web(2)

    参考:http://www.bubuko.com/infodetail-1855067.html 现使用 Maven 创建项目:本节接Java EE 学习(3):IDEA + maven 搭建 web ...

  8. Java EE—最轻量级的企业框架?

    确保高效发展进程的建议 很久以前,J2EE,特别是应用程序服务器被认为过于臃肿和"重量级".对于开发人员来说,使用此技术开发应用程序会非常繁琐且令人沮丧.但是,由于 J2EE 框架 ...

  9. Java EE学习——Quartz的Cron表达式

    经历过低谷后,还是要好好学习,越失落会越来越落后. 今天写一下Cron表达式的用法,虽然是之前自己写的,也过了挺长一段时间,这次就拿出来作为回顾吧. Cron表达式是Quartz的精髓(个人觉得),比 ...

随机推荐

  1. 构造函数忘记new? 看这里看这里

    方法一:自调用构造函数 function Person(name){ if( !(this instanceof Person)){//一定要放在开头.检查this是否为构造函数的一个实例 retur ...

  2. C# 获取磁盘剩余空间

    drive.TotalFreeSpace单位为bit,根据需要除以1024 drive同时可以可以获取磁盘分区容量等 //单位MB public static long GetHardDiskSpac ...

  3. p/invoke碎片,对结构体的处理

    结构体的一些相关知识 可直接转换类类型,比如int类型,在托管代码和非托管代码中占据内存大小 和意义都是一个样的. 结构体封送的关键是:在托管代码和非托管代码中定义的一致性.什么是定义的一致性?包括结 ...

  4. windows系统如何添加ssh key到github

    我自己的电脑安装了git后,从来没有用过,今天偶然用了一次,发现不能pull到东西,报错说我没有权限,于是我网上搜索了一下,应该是我没有配置ssh key的原因,相信很多人都有和我一样的经历吧,这里呢 ...

  5. Python PIP安装

    https://zhidao.baidu.com/question/550936793.html 按图做

  6. 使用 JSON JavaScriptSerializer 进行序列化或反序列化时出错。字符串的长度超过了为 maxJsonLength 属性设置的值。

    解决办法是在web.config增加如下节点到<configuration>下 <system.web.extensions> <scripting> <we ...

  7. gdb调试PHP扩展错误

    有时候,使用PHP的第三方扩展之后,可能会发生一些错误,这个时候,可能就需要更底层的方式追踪调试程序发生错误的地方和原因,熟悉linux下C编程的肯定不陌生gdb 首先,使用ulimit -c命令,查 ...

  8. Demo 版

    Demo1   美食网站 Demo2   12301智慧旅游公共服务平台 Demo3   react_and_koa example

  9. JavaScript 构造函数与原型链

    构造函数.原型链: function Person(name, age, job) { this.name = name; this.age = age; this.job = job; // thi ...

  10. PHP之compact()函数

    PHP之compact()函数 compact()函数将变量转化为数组: <?php //直接调用函数 $a=1;$b=3;$c=4; var_dump($a,$b,$c); //自定义函数实现 ...