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

时间:2022-10-30 23:23:24

I'm relative new to the webservices world and my research seems to have confused me more than enlighten me, my problem is that I was given a library(jar) which I have to extend with some webservice functionality.

我对网络服务世界相对较新,我的研究似乎让我困惑不仅仅是启发我,我的问题是我得到了一个库(jar),我必须扩展一些webservice功能。

This library will be shared to other developers, and among the classes in the jar will be classes that have a method which calls a webservice (that essentially sets an attribute of the class, does some business logic, like storing the object in a db, etc and sends back the object with those modifications). I want to make the call to this service as simple as possible, hopefully as simple so that the developer using the class only need to do.

这个库将与其他开发人员共享,并且jar中的类将是具有调用webservice的方法的类(实质上设置类的属性,执行一些业务逻辑,如将对象存储在db中,等,并通过这些修改发回对象)。我希望尽可能简单地调用此服务,希望这样简单,以便开发人员只需要使用该类。

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

I have been studying JAX-WS to use on the server but seems to me that I don't need to create a wsimport in the server nor the wsimport on the client, since I know that both have the classes, I just need some interaction between classes shared in both the server and the client. How do you think makes sense to do the webservice and the call in the class?

我一直在研究在服务器上使用的JAX-WS,但在我看来,我不需要在服务器上创建wsimport,也不需要在客户端上创建wsimport,因为我知道两者都有类,我只需要一些交互在服务器和客户端共享的类之间。您认为在课堂上进行网络服务和通话有何意义?

2 个解决方案

#1


235  

I understand your problem boils down to how to call a SOAP (JAX-WS) web service from Java and get its returning object. In that case, you have two possible approaches:

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

  1. Generate the Java classes through wsimport and use them; or
  2. 通过wsimport生成Java类并使用它们;要么
  3. Create a SOAP client that:
    1. Serializes the service's parameters to XML;
    2. 将服务的参数序列化为XML;
    3. Calls the web method through HTTP manipulation; and
    4. 通过HTTP操作调用web方法;和
    5. Parse the returning XML response back into an object.
    6. 将返回的XML响应解析回对象。
  4. 创建一个SOAP客户端:将服务的参数序列化为XML;通过HTTP操作调用web方法;并将返回的XML响应解析回对象。


About the first approach (using wsimport):

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

I see you already have the services' (entities or other) business classes, and it's a fact that the wsimport generates a whole new set of classes (that are somehow duplicates of the classes you already have).

我看到你已经拥有了服务'(实体或其他)业务类,并且事实上wsimport生成了一组全新的类(它们在某种程度上与你已经拥有的类重复)。

I'm afraid, though, in this scenario, you can only either:

