2014-06-26 121 views
0

我試圖消費一個在soap請求中使用兩個名稱空間的webservice,但它不接受任何前綴。我使用cxf來生成客戶端和數據綁定。當使用JAXB作爲默認的數據綁定,這是發送到Web服務的服務器的消息:JAXB如何正確生成XML?

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> 
    <soap:Header> 
     <nfeCabecMsg xmlns:ns2="http://www.portalfiscal.inf.br/nfe" 
        xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2"> 
      <cUF>31</cUF> 
      <versaoDados>2.00</versaoDados> 
     </nfeCabecMsg> 
    </soap:Header> 
    <soap:Body> 
     <nfeDadosMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2" 
        xmlns:ns2="http://www.portalfiscal.inf.br/nfe"> 
      <ns2:consStatServ versao="2.00"> 
       <ns2:tpAmb>2</ns2:tpAmb> 
       <ns2:cUF>31</ns2:cUF> 
       <ns2:xServ>STATUS</ns2:xServ> 
      </ns2:consStatServ> 
     </nfeDadosMsg> 
    </soap:Body> 
</soap:Envelope> 

但是這不是服務器期望的格式。使用XMLBean的默認數據綁定我可以正確生成消息(如服務器期望):

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> 
    <soap:Header> 
     <nfeCabecMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2"> 
      <cUF>31</cUF> 
      <versaoDados>2.00</versaoDados> 
     </nfeCabecMsg> 
    </soap:Header> 
    <soap:Body> 
     <nfeDadosMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2"> 
      <consStatServ xmlns="http://www.portalfiscal.inf.br/nfe" versao="2.00"> 
       <tpAmb>2</tpAmb> 
       <cUF>31</cUF> 
       <xServ>STATUS</xServ> 
      </consStatServ> 
     </nfeDadosMsg> 
    </soap:Body> 
</soap:Envelope> 

不過,我真的affraid有關使用XmlBeans的,因爲我的軟件的另一個重要部分是使用JAXB開發,我可能需要將其更改爲XmlBeans。在我看到XmlBeans的最後一個版本是在2012年之後,我不確定將來會支持XmlBeans。 有沒有一種方法可以使用JAXB正確生成消息?

UPDATE

這是Web服務的WSDL:

