116 votes

Comment faire un appel à un service Web SOAP à partir d'une classe Java ?

Je suis relativement nouveau dans le monde des webservices et mes recherches semblent m'avoir plus embrouillé qu'éclairé. Mon problème est qu'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, et parmi les classes dans le jar, il y aura des classes qui ont une méthode qui appelle un webservice (qui essentiellement définit un attribut de la classe, fait un peu de logique d'entreprise, comme stocker l'objet dans un db, etc et renvoie l'objet avec ces modifications). Je veux que l'appel à ce service soit aussi simple que possible, en espérant qu'il soit aussi simple que le développeur qui utilise la classe n'ait qu'à le faire.

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

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

0 votes

Votre question est un peu floue. La méthode que vous voulez créer (1) récupère l'objet du service Web, (2) travaille un peu avec l'objet et (3) le renvoie au service Web. Est-ce bien cela ?

0 votes

Non, l'objet sera créé dans le client, il sera envoyé au ws dans l'appel, le ws va définir une variable, par exemple currentTime, faire un peu de logique d'entreprise comme le stocker dans un db, et puis renvoyer l'objet au client avec le currentTime maintenant défini. J'espère que je me suis un peu mieux expliqué. Merci.

277voto

acdcjunior Points 19898

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

  1. Générer les classes Java par wsimport et les utiliser ; ou
  2. Créer un client SOAP qui :
    1. Sérialise les paramètres du service en XML ;
    2. appelle la méthode Web par une manipulation HTTP ; et
    3. Analyse la réponse XML retournée dans un objet.

Concernant la première approche (utilisant wsimport ) :

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

J'ai peur, cependant, que dans ce scénario, vous ne pouvez que soit :

  • Adapter (modifier) le wsimport pour que le code généré utilise votre les classes d'affaires (c'est difficile et cela n'en vaut pas la peine - n'oubliez pas qu'à chaque fois que la WSDL change, vous devrez régénérer et réadapter le code) ; ou
  • Abandonnez et utilisez le wsimport classes générées. (Dans cette solution, votre code métier pourrait "utiliser" les classes générées comme un service d'une autre couche architecturale).

Concernant la deuxième approche (créer votre client SOAP personnalisé) :

Afin de mettre en œuvre la deuxième approche, vous devrez :

  1. Passez l'appel :
    • Utilisez le cadre SAAJ (SOAP with Attachments API for Java) (voir ci-dessous, il est livré avec Java SE 1.6 ou supérieur) pour effectuer les appels ; ou
    • Vous pouvez également le faire par le biais de java.net.HttpUrlconnection (et quelques java.io manipulation).
  2. Transformez les objets en XML et inversement :
    • Utiliser un cadre OXM (Object to XML Mapping) tel que JAXB pour sérialiser/désérialiser le XML à partir de/vers des objets.
    • Ou, si vous le devez, créez/analysez manuellement le XML (cela peut être la meilleure solution si l'objet reçu ne diffère que très peu de l'objet envoyé).

Création d'un client SOAP à l'aide de classic java.net.HttpUrlConnection n'est pas si difficile (mais pas si simple non plus), et vous pouvez trouver en ce lien un très bon code de départ.

Je vous recommande d'utiliser le cadre SAAJ :

SOAP avec API de pièces jointes pour Java (SAAJ) est principalement utilisé pour traiter directement les messages de demande/réponse SOAP qui se produisent dans les coulisses de toute 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 fonctionnel (exécutez-le !) d'un appel de service web SOAP utilisant 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;
    }

}

En ce qui concerne 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/ .

0 votes

Comment puis-je définir la version du savon en utilisant la méthode mentionnée ci-dessus ?

0 votes

J'ai pu utiliser votre méthode et cela a fonctionné lorsque j'ai utilisé votre URI, mais pour ma propre requête SOAP, j'obtiens une réponse dans laquelle aucune des valeurs n'est affichée comme prévu, à savoir <xsd:element name="Incident_Number" type="xsd:string"/> . Comme vous pouvez le constater, l'élément est fermé et aucune information n'est générée par le WS.

0 votes

Le site GetInfoByCity est 503Service Unavailable il semble. :(

3voto

appl3r Points 817

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

Il est inclus dans le paquet binaire que vous pouvez télécharger depuis leur site web. Vous pouvez simplement exécuter une commande comme celle-ci :

$ ./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 suit ce (les noms des objets sont également extraits du wsdl, les vôtres seront donc légèrement différents) :

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 jeter un coup d'œil à ceci : https://stackoverflow.com/a/46812593/840315

1 votes

J'ai plus de 30 wsdl dans mon application. En préparant les ressources pour un seul wsdl (qui a 5 soapActions), mon IDE Eclipse s'est arrêté et a généré environ 100+ MB de classes/objets.

1voto

mel3kings Points 1201

J'ai trouvé un moyen alternatif beaucoup plus simple de générer un message de type soap. Étant donné un objet Personne :

import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class Person {
  private String name;
  private int age;
  private String address; //setter and getters below
}

Vous trouverez ci-dessous un simple générateur de messages Soap :

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

@Slf4j
public class SoapGenerator {

  protected static final ObjectMapper XML_MAPPER = new XmlMapper()
      .enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)
      .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
      .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
      .registerModule(new JavaTimeModule());

  private static final String SOAP_BODY_OPEN = "<soap:Body>";
  private static final String SOAP_BODY_CLOSE = "</soap:Body>";
  private static final String SOAP_ENVELOPE_OPEN = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">";
  private static final String SOAP_ENVELOPE_CLOSE = "</soap:Envelope>";

  public static String soapWrap(String xml) {
    return SOAP_ENVELOPE_OPEN + SOAP_BODY_OPEN + xml + SOAP_BODY_CLOSE + SOAP_ENVELOPE_CLOSE;
  }

  public static String soapUnwrap(String xml) {
    return StringUtils.substringBetween(xml, SOAP_BODY_OPEN, SOAP_BODY_CLOSE);
  }
}

Vous pouvez utiliser par :

 public static void main(String[] args) throws Exception{
        Person p = new Person();
        p.setName("Test");
        p.setAge(12);

        String xml = SoapGenerator.soapWrap(XML_MAPPER.writeValueAsString(p));
        log.info("Generated String");
        log.info(xml);
      }

0voto

Ajay Points 754

Cela pourrait être utile pour quelqu'un qui a une requête xml sous forme de chaîne. Si vous avez WSDL, vous pouvez créer une nouvelle requête soap dans SoapUI avec ce fichier WSDL.
Il génère automatiquement la Structure/XML pour la demande d'entrée.

Voici une version simple du code Java que vous pouvez utiliser pour appeler le service Soap si vous avez la demande d'entrée xml de SoapUI :

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class SimpleSoapClient {

public static void main(String args[]) throws IOException {

    String address="Hyderabad";

    /* place your xml request from soap ui below with necessary changes in parameters*/

    String xml="<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ws=\"http://www.YourUrlAsPerWsdl.com/\">\r\n" + 
                 "   <soapenv:Header/>\r\n" + 
                 "   <soapenv:Body>\r\n" + 
                 "      <ws:callRest>\r\n" + 
                 "         <name>"+"Hello"+"</name>\r\n" + 
                 "         <address>"+address+"</address>\r\n" + 
                 "      </ws:callRest>\r\n" + 
                 "   </soapenv:Body>\r\n" + 
                 "</soapenv:Envelope>";
            String responseF=callSoapService(xml);
            System.out.println(responseF);
    }

}

static String callSoapService(String soapRequest) {
    try {
     String url = "https://gogle.com/service/hello"; // replace your URL here
     URL obj = new URL(url);
     HttpURLConnection con = (HttpURLConnection) obj.openConnection();

     // change these values as per soapui request on top left of request, click on RAW, you will find all the headers
     con.setRequestMethod("POST");
     con.setRequestProperty("Content-Type","text/xml; charset=utf-8"); 
     con.setDoOutput(true);
     DataOutputStream wr = new DataOutputStream(con.getOutputStream());
     wr.writeBytes(soapRequest);
     wr.flush();
     wr.close();
     String responseStatus = con.getResponseMessage();
     System.out.println(responseStatus);
     BufferedReader in = new BufferedReader(new InputStreamReader(
     con.getInputStream()));
     String inputLine;
     StringBuffer response = new StringBuffer();
     while ((inputLine = in.readLine()) != null) {
         response.append(inputLine);
     }
     in.close();

     // You can play with response which is available as string now:
     String finalvalue= response.toString();

     // or you can parse/substring the required tag from response as below based your response code
     finalvalue= finalvalue.substring(finalvalue.indexOf("<response>")+10,finalvalue.indexOf("</response>")); */

     return finalvalue;
     } 
    catch (Exception e) {
        return e.getMessage();
    }   
}

}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X