但我担心,在这种情况下,你只能:

  • Adapt (edit) the wsimport generated code to make it use your business classes (this is difficult and somehow not worth it - bear in mind everytime the WSDL changes, you'll have to regenerate and readapt the code); or
  • 调整(编辑)wsimport生成的代码以使其使用您的业务类(这很难并且不知何故不值得 - 记住每次WSDL更改时,您都必须重新生成并重新编写代码);要么
  • Give up and use the wsimport generated classes. (In this solution, you business code could "use" the generated classes as a service from another architectural layer.)
  • 放弃并使用wsimport生成的类。 (在此解决方案中,业务代码可以将生成的类“用作”来自另一个体系结构层的服务。)

About the second approach (create your custom SOAP client):

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

In order to implement the second approach, you'll have to:

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

  1. Make the call:
    • Use the SAAJ (SOAP with Attachments API for Java) framework (see below, it's shipped with Java SE 1.6 or above) to make the calls; or
    • 使用SAAJ(SOAP with Attachments API for Java)框架(见下文,Java SE 1.6或更高版本附带)进行调用;要么
    • You can also do it through java.net.HttpUrlconnection (and some java.io handling).
    • 您也可以通过java.net.HttpUrlconnection(以及一些java.io处理)来完成。
  2. 拨打电话:使用SAAJ(SOAP with Attachments API for Java)框架(见下文,Java SE 1.6或更高版本附带)进行调用;或者您也可以通过java.net.HttpUrlconnection(以及一些java.io处理)来完成。
  3. Turn the objects into and back from XML:
    • Use an OXM (Object to XML Mapping) framework such as JAXB to serialize/deserialize the XML from/into objects
    • 使用OXM(对象到XML映射)框架(如JAXB)从/向对象序列化/反序列化XML
    • Or, if you must, manually create/parse the XML (this can be the best solution if the received object is only a little bit differente from the sent one).
    • 或者,如果必须,手动创建/解析XML(如果收到的对象与发送的对象有点不同,这可能是最佳解决方案)。
  4. 将对象转换为XML和从XML转回:使用OXM(对象到XML映射)框架(如JAXB)从/向对象序列化/反序列化XML或者,如果必须,手动创建/解析XML(这可能是最好的解决方案,如果收到的对象只与发送的对象有点不同)。

Creating a SOAP client using classic java.net.HttpUrlConnection is not that hard (but not that simple either), and you can find in this link a very good starting code.

使用经典的java.net.HttpUrlConnection创建SOAP客户端并不是那么难(但也不是那么简单),你可以在这个链接中找到一个非常好的起始代码。

I recommend you use the SAAJ framework:

我建议你使用SAAJ框架:

SOAP with Attachments API for Java (SAAJ) is mainly used for dealing directly with SOAP Request/Response messages which happens behind the scenes in any Web Service API. It allows the developers to directly send and receive soap messages instead of using JAX-WS.

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

See below a working example (run it!) of a SOAP web service call using SAAJ. It calls this web service.

请参阅下面的使用SAAJ的SOAP Web服务调用的工作示例(运行它!)。它称之为Web服务。

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;
    }

}

About using JAXB for serializing/deserializing, it is very easy to find information about it. You can start here: http://www.mkyong.com/java/jaxb-hello-world-example/.

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

#2


2  

Or just use Apache CXF's wsdl2java to generate objects you can use.

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

It is included in the binary package you can download from their website. You can simply run a command like this:

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

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

It uses the wsdl to generate objects, which you can use like this (object names are also grabbed from the wsdl, so yours will be different a little):

它使用wsdl生成对象,您可以像这样使用对象(对象名称也可以从wsdl中获取,因此您的对象会有所不同):

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

There is even a Maven plug-in which generates the sources: https://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html

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

Note: If you generate sources using CXF and IDEA, you might want to look at this: https://*.com/a/46812593/840315

注意:如果使用CXF和IDEA生成源,您可能需要查看以下内容:https://*.com/a/46812593/840315

#1


235  

I understand your problem boils down to how to call a SOAP (JAX-WS) web service from Java and get its returning object. In that case, you have two possible approaches:

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

  1. Generate the Java classes through wsimport and use them; or
  2. 通过wsimport生成Java类并使用它们;要么
  3. Create a SOAP client that:
    1. Serializes the service's parameters to XML;
    2. 将服务的参数序列化为XML;
    3. Calls the web method through HTTP manipulation; and
    4. 通过HTTP操作调用web方法;和
    5. Parse the returning XML response back into an object.
    6. 将返回的XML响应解析回对象。
  4. 创建一个SOAP客户端:将服务的参数序列化为XML;通过HTTP操作调用web方法;并将返回的XML响应解析回对象。


About the first approach (using wsimport):

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

I see you already have the services' (entities or other) business classes, and it's a fact that the wsimport generates a whole new set of classes (that are somehow duplicates of the classes you already have).

我看到你已经拥有了服务'(实体或其他)业务类,并且事实上wsimport生成了一组全新的类(它们在某种程度上与你已经拥有的类重复)。

I'm afraid, though, in this scenario, you can only either:

