如何从JAX-WS客户端获取XML响应体?

3

我在这里找到并阅读了许多关于如何从JAX-WS客户端检索XML响应的线程。在我的情况下,客户端是通过Oracle的JDeveloper产品从WSDL生成的,并将调用一个由.NET编写的Document/Literal服务端点。我想要做的是从调用客户端获取XML响应,而不是从处理程序内部获取。

我看到的最接近这个问题的线程是: http://www.coderanch.com/t/453537/Web-Services/java/capture-SoapRequest-xml-SoapResponse-xml

我不认为我想要生成一个Dispatch调用,因为端点的SOAP数据包的XML模式相当复杂,而自动生成的代理使调用变得微不足道。除非有其他方法来填充生成的bean(s),然后调用一些简单生成XML的方法,然后我再进行调用?

private void storeSOAPMessageXml(SOAPMessageContext messageContext) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    SOAPMessage soapMessage = messageContext.getMessage();
    try {
        soapMessage.writeTo(baos);
        String responseXml = baos.toString();
        log.debug("Response: " + responseXml );
        PaymentGatewayXMLThreadLocal.set(responseXml);
    } catch (SOAPException e) {
        log.error("Unable to retrieve SOAP Response message.", e);
    } catch (IOException e) {
        log.error("Unable to retrieve SOAP Response message.", e);
    }
}

我的想法是在处理程序内部将调用的响应存储在ThreadLocal中,然后在调用后读取它。这合理吗?因此,在处理程序执行handleMessage和handleFault中的上述代码之后,客户端调用代码会调用此方法:

@Override    
public String getSOAPResponseXML(Object clientstub) {
    String returnValue = PaymentGatewayXMLThreadLocal.get();
    return returnValue;
} // getSOAPResponseXML

看起来似乎还有另一种方法。阅读jax-ws-handlers后,我发现处理程序可以引入一个应用作用域变量。我更改了处理程序以实现此功能:

private void storeSOAPMessageXml(SOAPMessageContext messageContext) {
String xml = getSOAPMessageXml(messageContext);
// YourPayXMLThreadLocal.set(xml);
// put it into the messageContext as well, but change scope
// default of handler Scope, and client can't read it from responsecontext!
messageContext.put(SOAP_RESPONSE_XML, xml);
messageContext.setScope(SOAP_RESPONSE_XML, MessageContext.Scope.APPLICATION );
} // storeSOAPMessageXml

客户只需像这样阅读它:
@Override    
public String getSOAPResponseXML(Object clientstub) {
    String returnValue = null;
    // works (assuming a threadlocal is ok)
    // returnValue = YourPayXMLThreadLocal.get();

    BindingProvider bindingProvider = (BindingProvider) clientstub;
    // Thought this would work, but it doesn't - it returns null.        
    // Map<String, Object> requestContext = bindingProvider.getRequestContext();
    // String returnValue = (String) requestContext.get(JaxWsClientResponseXmlHandler.SOAP_RESPONSE_XML);

    // this works!!
    Map<String, Object> responseContext = bindingProvider.getResponseContext();
    System.out.println("has key? " + responseContext.containsKey(JaxWsClientResponseXmlHandler.SOAP_RESPONSE_XML));         
    returnValue = (String) responseContext.get(JaxWsClientResponseXmlHandler.SOAP_RESPONSE_XML);
    return returnValue;
} // getSOAPResponseXML
2个回答

1
如果您只想查看请求,您可以使用系统属性。
-Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true

如果您真的想要通过请求做些事情,那么处理程序似乎是自然的解决方案。也许可以使用请求上下文将值传递给处理程序?在客户端:
((BindingProvider) port).getRequestContext().put("KEY", "VALUE");

在处理器中:
String value = (String) messageContext.get("KEY");

1
我不只是想看到它,我想根据客户端已知的事务ID将其记录到数据库中。在发送请求之前,我创建此日志条目。处理程序不会知道这个事务ID(它不是请求的一部分 - 它是我的日志)。我想知道调用的SOAP响应结果。在Apache Axis中,我在另一个线程这里中回答了。我觉得一个更新的WS客户端堆栈会让这更容易。所以Threadlocal可以吗? - user1955401
jax-ws客户端将支付网关的soap响应解组为强类型对象。不幸的是,我们过去遇到过未记录的错误代码和超出预期/记录的字符串的情况。然后,我们简单持久化响应的例程会失败。这就是为什么故障安全响应列(clob)也被添加到日志中的原因。如果我按照您的路线走,我的处理程序必须能够持久化此响应,因为当我尝试在处理程序中放置KEY/VALUE对并在客户端中读取时,它为空。如果有帮助,我也使用MyBatis/Spring。 - user1955401

0

不幸的是,在发送XML之前且不使用消息处理程序的唯一方法是自己编组它(请参见JAXB)。这将为您提供数据的XML表示形式,但它可能与发送到WS的消息并不完全相同。可能会出现命名空间使用方式等方面的差异,但最重要的是,您将无法获得整个SOAP信封,只能获得您选择编组的标头的XML数据。


我在这里看到了一个回答:https://dev59.com/yGfWa4cB1Zd3GeqPgmjG?rq=1。我绝对不想在发送之前获取XML,我想要响应。SOAP故障和其他错误会阻止WS客户端解组为强类型Java对象。因此,我想要XML响应有效载荷。这回到了我的最初的问题:有没有任何理由我不能把它放在处理程序中的ThreadLocal中,以便从客户端检索?再次感谢所有的帮助。 - user1955401

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接