如何从Java类执行SOAP Web服务调用?

问题描述:

我对Web服务世界相对陌生,我的研究似乎让我困惑得比开导我多,我的问题是我得到了一个库(jar),我必须使用一些web服务功能来扩展它。如何从Java类执行SOAP Web服务调用?

这个库将被其他开发者共享,并且在jar中的类中将会有一些类,这些类有一个调用webservice的方法(基本上设置类的属性,做一些业务逻辑,比如存储对象在一个数据库等,并发送对象与这些修改)。我希望尽可能简单地调用此服务,希望尽可能简单,以便使用该类的开发人员只需要这样做。

Car c = new Car("Blue"); 
c.webmethod(); 

我一直在研究JAX-WS服务器上使用,但在我看来,我不需要在服务器中创建一个wsimport,也不在客户端上wsimport,因为我知道,无论有类,我只需要在服务器和客户端共享的类之间进行一些交互。您认为在课堂上进行web服务和调用有意义吗?

+0

你的问题有点不清楚。你想创建的方法将(1)从Web服务获取对象; (2)与对象一起工作;和(3)将其发回Web服务。是吗? – acdcjunior 2013-04-11 03:36:28

+0

不,对象将在客户端创建,它将被发送到调用中的ws,ws将设置一个变量,例如currentTime,执行一些业务逻辑,如将其存储在数据库中,然后发送给将对象返回给客户端并设置currentTime。希望我能更好地解释我的自我。谢谢。 – jpz 2013-04-11 04:57:09

我理解你的问题归结为如何从Java调用SOAP(JAX-WS)Web服务并获取其返回对象。在这种情况下,您有两种可能的方法:

  1. 通过wsimport生成Java类并使用它们;或
  2. 创建SOAP客户端:
    1. 序列化服务的参数,以XML;
    2. 通过HTTP操作调用Web方法;和
    3. 将返回的XML响应解析回对象。


关于(采​​用wsimport)第一种方法:

我看你已经有服务(实体或其他)业务类,这是一个事实,即wsimport产生一整套新的类(它们与你已有的类重复)。

我很害怕,但是,在这种情况下,你只能之一:

  • 适应(编辑)wsimport生成的代码,以使它使用业务类(这是困难的,有点不值得 - 每当WSDL发生变化时记住,你必须重新生成并重新调整代码);或
  • 放弃并使用wsimport生成的类。 (在此解决方案中,您的业务代码可以将生成的类作为另一个架构层的服务使用。)

关于第二个方法(创建自定义的SOAP客户端):

为了实现第二种方法,你必须:

  1. 请来电:
    • 使用SAAJ(SOAP with Attachments API for Java)框架(见下文,它随Java SE 1.6或更高版本提供)进行调用;或
    • 您也可以通过java.net.HttpUrlconnection(和一些java.io处理)来完成。
  2. 转动物体进入和回程从XML:
    • 使用OXM(对象到XML映射)框架,例如JAXB序列化/反序列化从XML /成对象
    • 或者,如果您必须手动创建/解析XML(如果接收的对象与发送的对象只有一点差异,这可能是最好的解决方案)。

创建使用经典java.net.HttpUrlConnection SOAP客户端并不难(但不是简单其一),你可以在this link一个很好的起点代码中找到。

我建议你使用SAAJ框架:

SOAP用于Java(SAAJ)附件API主要用于直接与发生在幕后的任何Web服务的SOAP请求/响应消息处理API。它允许开发人员直接发送和接收SOAP消息,而不是使用JAX-WS。

请参阅下面的使用SAAJ的SOAP Web服务调用的工作示例(运行它!)。它叫this web service

import javax.xml.soap.*; 

public class SOAPClientSAAJ { 

    // SAAJ - SOAP Client Testing 
    public static void main(String args[]) { 
     /* 
      The example below requests from the Web Service at: 
      https://www.w3schools.com/xml/tempconvert.asmx?op=CelsiusToFahrenheit 


      To call other WS, change the parameters below, which are: 
      - the SOAP Endpoint URL (that is, where the service is responding from) 
      - the SOAP Action 

      Also change the contents of the method createSoapEnvelope() in this class. It constructs 
      the inner part of the SOAP envelope that is actually sent. 
     */ 
     String soapEndpointUrl = "https://www.w3schools.com/xml/tempconvert.asmx"; 
     String soapAction = "https://www.w3schools.com/xml/CelsiusToFahrenheit"; 

     callSoapWebService(soapEndpointUrl, soapAction); 
    } 