但我担心,在这种情况下,你只能:

  • Adapt (edit) the wsimport generated code to make it use your business classes (this is difficult and somehow not worth it - bear in mind everytime the WSDL changes, you'll have to regenerate and readapt the code); or
  • 调整(编辑)wsimport生成的代码以使其使用您的业务类(这很难并且不知何故不值得 - 记住每次WSDL更改时,您都必须重新生成并重新编写代码);要么
  • Give up and use the wsimport generated classes. (In this solution, you business code could "use" the generated classes as a service from another architectural layer.)
  • 放弃并使用wsimport生成的类。 (在此解决方案中,业务代码可以将生成的类“用作”来自另一个体系结构层的服务。)

About the second approach (create your custom SOAP client):

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

In order to implement the second approach, you'll have to:

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

  1. Make the call:
    • Use the SAAJ (SOAP with Attachments API for Java) framework (see below, it's shipped with Java SE 1.6 or above) to make the calls; or
    • 使用SAAJ(SOAP with Attachments API for Java)框架(见下文,Java SE 1.6或更高版本附带)进行调用;要么
    • You can also do it through java.net.HttpUrlconnection (and some java.io handling).
    • 您也可以通过java.net.HttpUrlconnection(以及一些java.io处理)来完成。
  2. 拨打电话:使用SAAJ(SOAP with Attachments API for Java)框架(见下文,Java SE 1.6或更高版本附带)进行调用;或者您也可以通过java.net.HttpUrlconnection(以及一些java.io处理)来完成。
  3. Turn the objects into and back from XML:
    • Use an OXM (Object to XML Mapping) framework such as JAXB to serialize/deserialize the XML from/into objects
    • 使用OXM(对象到XML映射)框架(如JAXB)从/向对象序列化/反序列化XML
    • Or, if you must, manually create/parse the XML (this can be the best solution if the received object is only a little bit differente from the sent one).
    • 或者,如果必须,手动创建/解析XML(如果收到的对象与发送的对象有点不同,这可能是最佳解决方案)。
  4. 将对象转换为XML和从XML转回:使用OXM(对象到XML映射)框架(如JAXB)从/向对象序列化/反序列化XML或者,如果必须,手动创建/解析XML(这可能是最好的解决方案,如果收到的对象只与发送的对象有点不同)。

Creating a SOAP client using classic java.net.HttpUrlConnection is not that hard (but not that simple either), and you can find in this link a very good starting code.

使用经典的java.net.HttpUrlConnection创建SOAP客户端并不是那么难(但也不是那么简单),你可以在这个链接中找到一个非常好的起始代码。

I recommend you use the SAAJ framework:

我建议你使用SAAJ框架:

SOAP with Attachments API for Java (SAAJ) is mainly used for dealing directly with SOAP Request/Response messages which happens behind the scenes in any Web Service API. It allows the developers to directly send and receive soap messages instead of using JAX-WS.

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

See below a working example (run it!) of a SOAP web service call using SAAJ. It calls this web service.

请参阅下面的使用SAAJ的SOAP Web服务调用的工作示例(运行它!)。它称之为Web服务。

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;
    }

}

About using JAXB for serializing/deserializing, it is very easy to find information about it. You can start here: http://www.mkyong.com/java/jaxb-hello-world-example/.

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

#2


2  

Or just use Apache CXF's wsdl2java to generate objects you can use.

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

It is included in the binary package you can download from their website. You can simply run a command like this:

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

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

It uses the wsdl to generate objects, which you can use like this (object names are also grabbed from the wsdl, so yours will be different a little):

它使用wsdl生成对象,您可以像这样使用对象(对象名称也可以从wsdl中获取,因此您的对象会有所不同):

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

There is even a Maven plug-in which generates the sources: https://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html

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

Note: If you generate sources using CXF and IDEA, you might want to look at this: https://*.com/a/46812593/840315

注意:如果使用CXF和IDEA生成源,您可能需要查看以下内容:https://*.com/a/46812593/840315