Apache CXF学习 - SOAP Handler的使用

引入:html

咱们已经用前2篇的文章用2种方法建立了web service的endpoint而且对外提供服务。如今咱们假设要对来往的消息进行处理,而这些处理应该和咱们业务代码正交(也就是AOP,好比咱们要吧消息写入日志,或者区分是去web service站点的请求消息仍是从web service站点返回的相应消息),为了知足这个需求,咱们能够利用SOAPHandler来完成。java


代码实践:web

简单来讲,SOAPHandler就是用来对于SOAP消息进行处理的类,为了实现AOP,咱们有两种方式来实现对SOAP消息的处理。apache

一种是实现SOAPHandler<SOAPMessageContext>接口,它会对于整个SOAP消息进行处理。服务器

一种是实现LogicalHandler<LogicalMessageContext>接口,它会对消息的payload 进行处理。cookie

咱们就分别写2个处理器,来演示这2种用法。ide


服务器端:工具

首先,咱们开发一个LogHandler,它会拦截交互的SOAP消息而且打印出消息内容,咱们让其采用第一种方式,实现SOAPHandler<SOAPMessageContext>接口:测试

/**
 * SOAP Handler能够用来对SOAP消息进行访问。
 * 有2种Handler,一种是访问整个消息的, 一种是只访问SOAP消息payload的
 * 这里演示的是第一种,它必须实现SOAPHandler<SOAPMessageContext>接口
 */
package com.charles.cxfstudy.server.handlers;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
/**
 * 演示访问整个SOAP消息的Handler的用法
 * @author charles.wang
 *
 */
public class LogHandler implements SOAPHandler<SOAPMessageContext>{
    /**
     * 如何去处理SOAP消息的逻辑。
     * 这里会先打印当前调用的方法,而后从消息上下文中取出消息,而后写到标准输出流
     */
    public boolean handleMessage(SOAPMessageContext context) {
        System.out.println("LogHandler->handleMessage(context) method invoked");
        SOAPMessage message = context.getMessage();
        try{
            message.writeTo(System.out);
            System.out.println();
        }catch(Exception ex){
            System.err.print("Exception occured when handling message");
        }
        return true;
    }
    /**
     * 如何去处理错误的SOAP消息
     * 这里会先打印当前调用的方法,而后从消息上下文中取出消息,而后写到标准输出流
     */
    public boolean handleFault(SOAPMessageContext context) {
        System.out.println("LogHandler->handleFault(context) method invoked");
        SOAPMessage message = context.getMessage();
        try{
            message.writeTo(System.out);
            System.out.println();
        }catch(Exception ex){
            System.err.print("Exception occured when handling fault message");
        }
        return true;
    }
    /**
     * 这里没有资源清理的需求,因此咱们只打印动做到控制台
     */
    public void close(MessageContext context) {
        System.out.println("LogHandler->close(context) method invoked");
                                                                                                                                                                                                                                                                                                                                                                                   
    }
    public Set<QName> getHeaders() {
        return null;
    }
                                                                                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                                                                                               
}


而后咱们再开发AddCustomizedPartHandler,这个Handler会判断这个消息是入站(往web service Endpoint发送的请求消息)消息仍是出站(从web service Endpoint返回的消息)消息而后打印出结果,咱们采用第二种方式,让其实现 LogicalHandler<LogicalMessageContext>接口:spa

/**
 * SOAP Handler能够用来对SOAP消息进行访问。
 * 有2种Handler,一种是访问整个消息的, 一种是只访问SOAP消息payload的
 * 这里演示的是第二种,它必须实现LogicalHandler<LogicalMessageContext>接口
 */
package com.charles.cxfstudy.server.handlers;
import javax.xml.ws.handler.LogicalHandler;
import javax.xml.ws.handler.LogicalMessageContext;
import javax.xml.ws.handler.MessageContext;
/**
 * 演示访问SOAP消息的payload的Handler的用法
 * @author charles.wang
 *
 */
