最近一位做Siebel的同事需要通過Web Service接口調用另外一個系統,對方的Web Service使用的是CXF框架,並提供了WSDL文件。
Siebel通過WSDL生成請求報文時報錯,而直接通過SoapUI導入WSDL測試是OK的。通過抓取報文發現,兩者生成的報文namespace有所不同,Siebel生成的namespace放在節點上,SoapUI生成的namespace放在頭上,具體如下:
Siebel生成的報文:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <SOAP-ENV:Body> <handleCallCenterWarningInfo xmlns="http://service.webservice.kora.com/"> <arg0> <handleDepartment/> <handleResult/> <handleStatus>1</handleStatus> <handleTime/> <realWarningCaseId/> <rescueOrderNumber>121212121</rescueOrderNumber> </arg0> </handleCallCenterWarningInfo> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Siebel調用時報錯信息如下:
Unmarshalling Error: unexpected element (uri:"http://service.webservice.kora.com/", local:"arg0"). Expected elements are <{}arg0>
SoapUI生成的報文:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://server.webservice.mycompany.com/"> <soapenv:Header/> <soapenv:Body> <ser:haha> <arg0> <handleDepartment>1</handleDepartment> <handleResult>2</handleResult> <handleStatus>3</handleStatus> <handleTime>4</handleTime> <realWarningCaseId>5</realWarningCaseId> <rescueOrderNumber>6</rescueOrderNumber> </arg0> </ser:haha> </soapenv:Body> </soapenv:Envelope>
針對報文格式問題,准備兩種嘗試方式:
1、攔截請求報文,把報文修改成符合WS命名空間的結構。
2、通過CXF框架的設置,設成不校驗命名空間。(此方式沒有技術參考,憑空想象的。后經測試驗證也沒有發現該配置選項,具體的WS規范以及CXF實現后續需要更深一步的查閱文檔以及源碼)
后經測試驗證,最終選擇了方式1解決,具體調整步驟如下:
1、在WS配置文件中增加紅色區域內容。
<jaxws:endpoint implementor="com.kora.webservice.service.CallCenterServiceImplPortImpl" address="/callCenterService" >
<jaxws:inInterceptors>
<bean class="com.info.CAbstractPhaseInterceptor">
<constructor-arg><value>receive</value></constructor-arg>
</bean>
</jaxws:inInterceptors>
</jaxws:endpoint>
2、增加一個攔截類CallCenterServiceImplPortImpl修改報文:
/** * CAbstractPhaseInterceptor.java * Created at 2017-4-13 * Created by hff * Copyright (C) 2017 SHANGHAI XXX, All rights reserved. */ package com.info; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import org.apache.cxf.binding.soap.Soap11; import org.apache.cxf.binding.soap.SoapVersion; import org.apache.cxf.helpers.IOUtils; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.message.Message; import org.apache.cxf.phase.AbstractPhaseInterceptor; /** * <p>ClassName: CAbstractPhaseInterceptor</p> * <p>Description: cxf攔截器</p> * <p>Author: hff</p> * <p>Date: 2017-4-13</p> */ public class CAbstractPhaseInterceptor extends AbstractPhaseInterceptor<Message> { /** * <p>Description: TODO</p> * @param phase */ public CAbstractPhaseInterceptor(String phase) { super(phase); } /* (non-Javadoc) * <p>Title: handleMessage</p> * <p>Description: </p> * @param message * @throws Fault * @see org.apache.cxf.interceptor.Interceptor#handleMessage(org.apache.cxf.message.Message) */ @Override public void handleMessage(Message message) throws Fault { InputStream is = message.getContent(InputStream.class); if (is != null) { try { String str = IOUtils.toString(is); // 原請求報文 System.out.println("====> request xml=\r\n" + str); // 把siebel格式的報文替換成符合cxf帶前綴的命名空間 str = str.replace("<handleCallCenterWarningInfo xmlns=\"http://service.webservice.kora.com/\">", "<ser:handleCallCenterWarningInfo xmlns:ser=\"http://service.webservice.kora.com/\">").replace( "</handleCallCenterWarningInfo>", "</ser:handleCallCenterWarningInfo>").replace( "xmlns=\"http://service.webservice.kora.com/\"", ""); // 替換后的報文 System.out.println("====> replace xml=\r\n" + str); InputStream ism = new ByteArrayInputStream(str.getBytes()); message.setContent(InputStream.class, ism); } catch (IOException e) { e.printStackTrace(); } } } }