web-dev-qa-db-fra.com

Comment faire un appel de service Web SOAP à partir de la classe Java?

Je suis relativement nouveau dans le monde des webservices et mes recherches semblent m'avoir dérouté davantage que ne m'éclairer; mon problème est que l'on m'a donné une bibliothèque (jar) que je dois étendre avec certaines fonctionnalités de webservice.

Cette bibliothèque sera partagée avec d'autres développeurs. Parmi les classes du jar, il y aura des classes qui ont une méthode qui appelle un service Web (qui définit essentiellement un attribut de la classe, effectue une certaine logique métier, comme le stockage de l'objet dans une base de données, etc et renvoie l'objet avec ces modifications). Je souhaite que l'appel à ce service soit aussi simple que possible, espérons-le, de manière à ce que le développeur utilisant la classe n'ait qu'à le faire.

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

J'ai étudié JAX-WS à utiliser sur le serveur, mais il me semble que je n'ai pas besoin de créer un wsimport sur le serveur ni le wsimport sur le client, car je sais que les deux ont les classes, j'ai juste besoin d'une certaine interaction entre les classes partagées à la fois sur le serveur et le client. Comment pensez-vous qu'il est logique de faire le service Web et l'appel en classe?

106
jpz

Je comprends que votre problème se résume à comment appeler un service Web SOAP (JAX-WS) à partir de Java et obtenir son objet renvoyé . Dans ce cas, vous avez deux approches possibles:

  1. Générez les classes Java via wsimport et utilisez-les; ou
  2. Créez un client SOAP qui:
    1. Sérialise les paramètres du service en XML;
    2. Appelle la méthode Web via une manipulation HTTP. et
    3. Analyser la réponse XML renvoyée dans un objet.


À propos de la première approche (en utilisant wsimport):

Je vois que vous avez déjà les classes d’entreprise des services (entités ou autres), et c’est un fait que la wsimport génère un tout nouvel ensemble de classes (qui sont en quelque sorte des doubles des classes que vous avez déjà).

J'ai bien peur que dans ce scénario, vous ne puissiez que:

  • Adaptez (éditez) le code généré par wsimport pour lui faire utiliser vos classes d'entreprises (c'est difficile et ne vaut pas la peine en quelque sorte - gardez à l'esprit chaque fois que le WSDL change, vous devrez régénérer et réadapter le code); ou
  • Abandonnez et utilisez les classes wsimport générées. (Dans cette solution, votre code métier pourrait "utiliser" les classes générées en tant que service provenant d'une autre couche architecturale.)

À propos de la deuxième approche (créez votre client personnalisé SOAP):

Pour mettre en œuvre la seconde approche, vous devrez:

  1. Faire l'appel:
    • Utilisez la structure SAAJ (SOAP avec API pour pièces jointes pour Java) (voir ci-dessous, elle est livrée avec Java SE 1.6 ou version ultérieure) pour passer les appels. ou
    • Vous pouvez également le faire via Java.net.HttpUrlconnection (et un certain traitement Java.io.).
  2. Transformez les objets en XML et inversement:
    • Utiliser une infrastructure OXM (Object to XML Mapping) telle que JAXB pour sérialiser/désérialiser le code XML à partir/dans des objets
    • Ou, si vous devez, créer/analyser manuellement le code XML (cela peut être la meilleure solution si l'objet reçu est seulement un peu différent de celui envoyé).

Créer un client SOAP en utilisant le classique Java.net.HttpUrlConnection n'est pas si difficile (mais pas si simple non plus), et vous pouvez trouver dans ce lien un très bon code de départ.

Je vous recommande d'utiliser le framework SAAJ:

SOAP avec API de pièces jointes pour Java (SAAJ) est principalement utilisé pour traiter directement avec SOAP Requête/Réponse messages qui se produisent dans les coulisses de n’importe quelle API de service Web. Il permet aux développeurs d’envoyer et de recevoir directement des messages soap au lieu d’utiliser JAX-WS.

Voir ci-dessous un exemple de travail (lancez-le!) D'un appel de service Web SOAP à l'aide de SAAJ. Il appelle ce service 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;
    }

}

À propos de l’utilisation de JAXB pour la sérialisation/désérialisation, il est très facile de trouver des informations à ce sujet. Vous pouvez commencer ici: http://www.mkyong.com/Java/jaxb-hello-world-example/ .

256
acdcjunior

Ou utilisez simplement wsdl2Java d'Apache CXF pour générer des objets que vous pouvez utiliser.

Il est inclus dans le package binaire que vous pouvez télécharger sur leur site web. Vous pouvez simplement exécuter une commande comme ceci:

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

Il utilise le wsdl pour générer des objets, que vous pouvez utiliser comme this (les noms d’objets sont également saisis dans le wsdl, le vôtre sera donc légèrement différent):

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

Il existe même un plug-in Maven qui génère les sources: https://cxf.Apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-Java.html

Remarque: Si vous générez des sources à l'aide de CXF et IDEA, vous voudrez peut-être examiner ceci: https://stackoverflow.com/a/46812593/840315

4
szab.kel