public class AddCustomizedPartHandler implements LogicalHandler<LogicalMessageContext> {
    /**
     * 如何去处理SOAP消息的逻辑,它会去判断这是入站仍是出站消息
     */
    public boolean handleMessage(LogicalMessageContext context) {
        System.out.println("AddCustomizedPartHandler->handleMessage(context) invoked");
                                                                                                                                                                                                                                                                                                                      
        //先判断消息来源是入站仍是出站的
        //(入站表示是发送到web service站点的消息,出站表示是从web service站点返回的消息)
        boolean outbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
                                                                                                                                                                                                                                                                                                                      
        //若是是出站消息
        if(outbound){
            System.out.println("This is an outbound message");     
        }else{
            System.out.println("This is an inbound message");
        }
                                                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                                                      
        return true;
    }
    public boolean handleFault(LogicalMessageContext context) {
        System.out.println("AddCustomizedPartHandler->handleFault(context) invoked");
        return true;
    }
    public void close(MessageContext context) {
        System.out.println("AddCustomizedPartHandler->close(context) invoked");
                                                                                                                                                                                                                                                                                                                      
    }
                                                                                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                                                                                  
}



为了让这2个handler生效,咱们必须写一个配置文件,来配置处理器链,这里咱们自定义某个handler_chains.xml(能够是任意名字),而且在其中配置了2个处理器,定义他们的顺序和实现类:

<?xml version="1.0" encoding="UTF-8"?>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
   <handler-chain>
    <handler>
        <handler-name>AddCustomizedPartHandler</handler-name>
        <handler-class>com.charles.cxfstudy.server.handlers.AddCustomizedPartHandler</handler-class>
    </handler>
    <handler> 
        <handler-name>LogHandler</handler-name>
        <handler-class>com.charles.cxfstudy.server.handlers.LogHandler</handler-class>
    </handler>
   </handler-chain>
</handler-chains>

从这里看出,判断入站出站的处理器在前,打印日志的处理器在后。


为了让咱们的Handler链生效到咱们的web service的Endpoint,咱们必须在服务接口或者服务实现类上用@HandlerChain注解来配置这个Handler链定义文件。这里,咱们为前面开发的加法运算的web服务激活处理器,因此在CalcServiceImpl上咱们采用了这个注解:

@WebService(endpointInterface="com.charles.cxfstudy.server.services.ICalcService")
//这里展现如何用@HandlerChain来声明一组Handler,他们会对指定的web service使用的SOAP消息进行处理,相似AOP
@HandlerChain(file="/handler_chains.xml")
public class CalcServiceImpl implements ICalcService {
...


这时候,打包应用而且部署在服务器上,咱们服务器端的代码就完成了。


客户端:

为了演示客户端和服务器端的交互是否会自动触发Handler的执行,咱们写一个客户端,首先咱们用JDK的wsimport工具来从给定的wsdl文件生成一组客户端的java文件:

wKioL1MHOImTLy65AACb6YSQJ_0800.jpg


这样它会在咱们给定目录用给定的包名生成一组文件:

wKioL1MHOMGA0a1EAAJ6thTnO-E053.jpg

咱们把这些文件复制到咱们客户端的项目应用中,而后编写测试方法以下:

/**
 * 客户端测试代码
 */
package com.charles.cxfclient;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
/**
 * @author charles.wang
 *
 */
public class MainTest {
                                                                                                                                                             
    public static void main(String [] args){
                                                                                                                                                             
    JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
    factory.setServiceClass(ICalcService.class);
    factory.setAddress("http://localhost:8080/cxf_jaxws_server/services/calc");
                                                                                                                                                             
    //调用业务方法
    ICalcService service = (ICalcService) factory.create();
    int a = 3,b=5;
    System.out.println("调用CalcService进行加法计算,2个运算子分别是:"+a+","+b);
    System.out.println("加法运算结果为:" + service.calcSum(a, b));
                                                                                                                                                             
    }
}


执行,它显然会打印出执行结果,不过这个执行的结果运算是经过 web service的调用完成的。

wKiom1MHOXGSfcIXAAEq-ZRBv2s284.jpg


咱们来看服务器的日志,以下图:

wKiom1MHOaDyH1EJAAJjuSCTL6E927.jpg

显然,这两个Handler都被正确的调用了(能够比较咱们的Handler的代码),好比AddCustomizedPartHandler会正确的识别这是inbound 仍是outbound消息,好比LogHandler能吧inbound消息(就是图片中内含<a>3</a><b>5</b>的)和outbound消息(就是图片中内涵<return>8</return>的)都打印出来,因此证实咱们开发的Handler是正确的。


固然了,Handler还能够作不少更高级别的功能,好比检验cookie,持久化消息,添加自定义头等,有待咱们发觉,可是代码的结构大致和咱们例子类似。

相关文章
相关标签/搜索