如何使用spring-ws和jaxb从WS响应中提取SOAP标头

时间:2014-12-08 16:14:19

标签: java spring jaxb spring-ws

我们在应用程序中使用spring-ws 2.2来使用Web服务。我们很高兴这样做了很长一段时间,一切都运行良好,除了现在我需要访问响应中的SOAP标头,我只是找不到这样做的方法。

我们正在使用配置了Jaxb2Marshaller的WebServiceTemplate(来自springs-ws)。 jaxb文件是使用xjc从wsdl生成的。我的回复中的标题元素如下所示:

   <soapenv:Header>
         <v1:ResponseHeader status="OK">
             <v1:description>test</v1:description>
          </v1:ResponseHeader>
   </soapenv:Header>

在我的java类中,解析响应的代码看起来像这样(我删除了一些不相关的代码):

public CalculationData getValues(Integer id) throws IntegrationException {
    WebServiceMessageCallback callback = createCallback(soapAction);

    GetValuesRequest request = toGetValues(id);
    GetValuesResponse response = null;
    try {
        response = (GetValuesResponse) webServiceTemplate.marshalSendAndReceive(request,         callback);
    } catch (SOAPFaultException fault) {
        log.error("Soap fault occurred during getValues " + id);
        throw new IntegrationException(fault);
    }

    CalculationData data = fromGetValues(response);

    return data;
}

请帮我找到一个解决方案,用于从响应中的SOAP标头中提取信息。我必须能够解析作为属性发送的状态代码。

顺便说一下。我还有一个ResponseHeader.java jaxb类,它是从模式生成的。

从最终更改中更新:

这是在内联ClientInterceptor实现后我的handleResponse方法的样子:

@Override
public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
    SoapMessage message = (SoapMessage) messageContext.getResponse();
    Iterator<SoapHeaderElement> responseHeaderElements =
            message.getSoapHeader().examineAllHeaderElements();
    SoapHeaderElement header = null;
    if (responseHeaderElements.hasNext()) {
        header = responseHeaderElements.next();
    } else {
        log.error("Error! No ResponseHeader found in response.");
        return false;
    }

    String responseCode = header.getAttributeValue(new QName(STATUS_QNAME));
    responseMsg.put(RESPONSE_MSG_KEY, responseCode);
    return true;
}

我尝试通过QName获取ResponseHeader元素,但由于某种原因,这似乎不起作用。但是,我只希望无论如何都能在soap标题中获得一个元素,这样可以正常工作。

2 个答案:

答案 0 :(得分:1)

实现ClientInterceptor,具体请参见handleResponse()方法。

要访问Soap Headers,请转换为SoapMessage

public final boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
        QName v1ResponseHeaderQName = null;//todo
        QName statusAttrQName = null;//todo
        SoapMessage message = (SoapMessage) messageContext.getResponse();
        Iterator<SoapHeaderElement> matchingHeaders = message.getSoapHeader().examineHeaderElements(v1ResponseHeaderQName);
        String status = matchingHeaders.next().getAttributeValue(statusAttrQName);
}

然后致电webServiceTemplate.setInterceptors(..)

有关此内容的更多示例,请参阅AbstractWsSecurityInterceptor及其子类。但请注意,这些拦截器涉及替换请求消息,您只想阅读响应消息。

问题是你现在正在处理原始肥皂消息,所以你已经失去了良好的弹簧编组,需要开始处理命名空间(QNames)和w3c Dom的东西。

为了让拦截器将头传递回调用代码,可以使拦截器成为在getValues(...)方法中设置的匿名内部类。

final Map<String,String> headers = new HashMap<>();

template.setInterceptors(new ClientInterceptor[]{new ClientInterceptor() {

        @Override
        public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
            return true;
        }

        @Override
        public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
            headers.put("foo", "bar");
            return false;
        }

        @Override
        public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
            return true;
        }

        @Override
        public void afterCompletion(MessageContext messageContext, Exception ex) throws WebServiceClientException {
        }
}});
template.marshalSendAndReceive(....);

答案 1 :(得分:1)

对于此用例,最佳解决方案是使用自定义WebServiceMessageExtractor,如下所述:

http://veithen.github.io/2015/01/03/spring-ws-extracting-soap-headers-from-responses.html