CXF通过拦截器修改请求报文

Posted feong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CXF通过拦截器修改请求报文相关的知识,希望对你有一定的参考价值。

最近一位做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 &lt;{}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();
            }
        }
    }

}

 

 

以上是关于CXF通过拦截器修改请求报文的主要内容,如果未能解决你的问题,请参考以下文章

cxf client在后台不通且chunk设置为false的时候不能在控制台输出请求日志

webservice之拦截器

webservice 权限控制

CXF 中自定义SOAPHeader

CXF对Interceptor拦截器的支持

CXF拦截器(Interceptor)LoggingInInterceptor