<?xml version="1.0" encoding="utf-8"?> 
<wsdl:definitions xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" 
       xmlns:tns="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2" 
       xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" 
       targetNamespace="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2" 
       xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> 
    <wsdl:types> 
     <s:schema elementFormDefault="qualified" 
        targetNamespace="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2"> 
      <s:element name="nfeDadosMsg"> 
       <s:complexType mixed="true"> 
        <s:sequence> 
         <s:any/> 
        </s:sequence> 
       </s:complexType> 
      </s:element> 
      <s:element name="nfeStatusServicoNF2Result"> 
       <s:complexType mixed="true"> 
        <s:sequence> 
         <s:any/> 
        </s:sequence> 
       </s:complexType> 
      </s:element> 
      <s:element name="nfeCabecMsg" type="tns:nfeCabecMsg"/> 
      <s:complexType name="nfeCabecMsg"> 
       <s:sequence> 
        <s:element minOccurs="0" maxOccurs="1" name="cUF" type="s:string"/> 
        <s:element minOccurs="0" maxOccurs="1" name="versaoDados" type="s:string"/> 
       </s:sequence> 
       <s:anyAttribute/> 
      </s:complexType> 
     </s:schema> 
    </wsdl:types> 
    <wsdl:message name="nfeStatusServicoNF2Soap12In"> 
     <wsdl:part name="nfeDadosMsg" element="tns:nfeDadosMsg"/> 
    </wsdl:message> 
    <wsdl:message name="nfeStatusServicoNF2Soap12Out"> 
     <wsdl:part name="nfeStatusServicoNF2Result" element="tns:nfeStatusServicoNF2Result"/> 
    </wsdl:message> 
    <wsdl:message name="nfeStatusServicoNF2nfeCabecMsg"> 
     <wsdl:part name="nfeCabecMsg" element="tns:nfeCabecMsg"/> 
    </wsdl:message> 
    <wsdl:portType name="NfeStatusServico2Soap12"> 
     <wsdl:operation name="nfeStatusServicoNF2"> 
      <wsdl:input message="tns:nfeStatusServicoNF2Soap12In"/> 
      <wsdl:output message="tns:nfeStatusServicoNF2Soap12Out"/> 
     </wsdl:operation> 
    </wsdl:portType> 
    <wsdl:binding name="NfeStatusServico2Soap12" type="tns:NfeStatusServico2Soap12"> 
     <soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/> 
     <wsdl:operation name="nfeStatusServicoNF2"> 
      <soap12:operation soapAction="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2/nfeStatusServicoNF2" 
           style="document"/> 
      <wsdl:input> 
       <soap12:body use="literal"/> 
       <soap12:header message="tns:nfeStatusServicoNF2nfeCabecMsg" part="nfeCabecMsg" use="literal"/> 
      </wsdl:input> 
      <wsdl:output> 
       <soap12:body use="literal"/> 
       <soap12:header message="tns:nfeStatusServicoNF2nfeCabecMsg" part="nfeCabecMsg" use="literal"/> 
      </wsdl:output> 
     </wsdl:operation> 
    </wsdl:binding> 
    <wsdl:service name="NfeStatusServico2"> 
     <wsdl:port name="NfeStatusServico2Soap12" binding="tns:NfeStatusServico2Soap12"> 
      <soap12:address location="https://nfe.sefazvirtual.rs.gov.br/ws/NfeStatusServico/NfeStatusServico2.asmx"/> 
     </wsdl:port> 
    </wsdl:service> 
</wsdl:definitions> 

這些是用於創建consStatServ標籤最相關的模式:

<?xml version="1.0" encoding="UTF-8"?> 
<xs:schema xmlns="http://www.portalfiscal.inf.br/nfe" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      targetNamespace="http://www.portalfiscal.inf.br/nfe" elementFormDefault="qualified" 
      attributeFormDefault="unqualified"> 
    <xs:include schemaLocation="leiauteConsStatServ_v2.00.xsd"/> 
    <xs:element name="consStatServ" type="TConsStatServ"> 
     <xs:annotation> 
      <xs:documentation>Schema XML de validação do Pedido de Consulta do Status do Serviço</xs:documentation> 
     </xs:annotation> 
    </xs:element> 
</xs:schema> 


