Java WS:如何将直接XML作为SOAP请求的一部分发送

时间:2013-01-21 00:47:47

标签: java-ee xml-serialization jax-ws

  1. 我已经获得了SOAP Web服务的WSDL

  2. 我在RAD Developer(一个与IBM Websphere一起使用的基于Eclipse的编译器)中创建了一个“自上而下,Java Bean”Web服务客户端,并自动生成了一堆JAX-WS .java模块

    < / LI>
  3. 以下是其中一项操作的自动生成的JAX-WS代码:


  4. @WebMethod(operationName = "CommitTransaction", action = "http://myuri.com/wsdl/gitsearchservice/CommitTransaction")
    
    @RequestWrapper(localName = "CommitTransaction", targetNamespace = "http://myuri.com/wsdl/gitsearchservice", className = "com.myuri.shwsclients.CommitTransaction")
    @ResponseWrapper(localName = "CommitTransactionResponse", targetNamespace = "http://myuri.com/wsdl/gitsearchservice", className = "com.myuri.shwsclients.CommitTransactionResponse")
    public void commitTransaction(
        @WebParam(name = "requestOptions", targetNamespace = "http://myuri.com/wsdl/gitsearchservice")
        RequestOptions requestOptions,
        @WebParam(name = "transactionData", targetNamespace = "http://myuri.com/wsdl/gitsearchservice")
        TransactionData transactionData);
    

    问题:

    • “transactionData”来自大型复杂的XML数据记录。 WSDL格式与我将在Java端编写的XML完全匹配,并且完全匹配Web服务将在服务器端读取的内容。

    • 问:如何绕过“transactionData”参数的Java序列化,在SOAP消息中发送原始XML?而不是必须读取我的XML,解析它,并逐字段打包Java“TransactionType”结构?

    提前谢谢!

1 个答案:

答案 0 :(得分:1)

我对RequestWrapperResponseWrapper注释的使用并不熟悉,但您的出站邮件最终看起来像是:

<CommitTransaction>
    <requestOptions>...</requestOptions>
    <transactionData>...</transactionData>
</CommitTransaction>

让我们假装它确实:)并且我们还假设TransactionData param的XML由Source实例表示。创建一个自定义SOAPHandler,维护Source的句柄:

public class TransactionDataHandler implements SOAPHandler<SOAPMessageContext> {
    private final Source transactionDataSource;

    public TransactionDataHandler(Source transactionDataSource) {
        this.transactionDataSource = transactionDataSource;
    }

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        // no exception handling
        Boolean isOutbound = (Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (Boolean.TRUE.equals(isOutbound)) {
            SOAPMessage message = context.getMessage();
            SOAPBody body = message.getSOAPBody();
            Node commitTransactionNode = body.getFirstChild();
            Result commitTransactionResult = new DOMResult(commitTransactionNode);
            TransformerFactory.newInstance().newTransformer().transform(this.transactionDataSource, commitTransactionResult);
        }
        return true;
    }

    @Override
    public Set<QName> getHeaders() {
        return null;
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        return true;
    }

    @Override
    public void close(MessageContext context) {
        // no-op
    }
}

我们的想法是转换步骤应该创建子<transactionData>节点。您还需要一个自定义HandlerResolver,可能类似于:

public class TransactionDataHandlerResolver implements HandlerResolver {
    private final Handler transactionDataHandler;

    public TransactionDataHandlerResolver(Source transactionDataSource) {
        this.transactionDataHandler = new TransactionDataHandler(transactionDataSource);
    }

    @Override
    public List<Handler> getHandlerChain(PortInfo portInfo) {
        return Collections.singletonList(this.transactionDataHandler);
    }
}

最后,创建一个Service实例并挂钩XML SourceHandlerResolver

Source transactionDataSource;
URL wsdlDocumentLocation;
QName serviceName;
Service service = Service.create(wsdlDocumentLocation, serviceName);
service.setHandlerResolver(new TransactionDataHandlerResolver(transactionDataSource));

从此处,您可以获得Dispatch或端口代理并启动操作。这可能不完全适合您现有的代码/环境,但希望它能为您提供一些思考的东西......

编辑:如果您正在使用端口代理,请为第二个arg传递null

port.commitTransaction(requestOptions, null);