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,持久化消息,添加自定義頭等,有待咱們發覺,可是代碼的結構大致和咱們例子類似。

相關文章
相關標籤/搜索