Invocare un servizio Web SOAP in Java

1. Panoramica

In questo tutorial, impareremo come creare un client SOAP in Java con JAX-WS RI . Innanzitutto, genereremo il codice client utilizzando l' utilità wsimport , quindi lo testeremo utilizzando una JUnit.

Per coloro che iniziano, la nostra introduzione a JAX-WS fornisce un ottimo background sull'argomento.

2. Il servizio Web

Prima di iniziare a creare un client, abbiamo bisogno di un server. In questo caso, un server che espone un servizio web JAX-WS.

Ai fini di questo tutorial, utilizzeremo un servizio web che ci recupererà i dati di un paese, dato il suo nome.

2.1. Riepilogo dell'attuazione

Poiché ci stiamo concentrando sulla creazione del cliente, non entreremo nei dettagli di implementazione del nostro servizio.

Basti pensare che un'interfaccia CountryService viene utilizzata per esporre il servizio web al mondo esterno. Per semplificare le cose, creeremo e distribuiremo il servizio Web utilizzando l' API javax.xml.ws.Endpoint nella nostra classe CountryServicePublisher .

Eseguiremo CountryServicePublisher come applicazione Java per pubblicare un endpoint che accetterà le richieste in arrivo. In altre parole, questo sarà il nostro server.

Dopo aver avviato il server, premendo l'URL // localhost: 8888 / ws / country? Wsdl ci fornisce il file di descrizione del servizio web. Il WSDL funge da guida per comprendere le offerte del servizio e generare il codice di implementazione per il client.

2.2. Il linguaggio di descrizione dei servizi Web

Diamo un'occhiata al WSDL del nostro servizio web, paese :


    

In poche parole, queste sono le informazioni utili che fornisce:

  • possiamo invocare il metodo findByName con un argomento stringa
  • in risposta, il servizio ci restituirà un tipo di paese personalizzato
  • i tipi sono definiti in uno schema xsd generato nella posizione // localhost: 8888 / ws / country? xsd = 1 :

    

È tutto ciò di cui abbiamo bisogno per implementare un client.

Vediamo come nella prossima sezione.

3. Utilizzo di wsimport per generare il codice client

3.1. Plugin Maven

Innanzitutto, aggiungiamo un plug-in al nostro pom.xml per utilizzare questo strumento tramite 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  

Secondo, eseguiamo questo plugin:

mvn clean jaxws:wsimport

È tutto! Il comando precedente genererà il codice nel pacchetto specificato com.baeldung.soap.ws.client.generated all'interno di sourceDestDir che abbiamo fornito nella configurazione del plugin.

Un altro modo per ottenere lo stesso risultato sarebbe utilizzare l' utilità wsimport . Viene fornito con la distribuzione standard JDK 8 e può essere trovato nella directory JAVA_HOME / bin .

Per generare il codice client utilizzando wsimport , possiamo accedere alla radice del progetto ed eseguire questo comando:

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

È importante tenere presente che l'endpoint del servizio dovrebbe essere disponibile per eseguire correttamente il plug-in o il comando.

Successivamente, esaminiamo gli artefatti generati.

3.2. POJO generati

Sulla base dell'xsd che abbiamo visto in precedenza, lo strumento genererà un file denominato 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 }

Come possiamo vedere, la classe generata è decorata con annotazioni JAXB per il marshalling e l'unmarshalling dell'oggetto da e verso XML.

Inoltre, genera un'enumerazione di valuta :

@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. CountryService

Il secondo artefatto generato è un'interfaccia che funge da proxy per il servizio Web effettivo.

L'interfaccia CountryService dichiara lo stesso metodo del nostro server, 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); }

In particolare, l'interfaccia è contrassegnata come javax.jws.WebService , con SOAPBinding.Style come RPC come definito dal WSDL del servizio.

Il metodo findByName è annotato per dichiarare che è un javax.jws.WebMethod , con i suoi tipi di parametri di input e output previsti.

3.4. CountryServiceImplService

La nostra classe successiva generata, CountryServiceImplService , estende javax.xml.ws.Service. La sua annotazione WebServiceClient denota che è la visualizzazione client di un servizio:

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

Il metodo importante da notare qui è getCountryServiceImplPort . Dato un nome completo dell'endpoint del servizio, o QName , e il nome dell'interfaccia dell'endpoint del servizio del proxy dinamico, restituisce un'istanza del proxy.

Per richiamare il servizio web, dobbiamo utilizzare questo proxy, come vedremo a breve .

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

Come possiamo vedere, invocare i metodi del servizio remoto è diventato semplice come chiamare i metodi localmente. Il metodo findByName del proxy ha restituito un'istanza Country corrispondente al nome fornito. Quindi, abbiamo utilizzato vari getter del POJO per affermare i valori attesi.

5. conclusione

In questo tutorial, abbiamo visto come richiamare un servizio Web SOAP in Java utilizzando JAX-WS RI e l' utilità wsimport .

In alternativa, possiamo utilizzare altre implementazioni JAX-WS come Apache CXF, Apache Axis2 e Spring per fare lo stesso.

Come sempre, il codice sorgente è disponibile su GitHub.