    private static void createSoapEnvelope(SOAPMessage soapMessage) throws SOAPException { 
     SOAPPart soapPart = soapMessage.getSOAPPart(); 

     String myNamespace = "myNamespace"; 
     String myNamespaceURI = "https://www.w3schools.com/xml/"; 

     // SOAP Envelope 
     SOAPEnvelope envelope = soapPart.getEnvelope(); 
     envelope.addNamespaceDeclaration(myNamespace, myNamespaceURI); 

      /* 
      Constructed SOAP Request Message: 
      <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:myNamespace="https://www.w3schools.com/xml/"> 
       <SOAP-ENV:Header/> 
       <SOAP-ENV:Body> 
        <myNamespace:CelsiusToFahrenheit> 
         <myNamespace:Celsius>100</myNamespace:Celsius> 
        </myNamespace:CelsiusToFahrenheit> 
       </SOAP-ENV:Body> 
      </SOAP-ENV:Envelope> 
      */ 

     // SOAP Body 
     SOAPBody soapBody = envelope.getBody(); 
     SOAPElement soapBodyElem = soapBody.addChildElement("CelsiusToFahrenheit", myNamespace); 
     SOAPElement soapBodyElem1 = soapBodyElem.addChildElement("Celsius", myNamespace); 
     soapBodyElem1.addTextNode("100"); 
    } 

    private static void callSoapWebService(String soapEndpointUrl, String soapAction) { 
     try { 
      // Create SOAP Connection 
      SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance(); 
      SOAPConnection soapConnection = soapConnectionFactory.createConnection(); 

      // Send SOAP Message to SOAP Server 
      SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(soapAction), soapEndpointUrl); 

      // Print the SOAP Response 
      System.out.println("Response SOAP Message:"); 
      soapResponse.writeTo(System.out); 
      System.out.println(); 

      soapConnection.close(); 
     } catch (Exception e) { 
      System.err.println("\nError occurred while sending SOAP Request to Server!\nMake sure you have the correct endpoint URL and SOAPAction!\n"); 
      e.printStackTrace(); 
     } 
    } 

    private static SOAPMessage createSOAPRequest(String soapAction) throws Exception { 
     MessageFactory messageFactory = MessageFactory.newInstance(); 
     SOAPMessage soapMessage = messageFactory.createMessage(); 

     createSoapEnvelope(soapMessage); 

     MimeHeaders headers = soapMessage.getMimeHeaders(); 
     headers.addHeader("SOAPAction", soapAction); 

     soapMessage.saveChanges(); 

     /* Print the request message, just for debugging purposes */ 
     System.out.println("Request SOAP Message:"); 
     soapMessage.writeTo(System.out); 
     System.out.println("\n"); 

     return soapMessage; 
    } 

} 

关于使用JAXB进行序列化/反序列化,很容易找到关于它的信息。你可以从这里开始:http://www.mkyong.com/java/jaxb-hello-world-example/

+0

如何使用上述方法设置肥皂版本? – Redone 2016-10-27 10:37:12

+0

我能够使用你的方法,并且它在我使用你的URI的时候起作用,但是对于我自己的SOAP请求,我得到了一个响应,其中没有显示任何值,即''''。正如你所看到的,元素是关闭的,并且没有信息从WS生成。 – santafebound 2016-11-08 14:45:34

+0

'GetInfoByCity'是'503Service Unavailable',它看起来像。 :( – 2017-08-11 20:44:47

或者只是使用Apache CXF's wsdl2java来生成可以使用的对象。

它包含在二进制包中,您可以从他们的网站下载。你可以简单地运行这样的命令:

$ ./wsdl2java -p com.mynamespace.for.the.api.objects -autoNameResolution http://www.someurl.com/DefaultWebService?wsdl 

它使用WSDL生成对象,你可以使用这样的(对象名称也从WSDL抓起,让你的将是不同的一点):

DefaultWebService defaultWebService = new DefaultWebService(); 
String res = defaultWebService.getDefaultWebServiceHttpSoap11Endpoint().login("webservice","dadsadasdasd"); 
System.out.println(res); 

甚至有一个Maven插件生成来源:https://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html