Apache CXF = Celtix + Xfire
支持多种协议:
SOAP1.1,SOAP1,2
XML/HTTP
RESTful (REpresentation State Transfer )
CORBA(Common Object Request Broker Architecture公共对象请求代理体系结构,早期语言使用的WS。C,c++,C#)
支持多种数据格式:XML , JSON
并可以与Spring进行快速无缝的整合
灵活的部署:可以运行有Tomcat,Jboss,Jetty(内置web服务器),IBMWebSphera,BeaWebLogic上面。
官网的下载路径:http://cxf.apache.org/download.html
CXF的结构:
Bus是CXF框架的支撑, CXF Bus由spring配置文件构成(cxf.xml),在servlet初始化时,通过SpringBusFactory加载,它为所有终端定义了公共的上下文.它织入了所有运行时的结构组件并提供了一个公共的应用上下文. SpringBusFactory扫描并加载类路径下的META-INF/cxf目录并从以下文件构建上下文.
META-INF/cxf/cxf.xml
META-INF/cxf/cxf-extension.xml
META-INF/cxf/cxf-property-editors.xml
XML文件是安装CXF类库的一部分. CXF内部使用Spring配置.cxf.xml文件中bus定义如下:
<bean id="cxf" class="org.apache.cxf.bus.CXFBusImpl" />
核心bus组件是CXFBusImpl,该类更多扮演拦截器供应商的角色对于终端出入的请求.
这些拦截器一旦应用,即可用于上下文中所有的终端.cxf.xml文件也定义了其他的组件,比如BindingFactoryManager, ConduitFactoryManager等等.这些组件可用于bus
的扩展.可以使用getExtension()方法这些组件.注册这些组件以用于获取或更新服务终端级别参数如服务绑定,传输协议,中转等等.
Frontend
CXF提供了前端建模的概念,可以使用不同的前端API创建ws.这些API使用简单工厂bean和JAX-WS实现创建ws.可以创建动态ws客户端.CXF支持的前端主要是JAX-WS.
Message and intercetpors:
消息和拦截器
CXF框架中重要的组件之一是拦截器组件.拦截器拦截客户端和服务器间的消息.在CXF,这通过拦截器链的概念实现.拦截器链是CXF运行时的核心功能.链中的每个拦截器是可配的,用户可以控制他的执行.
框架的核心的是拦截器接口,它定义了两个方法handleMessage和handleFault,都携带Message类型作为参数.
拦截器通常分组成各阶段.每个阶段执行特定的消息处理,每个阶段又被添加到拦截器链中,因此,链有时有序的拦截器阶段的列表.典型的ws终端有三个连接器链:
Inbound messages chain(入消息链)
Outbound messages chain(出消息链)
Error messages chain(错误消息链)
内置拦截器如日志,安全,也可以自定义拦截器.
Service Model-主要用于生成wsdl文件的各个元素。
建模service,创建各种WSDL元素如操作,绑定,终端,schema等等.
如下显示了服务模型中的各个组件:
Data binding
数据绑定是ws开发的关键.它意味着java对象和xml元素之间的映射.数据绑定组件执行这一工作.CXF最新版本使用JAXB2.1.JAXB使用注解定义java对象和XML之间的映射.如下:
@XmlRootElement(name="processOrder",
namespace=" http://localhost/orderprocess")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name="processOrder", namespace="http://localhost/orderprocess")
public class OrderProcess {
@XmlElement(name="arg0", namespace="")
private order.Order arg0;
//Gettter and Setter
…
}
协议绑定:protocol bindings
CXF支持以下形式的绑定:
SOAP1.1
SOAP1.2
CORBA
Pure XML
数据传输——transport
CXF支持以下数据传输方式:
HTTP
CORBA
JMS
LOCAL
安装CXF的其他支持项目:
MAVEN - 支持发布、运行和测试。
并设置以下环境变量:
JAVA_HOME
CXF_HOME
MAVEN_HOME
Path 添加
%JAVA_HOME%\bin;%CXF_HOME%\bin;MAVEN_HOME%\bin
CLASSPATH 添加
.;%CXF_HOME%\lib\cxf-manifest.jar;.\build\classes
在配置好以上环境后在命令行模式下进入cxf_home\samples\java_first_pojo
按照README.txt的提示进行操作。
主要是以下三个命令:
mvn install (builds the demo)
mvn -Pserver (from one command line window)
mvn -Pclient (from a second command line window)
先打开一个终端,输入mvn install ,然后出现以下信息的时候表示运行成功。
然后输入mvn -Pserver ,运行成功后会出现以下信息:
然后新打开一个终端,切换到相应的目录下输入 mvn -Pclient ,然后会在客户端打印如下信息:
在服务器端打印如下信息:
核心源码片段:
server端
HelloWorldImpl helloworldImpl = new HelloWorldImpl();
ServerFactoryBean svrFactory = new ServerFactoryBean();
svrFactory.setServiceClass(HelloWorld.class);
svrFactory.setAddress("http://localhost:9000/Hello");
svrFactory.setServiceBean(helloworldImpl);
//svrFactory.getServiceFactory().setDataBinding(new AegisDatabinding());
svrFactory.create();
client端
ClientProxyFactoryBean factory = new ClientProxyFactoryBean();
if (args != null && args.length > 0 && !"".equals(args[0])) {
factory.setAddress(args[0]);
} else {
factory.setAddress("http://localhost:9000/Hello");
}
HelloWorld client = factory.create(HelloWorld.class);
System.out.println("Invoke sayHi()....");
System.out.println(client.sayHi(System.getProperty("user.name")));
System.exit(0);
在Eclipse中开发CXF的JavaSE应用:
CXF发布服务的类:
JaxWsServerFactoryBean
JaxWsServerFactoryBean用于发布一个服务,可以通过默认构造实例此类。
它的方法如下:
setServiceBean(Object) – 设置一个服务对象 - *
setAddress(String url) – 绑定一个地址和端口 - *
create() - 在JavaSE环境下,使用jetty发布WebService. - *
以下是可选方法 :
setServiceClass(Class cls) – 设置服务对象实现的接口类。
JaxRsServerFactoryBean
此类用于发布RESTful风格的webService.
RESTful风格是以普通get,post请求为标准的,并可以请求和响应json数据。
CXF发布服务的类,其实是有两个,另一个是ServerFactoryBean它是JaxWsServerFactoryBean的父类。
server端代码示例:
/*
如果不是使用spring的配置文件发布,可以没有接口文件,但在任何情况下建议拥有接口文件。如果使用spring的配置文件发布,则必须要拥有接口类。
*/
package com.cxf.my;
import javax.jws.WebService;
@WebService
public interface HelloWorld {
String sayHi(String name);
}
package com.cxf.my;
import javax.jws.WebService;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
@WebService
public class HelloWorldCXF implements HelloWorld{
@Override
public String sayHi(String name){
System.out.println("CXF Server sayHi...");
return "Hi " + name;
}
public static void main(String[] args) throws Exception{
JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
svrFactory.setServiceClass(HelloWorldCXF.class);
svrFactory.setAddress("http://localhost:9000/helloWorld");
svrFactory.setServiceBean(new HelloWorldCXF());
svrFactory.getInInterceptors().add(new LoggingInInterceptor());//信息输入时的拦截器 –请求
svrFactory.getOutInterceptors().add(new LoggingOutInterceptor());//信息输出时的拦截器-响应
svrFactory.create();
}
}
client端
package com.cxf.my;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
public class TestClient {
public static void main(String[] args) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.getInInterceptors().add(new LoggingInInterceptor());
factory.getOutInterceptors().add(new LoggingOutInterceptor());
factory.setAddress("http://localhost:9000/helloWorld");
HelloWorld client = factory.create(HelloWorld.class);
System.out.println(client.sayHi("World"));
}
}
终端运行
wsimport -s . -p com.my.cxf http://localhost:9000/helloWorld?wsdl
然后将生成的代码导入新工程中进行测试:
HelloWorldCXF service = new HelloWorldCXFService().getHelloWorldCXFPort();
String str = service.sayHi("Rose");
System.out.println(str);
wsdl2java生成客户代码:
在cxf中,也提供了一个用于生成客户端调用代码的工具。它的功能就如同wsimport一样。
先让我们了解一下cxf的wsdl2java工具,可以生成一堆客户端调用的代码。
此工具位于cxf_home/bin目录下。参数与wsimport有所不同。
它包含以下参数:
-d参数,指定代码生成的目录。
-p参数,指定生成的新的包结构。
需要说明的是,由于wsdl2java是根据jdk1.7生成的本地代码,所以,需要对生成的代码做一点点修改。
在命令行执行:
在cxf中,也提供了一个用于生成客户端调用代码的工具。它的功能就如同wsimport一样。
先让我们了解一下cxf的wsdl2java工具,可以生成一堆客户端调用的代码。
此工具位于cxf_home/bin目录下。参数与wsimport有所不同。
它包含以下参数:
-d参数,指定代码生成的目录。
-p参数,指定生成的新的包结构。
需要说明的是,由于wsdl2java是根据jdk1.7生成的本地代码,所以,需要对生成的代码做一点点修改。
在命令行执行:
wsdl2java –d . http://127.0.0.1:6666/helloworld?wsdl
使用本JavaScript也可以访问WebServie:
jQuery访问WebService.
1、在本域准备jquery.js (由于jquery对跨域的请求做了限制,所以jquery仅限于在本域中使用。但为了快速解析XML文件,仍然可以使用jquery当成解析xml文件的工具。)。
2、通过js发起ajax请求。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<script type="text/javascript" src="<c:url value='/js/jquery-1.6.2.js'/>"></script>
</head>
<body>
<p>用js来控制的客户端</p>
<button id="all">显示所有</button><br/>
<hr/>
Name:<input type="text" id="_name">,Age:<input type="text" id="_age">
<button id="add">增加一个</button><br/>
<table id="tb" width="70%" border="1">
<tr>
<th>学生姓名</th>
<th>学生年龄</th>
</tr>
</table>
</body>
<script type="text/javascript">
$(function(){
var url = "http://localhost:7777/xcxf3_ss/ws/studQuery";
$("#all").click(function(){
//查询时必须向服务器发以下xml文件
var xml = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">'+
'<soap:Body><ns2:query xmlns:ns2="http://service.stud.cn/"/>'+
'</soap:Body></soap:Envelope>';
$.ajax({
url:url,
type:'post',
dataType:'xml',
contentType:'application/soap+xml;charset=UTF-8',
data:xml,
success:function(data){
$("#tb tr:gt(0)").remove();//删除所有列
//遍历data
$(data).find("return").each(function(){
var name = $(this).find("name").text();
var age = $(this).find("age").text();
var tr = $('<tr><td>'+name+'</td><td>'+age+'</td></tr>');
tr.appendTo("#tb");
});
}
});
//以下是增加
$("#add").click(function(){
var nm = $("#_name").val();
var age = $("#_age").val();
if($.trim(nm)=="" || $.trim(age)==""){
alert('姓名和年龄必须输入');
}
//以下是保存服务的xml
var xml = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">'
+'<soap:Body><ns2:add xmlns:ns2="http://service.stud.cn/">'
+'<arg0><age>'+age+'</age><name>'+nm+'</name></arg0></ns2:add>'
+'</soap:Body></soap:Envelope>';
$.ajax({
url:url,
type:'post',
dataType:'xml',
contentType:'application/soap+xml;charset=UTF-8',
data:xml,
success:function(){
alert('保存成功');
}
});
});
});
});
</script>
</html>