代码之家  ›  专栏  ›  技术社区  ›  Pablo Santa Cruz

更改用JAXWS生成的默认XML命名空间前缀

  •  13
  • Pablo Santa Cruz  · 技术社区  · 14 年前

    我正在使用JAXWS为我们正在构建的Java应用程序生成WebService客户端。

    当JAXWS构建其XML以在SOAP协议中使用时,它会生成以下命名空间前缀:

    <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
       <env:Body ...>
           <!-- body goes here -->
       </env:Body>
    </env:Envelope>
    

    我的问题是,我的对手(一家大型的转账公司)管理我的客户机连接到的服务器,拒绝接受WebService调用( 请不要问我为什么 )除非xmlns(xml名称空间前缀为 soapenv )这样地:

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
       <soapenv:Body ...>
           <!-- body goes here -->
       </soapenv:Body>
    </soapenv:Envelope>
    

    所以我的问题是:

    是否有一种方法可以命令JAXWS(或任何其他Java WS-Client技术)生成客户端 索帕涅夫 而不是 env 作为 XMLNS 前缀?有没有 API调用 设置此信息?

    谢谢!

    2 回复  |  直到 7 年前
        1
  •  17
  •   joergl Zahid    11 年前

    也许你迟到了,我不确定这是否可行,但你可以试试。

    首先,您需要实现一个soaphandler,并在 handleMessage 方法可以修改 SOAPMessage . 我不确定您是否可以直接修改该前缀,但您可以尝试:

    public class MySoapHandler implements SOAPHandler<SOAPMessageContext>
    {
    
      @Override
      public boolean handleMessage(SOAPMessageContext soapMessageContext)
      {
        try
        {
          SOAPMessage message = soapMessageContext.getMessage();
          // I haven't tested this
          message.getSOAPHeader().setPrefix("soapenv");
          soapMessageContext.setMessage(message);
        }
        catch (SOAPException e)
        {
          // Handle exception
        }
    
        return true;
      }
    
      ...
    }
    

    然后你需要创建一个 HandlerResolver :

    public class MyHandlerResolver implements HandlerResolver
    {
      @Override
      public List<Handler> getHandlerChain(PortInfo portInfo)
      {
        List<Handler> handlerChain = Lists.newArrayList();
        Handler soapHandler = new MySoapHandler();
        String bindingID = portInfo.getBindingID();
    
        if (bindingID.equals("http://schemas.xmlsoap.org/wsdl/soap/http"))
        {
          handlerChain.add(soapHandler);
        }
        else if (bindingID.equals("http://java.sun.com/xml/ns/jaxws/2003/05/soap/bindings/HTTP/"))
        {
          handlerChain.add(soapHandler);
        }
    
        return handlerChain;
      }
    }
    

    最后,你必须添加 手持式旋转变压器 到您的客户服务:

    Service service = Service.create(wsdlLoc, serviceName);
    service.setHandlerResolver(new MyHandlerResolver());
    
        2
  •  5
  •   bluecarbon    7 年前

    虽然这篇文章对于最初的海报来说可能太晚了,但它的目的是帮助其他可能遇到这种情况的人。过去几天我不得不解决这个问题。特别是,我需要更改SOAP信封中使用的前缀,因为服务提供者要求命名空间前缀符合非常特定的模式。按照这种模式,需要更改信封、头和正文以及正文元素的名称空间前缀(从JAX-WS输入的标准前缀开始)。下面是我使用的解决方案的概要:

    import javax.xml.namespace.QName;
    import javax.xml.soap.SOAPBody;
    import javax.xml.soap.SOAPElement;
    import javax.xml.soap.SOAPEnvelope;
    import javax.xml.soap.SOAPException;
    import javax.xml.soap.SOAPHeader;
    import javax.xml.soap.SOAPMessage;
    import javax.xml.ws.handler.MessageContext;
    import javax.xml.ws.handler.soap.SOAPHandler;
    import javax.xml.ws.handler.soap.SOAPMessageContext;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;
    
    public class MyMessageNamespaceMapper implements SOAPHandler<SOAPMessageContext> {
    
      @Override
      public Set<QName> getHeaders() {
        return null;
      }
    
      @Override
      public boolean handleMessage(SOAPMessageContext context) {
        final Boolean outbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        // only process outbound messages
        if (outbound) {
          try {
            final SOAPMessage soapMessage = context.getMessage();
            final SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();
            final SOAPHeader soapHeader = soapMessage.getSOAPHeader();
            final SOAPBody soapBody = soapMessage.getSOAPBody();
    
            // STEP 1: add new prefix/namespace entries
            soapEnvelope.addNamespaceDeclaration("S1", "http://schemas.xmlsoap.org/soap/envelope/");
            soapEnvelope.addNamespaceDeclaration("FOO-1", "http://foo1.bar.com/ns");
    
            // STEP 2: set desired namespace prefixes
            // set desired namespace prefix for the envelope, header and body
            soapEnvelope.setPrefix("S1");
            soapHeader.setPrefix("S1");
            soapBody.setPrefix("S1");
            addDesiredBodyNamespaceEntries(soapBody.getChildElements());
    
            // STEP 3: remove prefix/namespace entries entries added by JAX-WS
            soapEnvelope.removeNamespaceDeclaration("S");
            soapEnvelope.removeNamespaceDeclaration("SOAP-ENV");
            removeUndesiredBodyNamespaceEntries(soapBody.getChildElements());
    
            // IMPORTANT! "Save" the changes
            soapMessage.saveChanges();
          }
          catch (SOAPException e) {
            // handle the error
          }
        }
    
        return true;
      }
    
      private void addDesiredBodyNamespaceEntries(Iterator childElements) {
        while (childElements.hasNext()) {
          final Object childElementNode = childElements.next();
          if (childElementNode instanceof SOAPElement) {
            SOAPElement soapElement = (SOAPElement) childElementNode;
    
            // set desired namespace body element prefix
            soapElement.setPrefix("FOO-1");
    
            // recursively set desired namespace prefix entries in child elements
            addDesiredBodyNamespaceEntries(soapElement.getChildElements());
          }
        }
      }
    
      private void removeUndesiredBodyNamespaceEntries(Iterator childElements) {
        while (childElements.hasNext()) {
          final Object childElementNode = childElements.next();
          if (childElementNode instanceof SOAPElement) {
            SOAPElement soapElement = (SOAPElement) childElementNode;
    
            // we remove any prefix/namespace entries added by JAX-WS in the body element that is not the one we want
            for (String prefix : getNamespacePrefixList(soapElement.getNamespacePrefixes())) {
              if (prefix != null && ! "FOO-1".equals(prefix)) {
                soapElement.removeNamespaceDeclaration(prefix);
              }
            }
    
            // recursively remove prefix/namespace entries in child elements
            removeUndesiredBodyNamespaceEntries(soapElement.getChildElements());
          }
        }
      }
    
      private Set<String> getNamespacePrefixList(Iterator namespacePrefixIter) {
        Set<String> namespacePrefixesSet = new HashSet<>();
        while (namespacePrefixIter.hasNext()) {
          namespacePrefixesSet.add((String) namespacePrefixIter.next());
        }
        return namespacePrefixesSet;
      }
    
      @Override
      public boolean handleFault(SOAPMessageContext context) {
        return true;
      }
    
      @Override
      public void close(MessageContext context) {
      }
    }
    

    在服务类(由jax-ws/wsimport生成)的实例上设置上面的处理程序冲突解决程序,如下所示:

    yourWebServiceClient.setHandlerResolver(new HandlerResolver() {
      @Override
      public List<Handler> getHandlerChain(PortInfo portInfo) {
        return Arrays.asList(new MyMessageNamespaceMapper());
      }
    });