最近一位做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= " + 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= " + str); InputStream ism = new ByteArrayInputStream(str.getBytes()); message.setContent(InputStream.class, ism); } catch (IOException e) { e.printStackTrace(); } } } }