<?xml version="1.0" encoding="UTF-8"?> 
<xs:schema xmlns="http://www.portalfiscal.inf.br/nfe" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      targetNamespace="http://www.portalfiscal.inf.br/nfe" elementFormDefault="qualified" 
      attributeFormDefault="unqualified"> 
    <xs:include schemaLocation="tiposBasico_v1.03.xsd"/> 
    <xs:complexType name="TConsStatServ"> 
     <xs:annotation> 
      <xs:documentation>Tipo Pedido de Consulta do Status do Serviço</xs:documentation> 
     </xs:annotation> 
     <xs:sequence> 
      <xs:element name="tpAmb" type="TAmb"> 
       <xs:annotation> 
        <xs:documentation>Identificação do Ambiente: 
         1 - Produção 
         2 - Homologação 
        </xs:documentation> 
       </xs:annotation> 
      </xs:element> 
      <xs:element name="cUF" type="TCodUfIBGE"> 
       <xs:annotation> 
        <xs:documentation>Sigla da UF consultada</xs:documentation> 
       </xs:annotation> 
      </xs:element> 
      <xs:element name="xServ"> 
       <xs:annotation> 
        <xs:documentation>Serviço Solicitado</xs:documentation> 
       </xs:annotation> 
       <xs:simpleType> 
        <xs:restriction base="TServ"> 
         <xs:enumeration value="STATUS"/> 
        </xs:restriction> 
       </xs:simpleType> 
      </xs:element> 
     </xs:sequence> 
     <xs:attribute name="versao" type="TVerConsStatServ" use="required"/> 
    </xs:complexType> 
    <xs:complexType name="TRetConsStatServ"> 
     <xs:annotation> 
      <xs:documentation>Tipo Resultado da Consulta do Status do Serviço</xs:documentation> 
     </xs:annotation> 
     <xs:sequence> 
      <xs:element name="tpAmb" type="TAmb"> 
       <xs:annotation> 
        <xs:documentation>Identificação do Ambiente: 
         1 - Produção 
         2 - Homologação 
        </xs:documentation> 
       </xs:annotation> 
      </xs:element> 
      <xs:element name="verAplic" type="TVerAplic"> 
       <xs:annotation> 
        <xs:documentation>Versão do Aplicativo que processou a NF-e</xs:documentation> 
       </xs:annotation> 
      </xs:element> 
      <xs:element name="cStat" type="TStat"> 
       <xs:annotation> 
        <xs:documentation>Código do status da mensagem enviada.</xs:documentation> 
       </xs:annotation> 
      </xs:element> 
      <xs:element name="xMotivo" type="TMotivo"> 
       <xs:annotation> 
        <xs:documentation>Descrição literal do status do serviço solicitado.</xs:documentation> 
       </xs:annotation> 
      </xs:element> 
      <xs:element name="cUF" type="TCodUfIBGE"> 
       <xs:annotation> 
        <xs:documentation>Código da UF responsável pelo serviço</xs:documentation> 
       </xs:annotation> 
      </xs:element> 
      <xs:element name="dhRecbto" type="xs:dateTime"> 
       <xs:annotation> 
        <xs:documentation>AAAA-MM-DDTHH:MM:SS</xs:documentation> 
       </xs:annotation> 
      </xs:element> 
      <xs:element name="tMed" type="TMed" minOccurs="0"> 
       <xs:annotation> 
        <xs:documentation>Tempo médio de resposta do serviço (em segundos) dos últimos 5 minutos 
        </xs:documentation> 
       </xs:annotation> 
      </xs:element> 
      <xs:element name="dhRetorno" type="xs:dateTime" minOccurs="0"> 
       <xs:annotation> 
        <xs:documentation>AAAA-MM-DDTHH:MM:SSDeve ser preenchida com data e hora previstas para o retorno 
         dos serviços prestados. 
        </xs:documentation> 
       </xs:annotation> 
      </xs:element> 
      <xs:element name="xObs" type="TMotivo" minOccurs="0"> 
       <xs:annotation> 
        <xs:documentation>Campo observação utilizado para incluir informações ao contribuinte 
        </xs:documentation> 
       </xs:annotation> 
      </xs:element> 
     </xs:sequence> 
     <xs:attribute name="versao" type="TVerConsStatServ" use="required"/> 
    </xs:complexType> 
    <xs:simpleType name="TVerConsStatServ"> 
     <xs:annotation> 
      <xs:documentation>Tipo versão do leiuate da Consulta Status do Serviço 2.00</xs:documentation> 
     </xs:annotation> 
     <xs:restriction base="xs:token"> 
      <xs:pattern value="2\.00"/> 
     </xs:restriction> 
    </xs:simpleType> 
</xs:schema> 
+0

你可以發佈你的JAXB源代碼(xsd或Annotated Java Classes)嗎? – superbob

回答

0

我終於解決了這個問題。由於這是第三方Web服務,我唯一的選擇是編輯由JAXB生成的類。我做的第一件事是從package-info.java文件中刪除命名空間屬性。然後,我也做了同樣的的ObjectFactory類,在這裏我只是從改變的QName構造:

