簡體   English   中英

用Java構建SOAP客戶端

[英]Building a SOAP client in Java

我想將Java的SOAP API與Jav​​a一起使用,以校准一種方法:

<?xml version="1.0" encoding="utf-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <env:Body>
        <GetReturnAnalysis xmlns="http://www.address.com/integration">
            <entityCode>186D3CAD-0841</entityCode>
        </GetReturnAnalysis>
    </env:Body>
</env:Envelope>

為了做到這一點,我創建了以下類:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "GetReturnAnalysis")
public class GetReturnAnalysisRequest {
  @XmlElement(name = "entityCode")
  protected String entityCode;
  @XmlAttribute(name="xmlns", required = true)
  public final static String xmlns="http://www.address.com/integration";

  public GetReturnAnalysisRequest(String entityCode) {
    this.entityCode = entityCode;
  }

  public GetReturnAnalysisRequest() { }

  public String getEntityCode() {
    return entityCode;
  }

  public void setEntityCode(String entityCode) {
    this.entityCode = entityCode;
  }        
}

並做了以下代碼來構建要發送的消息:

private  SOAPMessage createSOAPRequest(GetReturnAnalysis request) throws SOAPException, JAXBException, IOException, ParserConfigurationException, SAXException {
    MessageFactory messageFactory = MessageFactory.newInstance("SOAP 1.2 Protocol");
    SOAPMessage message = messageFactory.createMessage();
    SOAPPart soapPart = message.getSOAPPart();
    SOAPEnvelope envelope = soapPart.getEnvelope();
    envelope.addNamespaceDeclaration("xsi", "http://www.w3.org/2001/XMLSchema-instance");
    envelope.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema");
    message.getSOAPHeader().detachNode();

    SOAPBody body = envelope.getBody();
    String requestString =  XmlHelper.toOutputString(request);
    Document doc = convertStringToDocument(requestString);
    body.addDocument(doc);
    message.writeTo(System.out);

    message.saveChanges();
    message.writeTo(System.out);


    return message;
  }

(在此代碼中內部調用的方法):

public static <T> String toOutputString(T type) throws IOException {
    Validate.notNull(type, "Java type not defined!");

    try {
      StringWriter os = new StringWriter();
      JAXBContext jaxbContext = JAXBContext.newInstance(type.getClass());
      Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

      // output pretty printed
      jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
      jaxbMarshaller.marshal(type, os);

      System.out.println(os.toString());

      return os.toString();
    } catch (JAXBException e) {
      throw new IOException(e);
    }
  }




private Document convertStringToDocument(String xml) throws SAXException, IOException, ParserConfigurationException {
    return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
  }

以我的觀點,它應該起作用。 但是,它會生成這樣的XML:

<?xml version="1.0" encoding="utf-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <env:Body>
        <GetReturnAnalysis xmlns="">
            <entityCode>186D3CAD-0841</entityCode>
        </GetReturnAnalysis>
    </env:Body>
</env:Envelope>

服務器不接受它,因為它沒有填寫xmlns =“ http://www.address.com/integration”屬性。 我想知道這是否歸因於屬性(xmlns)的名稱...但是,這是服務器期望的名稱,因為它是第三方API,所以我無法更改它。

我也嘗試使它與眾不同,聲明了這樣的類:

  @XmlRootElement(name = "GetReturnAnalysis", namespace = "http://www.address.com/integration")
  public class GetReturnAnalysisRequest { ...

但是,當我添加到消息中(body.addDocument方法)時,它會檢索到錯誤(那里不應該有名稱空間)。

您可能已經注意到,在代碼上,我放置了兩個message.writeTo(用於調試,位於createSOAPRequest方法上)。 第一個正確地給了我XML,第二個正確地給了我XML,在我調用“保存”之后,我在GetReturnAnalysis上得到了xmlns屬性為空的xml。

我想知道您是否可以幫助我。 我是SOAP的新手,在這個問題上遇到了很多麻煩...

更新1

我已經使用郵遞員成功發送了以下XML消息:

<?xml version="1.0" encoding="utf-8"?>
<env:Envelope xmlns="http://www.address.com/integration" xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <env:Body>
        <GetReturnAnalysis >
            <entityCode>186D3CAD-0841</entityCode>
        </GetReturnAnalysis>
    </env:Body>
</env:Envelope>

所以我對代碼做了一些小的更改,更改了類

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "GetReturnAnalysis")
public class GetReturnAnalysisRequest {
  @XmlElement(name = "entityCode")
  protected String entityCode;

  public GetReturnAnalysisRequest(String entityCode) {
    this.entityCode = entityCode;
  }

  public GetReturnAnalysisRequest() { }

  public String getEntityCode() {
    return entityCode;
  }

  public void setEntityCode(String entityCode) {
    this.entityCode = entityCode;
  }        
}

和create SOAP request方法:

private  SOAPMessage createSOAPRequest(GetReturnAnalysis request) throws SOAPException, JAXBException, IOException, ParserConfigurationException, SAXException {
    MessageFactory messageFactory = MessageFactory.newInstance("SOAP 1.2 Protocol");
    SOAPMessage message = messageFactory.createMessage();
    SOAPPart soapPart = message.getSOAPPart();
    SOAPEnvelope envelope = soapPart.getEnvelope();
    envelope.addNamespaceDeclaration("", "http://www.address.com/integration");
    envelope.addNamespaceDeclaration("xsi", "http://www.w3.org/2001/XMLSchema-instance");
    envelope.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema");
    message.getSOAPHeader().detachNode();

    SOAPBody body = envelope.getBody();
    String requestString =  XmlHelper.toOutputString(request);
    Document doc = convertStringToDocument(requestString);
    body.addDocument(doc);
    message.writeTo(System.out);

    message.saveChanges();
    message.writeTo(System.out);    

    return message;
  }

但是,由於某些不確定的原因,當我調用message.saveChanges時,GetReturnAnalysis類最終如下所示:

<GetReturnAnalysis xmlns="">
    <EntityCode>186D3CAD-0841</EntityCode>
</GetReturnAnalysis>ityCode>

並且空的xmlns屬性將覆蓋我提供的整體名稱空間。 我想知道為什么會這樣嗎? 它不能簡單地保存我想要保存的字符串,而無需更改嗎?

您的代碼中有幾個問題

命名空間定義:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "GetReturnAnalysis", namespace = "http://www.address.com/integration")
public class GetReturnAnalysisRequest {
  @XmlElement(name = "entityCode", namespace = "http://www.address.com/integration")
  protected String entityCode;

  public GetReturnAnalysisRequest(String entityCode) {
    this.entityCode = entityCode;
  }

  public GetReturnAnalysisRequest() { }

  public String getEntityCode() {
    return entityCode;
  }

  public void setEntityCode(String entityCode) {
    this.entityCode = entityCode;
  }   
}

第二-將文檔構建器設置為名稱空間感知

String requestString =  toOutputString(request);

Document doc = convertStringToDocument(requestString);
body.addDocument(doc);
message.writeTo(System.out);

--

private Document convertStringToDocument(String xml) throws SAXException, IOException, ParserConfigurationException {
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        docFactory.setNamespaceAware(true);
    return docFactory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
  }

使用框架

要真正使用Web服務,您應該使用框架。 我建議使用CXF (我的首選)或Axis2 然后,您可以定義服務接口並生成正確的wsdl和客戶端類,並且獲得對其他可選協議和擴展(例如安全性)的支持。

直接處理XML我僅在特殊情況下建議使用,例如RPC文字,自定義安全性或其他不再受支持的協議。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM