Appel d'un service Web SOAP en Java

1. Vue d'ensemble

Dans ce didacticiel, nous allons apprendre à créer un client SOAP en Java avec JAX-WS RI . Tout d'abord, nous allons générer le code client à l'aide de l' utilitaire wsimport , puis le tester à l'aide d'un JUnit.

Pour ceux qui débutent, notre introduction à JAX-WS fournit une excellente base sur le sujet.

2. Le service Web

Avant de commencer à créer un client, nous avons besoin d'un serveur. Dans ce cas, un serveur exposant un service Web JAX-WS.

Pour les besoins de ce tutoriel, nous utiliserons un service Web qui nous récupérera les données d'un pays, compte tenu de son nom.

2.1. Résumé de la mise en œuvre

Puisque nous nous concentrons sur la construction du client, nous n'entrerons pas dans les détails de mise en œuvre de notre service.

Disons simplement qu'une interface CountryService est utilisée pour exposer le service web au monde extérieur. Pour simplifier les choses, nous allons créer et déployer le service Web à l'aide de l' API javax.xml.ws.Endpoint dans notre classe CountryServicePublisher .

Nous exécuterons CountryServicePublisher en tant qu'application Java pour publier un point de terminaison qui acceptera les demandes entrantes. En d'autres termes, ce sera notre serveur.

Après avoir démarré le serveur, frapper l'URL // localhost: 8888 / ws / country? Wsdl nous donne le fichier de description du service Web. Le WSDL sert de guide pour comprendre les offres du service et générer un code d'implémentation pour le client.

2.2. Le langage de description des services Web

Regardons le WSDL de notre service Web, pays :


    

En un mot, voici les informations utiles qu'il fournit:

  • on peut invoquer la méthode findByName avec un argument string
  • en réponse, le service nous retournera un type de pays personnalisé
  • les types sont définis dans un schéma xsd généré à l'emplacement // localhost: 8888 / ws / country? xsd = 1 :

    

C'est tout ce dont nous avons besoin pour implémenter un client.

Voyons comment dans la section suivante.

3. Utilisation de wsimport pour générer le code client

3.1. Plugin Maven

Tout d'abord, ajoutons un plugin à notre pom.xml pour utiliser cet outil via Maven:

 org.codehaus.mojo jaxws-maven-plugin 2.6   wsimport-from-jdk  wsimport      //localhost:8888/ws/country?wsdl  true com.baeldung.soap.ws.client.generated src/main/java  

Deuxièmement, exécutons ce plugin:

mvn clean jaxws:wsimport

C'est tout! La commande ci-dessus générera du code dans le package spécifié com.baeldung.soap.ws.client.generated dans le sourceDestDir que nous avons fourni dans la configuration du plugin.

Une autre façon d'obtenir la même chose serait d'utiliser l' utilitaire wsimport . Il est livré avec la distribution standard JDK 8 et se trouve dans le répertoire JAVA_HOME / bin .

Pour générer du code client à l'aide de wsimport , nous pouvons accéder à la racine du projet et exécuter cette commande:

JAVA_HOME/bin/wsimport -s src/main/java/ -keep -p com.baeldung.soap.ws.client.generated "//localhost:8888/ws/country?wsdl"

Il est important de garder à l'esprit que le point de terminaison du service doit être disponible afin d'exécuter avec succès le plugin ou la commande.

Ensuite, regardons les artefacts générés.

3.2. POJO générés

Sur la base du xsd que nous avons vu précédemment, l'outil générera un fichier nommé Country.java :

@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "country", propOrder = { "capital", "currency", "name", "population" }) public class Country { protected String capital; @XmlSchemaType(name = "string") protected Currency currency; protected String name; protected int population; // standard getters and setters }

Comme nous pouvons le voir, la classe générée est décorée d'annotations JAXB pour le marshalling et le démarshalling de l'objet vers et depuis XML.

En outre, il génère une énumération de devises :

@XmlType(name = "currency") @XmlEnum public enum Currency { EUR, INR, USD; public String value() { return name(); } public static Currency fromValue(String v) { return valueOf(v); } }

3.3. PaysService

Le deuxième artefact généré est une interface qui agit comme un proxy pour le service Web réel.

L'interface CountryService déclare la même méthode que notre serveur, findByName :

@WebService(name = "CountryService", targetNamespace = "//server.ws.soap.baeldung.com/") @SOAPBinding(style = SOAPBinding.Style.RPC) @XmlSeeAlso({ ObjectFactory.class }) public interface CountryService { @WebMethod @WebResult(partName = "return") @Action(input = "//server.ws.soap.baeldung.com/CountryService/findByNameRequest", output = "//server.ws.soap.baeldung.com/CountryService/findByNameResponse") public Country findByName(@WebParam(name = "arg0", partName = "arg0") String arg0); }

Notamment, l'interface est marquée comme un javax.jws.WebService , avec un SOAPBinding.Style comme RPC tel que défini par le WSDL du service.

La méthode findByName est annotée pour déclarer qu'il s'agit d'un javax.jws.WebMethod , avec ses types de paramètres d'entrée et de sortie attendus.

3.4. CountryServiceImplService

Notre prochaine classe générée, CountryServiceImplService , étend javax.xml.ws.Service. Son annotation WebServiceClient indique qu'il s'agit de la vue client d'un service:

@WebServiceClient(name = "CountryServiceImplService", targetNamespace = "//server.ws.soap.baeldung.com/", wsdlLocation = "//localhost:8888/ws/country?wsdl") public class CountryServiceImplService extends Service { private final static URL COUNTRYSERVICEIMPLSERVICE_WSDL_LOCATION; private final static WebServiceException COUNTRYSERVICEIMPLSERVICE_EXCEPTION; private final static QName COUNTRYSERVICEIMPLSERVICE_QNAME = new QName("//server.ws.soap.baeldung.com/", "CountryServiceImplService"); static { URL url = null; WebServiceException e = null; try { url = new URL("//localhost:8888/ws/country?wsdl"); } catch (MalformedURLException ex) { e = new WebServiceException(ex); } COUNTRYSERVICEIMPLSERVICE_WSDL_LOCATION = url; COUNTRYSERVICEIMPLSERVICE_EXCEPTION = e; } public CountryServiceImplService() { super(__getWsdlLocation(), COUNTRYSERVICEIMPLSERVICE_QNAME); } // other constructors @WebEndpoint(name = "CountryServiceImplPort") public CountryService getCountryServiceImplPort() { return super.getPort(new QName("//server.ws.soap.baeldung.com/", "CountryServiceImplPort"), CountryService.class); } private static URL __getWsdlLocation() { if (COUNTRYSERVICEIMPLSERVICE_EXCEPTION != null) { throw COUNTRYSERVICEIMPLSERVICE_EXCEPTION; } return COUNTRYSERVICEIMPLSERVICE_WSDL_LOCATION; } }

La méthode importante à noter ici est getCountryServiceImplPort . Étant donné un nom qualifié du point de terminaison de service, ou QName , et le nom d'interface de point de terminaison de service du proxy dynamique, il renvoie une instance de proxy.

Pour appeler le service Web, nous devons utiliser ce proxy, comme nous le verrons bientôt .

Using a proxy makes it seem as if we are calling a service locally, abstracting away the intricacies of remote invocation.

4. Testing the Client

Next, we'll write a JUnit test to connect to the web service using the generated client code.

Before we can do that, we need to get the service's proxy instance at the client end:

@BeforeClass public static void setup() { CountryServiceImplService service = new CountryServiceImplService(); CountryService countryService = service.getCountryServiceImplPort(); }

For more advanced scenarios such as enabling or disabling a WebServiceFeature, we can use other generated constructors for CountryServiceImplService.

Now let's look at some tests:

@Test public void givenCountryService_whenCountryIndia_thenCapitalIsNewDelhi() { assertEquals("New Delhi", countryService.findByName("India").getCapital()); } @Test public void givenCountryService_whenCountryFrance_thenPopulationCorrect() { assertEquals(66710000, countryService.findByName("France").getPopulation()); } @Test public void givenCountryService_whenCountryUSA_thenCurrencyUSD() { assertEquals(Currency.USD, countryService.findByName("USA").getCurrency()); } 

Comme nous pouvons le voir, appeler les méthodes du service distant est devenu aussi simple que d'appeler des méthodes localement. La méthode findByName du proxy a renvoyé une instance Country correspondant au nom que nous avons fourni. Ensuite, nous avons utilisé divers getters du POJO pour affirmer les valeurs attendues.

5. Conclusion

Dans ce didacticiel, nous avons vu comment appeler un service Web SOAP en Java à l'aide de JAX-WS RI et de l' utilitaire wsimport .

Alternativement, nous pouvons utiliser d'autres implémentations JAX-WS telles que Apache CXF, Apache Axis2 et Spring pour faire de même.

Comme toujours, le code source est disponible sur sur GitHub.