的QName(字符串的namespaceURI,字符串的localpart)

的QName (String localPart)

不幸的是,這些修改不刪除前綴,所以我實現我自己的CXF interceptor

public class NamespacePrefixInterceptor extends AbstractPhaseInterceptor<Message> { 
    public NamespacePrefixInterceptor() { 
     super(Phase.PRE_STREAM); 
     addBefore(SoapPreProtocolOutInterceptor.class.getName()); 
    } 

    @Override 
    public void handleMessage(Message message) throws Fault { 
     if (isOutbound(message)) { 
      OutputStream outputStream = message.getContent(OutputStream.class); 
      CachedOutputStream cachedOutputStream = new CachedOutputStream(); 
      message.setContent(OutputStream.class, cachedOutputStream); 
      message.getInterceptorChain().doIntercept(message); 
      try { 
       cachedOutputStream.flush(); 
       CachedOutputStream messageStream = (CachedOutputStream) message.getContent(OutputStream.class); 
       String currentEnvelopeMessage = IOUtils.toString(messageStream.getInputStream(), "UTF-8"); 
       currentEnvelopeMessage = currentEnvelopeMessage.replaceAll("ns2:", ""); 
       currentEnvelopeMessage = currentEnvelopeMessage.replaceAll(":ns2", ""); 
       messageStream.flush(); 
       messageStream.close(); 
       InputStream replaceInStream = new ByteArrayInputStream(currentEnvelopeMessage.getBytes(StandardCharsets.UTF_8)); 
       IOUtils.copy(replaceInStream, outputStream); 
       replaceInStream.close(); 
       outputStream.flush(); 
       message.setContent(OutputStream.class, outputStream); 
       outputStream.close(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    private boolean isOutbound(Message message){ 
     return message == message.getExchange().getOutMessage() 
      || message == message.getExchange().getOutFaultMessage(); 
    } 
} 

有了這個攔截我終於可以刪除的命名空間。最後一個問題是名稱空間xmlns =「http://www.portalfiscal.inf.br/nfe」應該出現在consStatServ元素中。由於所有不必要的命名空間是在JAXB生成的類修改後取出,我做了變通方法簡單地創建ConsStatServ類xmln屬性:

public class ConsStatServ { 
    . 
    . 
    . 
    @XmlAttribute(name = "xmlns", required = true) 
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class) 
    protected String xmlns = "http://www.portalfiscal.inf.br/nfe"; 
    public String getXmlns() { 
     return xmlns; 
    } 
} 

我知道這個解決方案是一個龐大的雜牌,但我找不到另外一個選擇。

2

你可能想用http://docs.oracle.com/javaee/5/api/javax/xml/bind/annotation/XmlElement.html對你的基因組元素進行註釋編輯類。它具有您感興趣的命名空間參數。我們之前有過類似的問題,並且能夠使其與這些手動更新一起工作。

參見JAXB: How do I annotate classes so that they belong to different namespaces?

+0

Web服務不接受soap消息中的任何名稱空間前綴。如果消息至少有一個名稱空間前綴,則返回被拒絕。 – brevleq

+0

@brevleq,這似乎是你打電話的服務中一個非常重要的缺陷。他們提供了一個理由,爲什麼格式良好的xml對提供的模式有效將被拒絕?一旦涉及多個模式名稱空間,防止使用前綴將可能導致適用的名稱空間被重複聲明,而不是在更高級別上進行1次聲明。把它看作一直使用完全合格的java類名稱,而不是在類的頂部有一個import語句(這不是一個完美的類比,但很接近)。 –

+0

@brevieq嘗試在XmlElement註釋中專門爲需要名稱空間的XML中的每個元素設置「namespace」參數:nfeDadosMsg和consStatServ。嘗試在XmlType註釋上設置namespace =「」。我知道這不是處理這個問題的最好方法,它是使它在我們的案例中工作的唯一方法。 – Artem