- 浏览: 525881 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
yadongliang:
终于找到HelloWorld++的版本...感谢
使用CXF开发RESTFul服务 -
hl174:
还是有点看不懂 存着再说
使用CXF Interceptor&Feature -
zxjlwt:
学习了。http://surenpi.com
Cannot find any registered HttpDestinationFactory from the Bus -
小4与小:
cj_long 写道楼主请问一下,如果文档第一页(例如:封面页 ...
创建itext document&横向打印 -
houxu109:
houxu109 写道我做了一些简单的优化,仅供参考publi ...
java实现oracle函数rpad和lpad
使用CXF Interceptor特性
本例代码在附件中
在Web Service中,客户端和服务端通过交换信息来互相通信。信息在客户端组装,在服务端解组。在Web Service术语中,组装表示将JAVA对象转换为XML文件,这些XML文档将被传输到网络中;反而言之,解组就是将XML文档转换为JAVA对象。
当客户端向服务端发送请求,请求中的数据将被组装并传输到服务器。服务器获取该数据,解组,最后调用服务方法。当服务器发送响应给客户端时,将重复该过程。组装和解组是客户端和服务端提供的核心功能。CXF通过Interceptor来提供这些功能。
Interceptor通过监听传输过来的信息来提供核心功能。这些功能包括:组装、解组、操纵消息头、执行认证检查、验证消息数据等。CXF提供内置的Interceptor来实现这些功能。用户也可以自定义Interceptor。Interceptor以phases组织起来,以链的形式调用,
理解interceptor phase 和chain
Phase可以被当作分类框,将类似功能的Interceptor组织起来。
有两种Interceptor链,inbound链和outbound链。两种都有一系列的Phase。例如,在inbound链中有UNMARSHAL Phase,用来解组信息数据,并将其转化为JAVA对象。
对于每个请求来讲,在服务端创建inbound Interceptor;对于每个响应来讲,将创建outbound Interceptor。
消息传输到链中,按特定的顺序在Phase中的Interceptor执行。
在信息传输到服务端之前,inbound Interceptor操作信息。
在信息传输到客户端之前,outbound Interceptor操作信息。
如果出现错误,Interceptor链释放自己,不去调用应用。
interceptor API概览
PhaseInterceptor继承自Interceptor接口。AbstractPhaseInterceptor实现了PhaseInterceptor。
Interceptor接口
如果要自定义Interceptor,就必须直接或间接实现Interceptor接口。Interceptor接口定义了两个方法。handleMessage和handleFault。
package org.apache.cxf.interceptor;
public interface Interceptor<T extends Message> {
void handleMessage(T message) throws Fault;
void handleFault(T message);
}
handleMessage方法需要org.apache.cxf.message.Message对象。这是执行信息的核心方法。为了自定义Interceptor就必须实习该方法,并提供执行信息的逻辑。
handleFault方法同样需要org.apache.cxf.message.Message对象。在执行Interceptor过程中出现错误时将会调用该方法。
PhaseInterceptor接口
大多数核心Interceptor都是实现继承自Interceptor接口的PhaseInterceptor。
PhaseInterceptor定义了4个方法。
getAfter将返回一个Set,包含了在这个Interceptor之前执行Interceptor的IDs。
getBefore将返回一个Set,包含了在这个Interceptor之后执行Interceptor的IDs。
getId返回ID
getPhase返回这个Interceptor所在的phase。
为了自定义Interceptor,开发者必须继承AbstractPhaseInterceptor抽象类。
AbstractPhaseInterceptor抽象类
AbstractPhaseInterceptor定义了构造器,可以为自定义的Interceptor指定特定的phase。当你指定了phase,自定义的Interceptor将会安排在链中Phase。AbstractPhaseInterceptor提供了空实现的handleFault。开发者可以覆盖这个方法。开发者必须实现handleMessage方法。
查看AbstractPhaseInterceptor抽象类,它已实现PhaseInterceptor接口的方法。Phase的顺序由PhaseInterceptorChain类决定
开发自定义的interceptor
为了演示interceptor的功能,假定一个用例:只有经过认证的用户才能调用Web Service,用户认证需要获取SOAP头的信息。
为了实现这些需求,创建两个interceptor,一个客户端,一个服务端。客户端interceptor负责拦截即将发出的SOAP信息,并在SOAP头中添加用户验证。服务端interceptor负责拦截收到的SOAP信息,从SOAP信息获取用户认证信息并验证该用户。如果用户验证失败,将抛出异常,在这种情况下阻止Web Service的运行。
开发自定义的interceptor分为如下几个步骤:
开发服务端的interceptor。
在Web Service服务类添加服务端interceptor。
开发客户端interceptor。
在客户端添加客户端interceptor。
开发发布Web Service的服务器。
开发服务端interceptor
OrderProcessUserCredentialInterceptor继承自AbstractSoapInterceptor,AbstractSoapInterceptor继承自AbstractPhaseInterceptor。AbstractSoapInterceptor提供了获取SOAP头和版本的信息。
OrderProcessUserCredentialInterceptor默认构造函数中,指定了Phase.PRE_INVOKE,代表着该interceptor将先于Web Service服务类执行。
public OrderProcessUserCredentialInterceptor() {
super(Phase.PRE_INVOKE);
}
handleMessage方法中,SoapMessage提供了获取SOAP头的信息。使用message.getHeader获取SOAP头中<OrderCredentials>元素
Header header = message.getHeader(qnameCredentials);
<soap:Header>
<OrderCredentials>
<username>John</username>
<password>password</password>
</OrderCredentials>
</soap:Header>
在OrderCredentials节点下,可以获得用户名和密码节点。
Element elementOrderCredential = (Element) header.getObject();
Node nodeUser = elementOrderCredential.getFirstChild();
Node nodePassword = elementOrderCredential.getLastChild();
package demo.order.server;
import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
public class OrderProcessUserCredentialInterceptor extends AbstractSoapInterceptor {
private String userName;
private String password;
public OrderProcessUserCredentialInterceptor() {
super(Phase.PRE_INVOKE);
}
public void handleMessage(SoapMessage message) throws Fault {
System.out.println("OrderProcessUserCredentialInterceptor handleMessage invoked");
QName qnameCredentials = new QName("OrderCredentials");
// Get header based on QNAME
if (message.hasHeader(qnameCredentials)) {
Header header = message.getHeader(qnameCredentials);
Element elementOrderCredential = (Element) header.getObject();
Node nodeUser = elementOrderCredential.getFirstChild();
Node nodePassword = elementOrderCredential.getLastChild();
if (nodeUser != null) {
userName = nodeUser.getTextContent();
}
if (nodePassword != null) {
password = nodePassword.getTextContent();
}
}
System.out.println("userName reterived from SOAP Header is " + userName);
System.out.println("password reterived from SOAP Header is " + password);
// Perform dummy validation for John
if ("John".equalsIgnoreCase(userName) && "password".equalsIgnoreCase(password)) {
System.out.println("Authentication successful for John");
} else {
throw new RuntimeException("Invalid user or password");
}
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Web Service业务类添加interceptor
Web Service业务类可以添加配置文件或者定义annotations添加interceptor。
添加InInterceptors注释定义了一个Inbound interceptor,将在Web Service执行之前调用。
@org.apache.cxf.interceptor.InInterceptors (interceptors = {"demo.
order.server.OrderProcessUserCredentialInterceptor" })
package demo.order; import javax.jws.WebService; @org.apache.cxf.interceptor.InInterceptors(interceptors = {"demo.order.server.OrderProcessUserCredentialInterceptor"}) @WebService public class OrderProcessImpl implements OrderProcess { public String processOrder(Order order) { System.out.println("Processing order..."); String orderID = validate(order); return orderID; } /** * Validates the order and returns the order ID * */ private String validate(Order order) { String custID = order.getCustomerID(); String itemID = order.getItemID(); int qty = order.getQty(); double price = order.getPrice(); if (custID != null && itemID != null && qty > 0 && price > 0.0) { return "ORD1234"; } return null; } }
开发客户端interceptor
同样的OrderProcessClientHandler继承自AbstractSoapInterceptor。
OrderProcessClientHandler默认构造器,指定了super(Phase.WRITE),还addAfter方法。addAfter指定了OrderProcessClientHandler将在CXF内置SoapPreProtocolOutInterceptor之后添加。OrderProcessClientHandler将在Phase.WRITE并在SoapPreProtocolOutInterceptor之后运行。SoapPreProtocolOutInterceptor负责建立SOAP版本和头,因此任何SOAP头元素的操作都必须在SoapPreProtocolOutInterceptor之后执行。
public OrderProcessClientHandler() {
super(Phase.WRITE);
addAfter(SoapPreProtocolOutInterceptor.class.getName());
}
构造函数new Header(qnameCredentials, elementCredentials);创建了Header对象,并设置了OrderCredentials元素。最后message.getHeaders().add(header)将SOAP头添加到信息中。
package demo.order.client; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor; import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor; import org.apache.cxf.headers.Header; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.phase.Phase; import org.w3c.dom.Document; import org.w3c.dom.Element; public class OrderProcessClientHandler extends AbstractSoapInterceptor { public String userName; public String password; public OrderProcessClientHandler() { super(Phase.WRITE); addAfter(SoapPreProtocolOutInterceptor.class.getName()); } public void handleMessage(SoapMessage message) throws Fault { System.out.println("OrderProcessClientHandler handleMessage invoked"); DocumentBuilder builder = null; try { builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); } catch (ParserConfigurationException e) { e.printStackTrace(); } Document doc = builder.newDocument(); Element elementCredentials = doc.createElement("OrderCredentials"); Element elementUser = doc.createElement("username"); elementUser.setTextContent(getUserName()); Element elementPassword = doc.createElement("password"); elementPassword.setTextContent(getPassword()); elementCredentials.appendChild(elementUser); elementCredentials.appendChild(elementPassword); // Create Header object QName qnameCredentials = new QName("OrderCredentials"); Header header = new Header(qnameCredentials, elementCredentials); message.getHeaders().add(header); } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } }
客户端添加interceptor
OrderProcessClientHandler设置了username和password。通过ClientProxy.getClient(client);获取Client对象,并通过cxfClient.getOutInterceptors().add(clientInterceptor)将clientInterceptor作为outbound interceptor。
package demo.order.client;
import demo.order.OrderProcess;
import demo.order.Order;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.transport.http.gzip.GZIPInInterceptor;
import org.apache.cxf.transport.http.gzip.GZIPOutInterceptor;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Client {
public Client() {
}
public static void main(String args[]) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"client-beans.xml"});
OrderProcess client = (OrderProcess) context.getBean("orderClient");
// OrderProcess client = (OrderProcess) context.getBean("orderClient2");
OrderProcessClientHandler clientInterceptor = new OrderProcessClientHandler();
clientInterceptor.setUserName("John");
clientInterceptor.setPassword("password");
org.apache.cxf.endpoint.Client cxfClient = ClientProxy.getClient(client);
cxfClient.getOutInterceptors().add(clientInterceptor);
Order order = new Order();
order.setCustomerID("C001");
order.setItemID("I001");
order.setQty(100);
order.setPrice(200.00);
String orderID = client.processOrder(order);
String message = (orderID == null) ? "Order not approved" : "Order approved; order ID is " + orderID;
System.out.println(message);
}
}
开发发布Web Service的服务器
package demo.order; import org.apache.cxf.feature.LoggingFeature; import org.apache.cxf.interceptor.LoggingInInterceptor; import org.apache.cxf.interceptor.LoggingOutInterceptor; import org.apache.cxf.jaxws.JaxWsServerFactoryBean; import org.apache.cxf.transport.http.gzip.GZIPFeature; import org.apache.cxf.transport.http.gzip.GZIPInInterceptor; import org.apache.cxf.transport.http.gzip.GZIPOutInterceptor; public class OrderProcessServerStart { public static void main(String[] args) throws Exception { OrderProcess orderProcess = new OrderProcessImpl(); LoggingFeature log = new LoggingFeature(); GZIPFeature gzip = new GZIPFeature(); gzip.setThreshold(1); JaxWsServerFactoryBean server = new JaxWsServerFactoryBean(); server.setServiceBean(orderProcess); server.setAddress("http://localhost:8080/OrderProcess"); server.getFeatures().add(log); server.getFeatures().add(gzip); //server.getFeatures().add(log); //server.getInInterceptors().add(new LoggingInInterceptor()); //server.getOutInterceptors().add(new LoggingOutInterceptor()); server.create(); System.out.println("Server ready...."); Thread.sleep(5 * 60 * 1000); System.out.println("Server exiting"); System.exit(0); } }
理解CXF features
Feature其实是interceptors另外一种形式。可以使用feature组件来代替直接使用interceptor。
本例中添加了log和gzip两个feature,正如Interceptor中所描述的phase的概念,添加log和gzip的顺序会影响LoggingFeature显示的内容。
请读者自行尝试OrderProcessServerStart中
server.getFeatures().add(log);
server.getFeatures().add(gzip);
//server.getFeatures().add(log);
和client-beans.xml中
<bean class="org.apache.cxf.feature.LoggingFeature"></bean>
<bean class="org.apache.cxf.transport.http.gzip.GZIPFeature" >
<property name="threshold" value="1" />
</bean>
<!--bean class="org.apache.cxf.feature.LoggingFeature"></bean-->
安排log和gzip的添加次序。
LoggingFeature
LoggingFeature可以独立于服务端和客户端。也就是说,可以服务端添加LoggingFeature,而客户端不添加,反之亦然。
GZIPFeature
GZIPFeature不同于LoggingFeature,客户端和服务端必须同时实现GZIPFeature,不然会抛出异常javax.xml.ws.soap.SOAPFaultException: Couldn't parse stream.。
查看添加GZIPFeature的服务器需要借助于工具。Tcpmon是其中的一个选择,另外LoggingFeature提供了tcpmon类似的功能。
在client-beans.xml中<http-conf:client>元素指定了AcceptEncoding属性,这个属性暗示客户端应用将会接受gzip的内容。
tcpmon
http://www.blogjava.net/heyang/archive/2010/12/10/340294.html
下载地址http://ws.apache.org/commons/tcpmon/download.cgi
在执行CXF过程中,是无法查看到组装和解组的内容。如果希望看到内容,则需要借助工具。外部工具如tcpmon。将client-beans.xml address中的端口修改你希望的端口,如8081。然后在OrderProcessServerStart查看发布的端口
server.setAddress("http://localhost:8080/OrderProcess");
为8080。在tcpmon解压的目录bin中执行tcpmon.bat,出现tcpmon界面。切换到Admin。在Listen Port #处填写8081,在Target Port #填写8080,点击Add。然后切换到Sender。为了方便查看XML,在左下角有个XML Format,将其勾选上,tcpmon会将捕获的内容整理为XML格式。执行Client,便可以再Sender界面查看到XML的具体内容了。
threshold
忽略1 byte并压缩剩下的内容。Threshold若为0值表示全部内容都将压缩。如果Threshold未提供任何值,那么默认将执行全部内容压缩。
- interceptor.7z (3.3 KB)
- 下载次数: 144
评论
发表评论
-
Apache CXF开发Web Service 理解CXF Frontends之Contract-First
2013-01-05 15:03 3660《Apache CXF开发Web Service 理解C ... -
Apache CXF开发Web Service 目录
2012-12-31 15:47 2111最近看到回复中提到《开发CXF JAVA客户端》写得不 ... -
Apache CXF开发Web Service 开发Web Service之Kick Start
2012-12-31 15:44 4181Web Service看起来很神 ... -
Apache.CXF.Web.Service.Development学习笔记
2012-05-16 10:49 2216相信大家在阅读CXF官方文档(http://cxf.apach ... -
使用CXF开发RESTFul服务
2012-05-11 16:57 56747相信大家在阅读 CXF ... -
开发CXF JAVA客户端
2012-05-04 11:50 31897CXF提供了很多client端的调用方法。这里让你快速了解这些 ... -
Cannot find any registered HttpDestinationFactory from the Bus
2012-05-02 16:24 9456严重: Cannot find any registered ... -
Cannot find any registered HttpDestinationFactory from the Bus
2012-04-13 11:31 2428apache cxf 2.4.6 samples\wsdl_f ...
相关推荐
CXF&spring实例,服务端客户调,spring配置
讲解了cxf实现拦截器的原因、核心API及使用方法
使用CXF开发Web Service,包含服务器端和客户端
WebService CXF技术手册 和 XFire技术手册,详细,有实例
使用CXF开发简单HelloWorld实例
java语言实现使用spring+mybatis+oracle访问数据库,使用cxf发布webservice,并使用axis调用webservice。项目使用maven管理jar包。
使用cxf wsdl2java生成webservice客户端命令
CXF视频:1、使用CXF实现简单的HelloWorld
使用cxf搭建webService,客户端通过接口进行调用
这是我在使用cxf+spring进行开发中的一点总结,如何搭建开发环境、如何配置dao使用,如何解决乱码问题等的经验分享
02.CXF功能概述_CXF发展历史和使用CXF开发WebService服务器端
这里的Interceptor就和Filter、Struts的Interceptor很类似,提供它的主要作用就是为了很好的降低代码的耦合性,提供代码的内聚性。以HelloWorldService为例子。 参照网址:...
使用CXF暴露您的REST服务 简单的例子,完整的配置过程
使用cxf webservice时容易出现的异常
这是讲解cxf的权威开发文档 文档内容:Apache CXF 提供方便的Spring整合方法,可以通过注解、Spring标签式配置来暴露Web Services和消费Web Services
cxf&spring;&json;&xml;所需要的jar包和实例
JAVA7和JAVA8对应CXF资源 WebService CXF 用了一天时间找,官网打不开,国内要积分,下下来又永不了。最后终于搞到手,上传上来分享给大家。 jdk版本 CXF版本 java 9及以上 3.3.x java 8 3.x java 7 2.2x --- ...
2、将cxf_jar包文件夹下所有包,拷至MyCXFService与MyCXFClient项目WebRoot\WEB-INF\lib\cxf_2.7.8 目录下(注意:两个项目都需要这些jar包) 3、将两个项目都导入myEclipse 4、将MyCXFService与MyCXFClient 一起...
文中讲解了CXF服务端的库文件,文件配置要求;客户端、服务端的访问示例;CXF的整合;拦截器的使用;等CXF常用的操作。