Webservices in Java SE, deel 2: SOAP-webservices maken

JAX-WS ondersteunt op SOAP gebaseerde webservices. Deel 2 van deze vierdelige serie over Java SE-webservices definieert een op SOAP gebaseerde webservice voor eenhedenconversie, bouwt en verifieert deze webservice lokaal via de standaard lichtgewicht HTTP-server (besproken in deel 1), interpreteert het WSDL-document van de service , en heeft toegang tot de service vanaf een eenvoudige client.

Een webservice voor eenhedenconversie definiëren

De webservice voor eenhedenconversie, die ik UC heb genoemd, bestaat uit vier functies voor het omrekenen tussen centimeters en inches en tussen graden Fahrenheit en graden Celsius. Hoewel dit voorbeeld kan worden ontworpen als een enkele Java-klasse, heb ik ervoor gekozen om de beste praktijken te volgen door het te ontwerpen als een Java-interface en een Java-klasse. Lijst 1 presenteert de UCinterface van de webservice .

Lijst 1. De service-eindpuntinterface van de UC-webservice

package ca.javajeff.uc; import javax.jws.WebMethod; import javax.jws.WebService; @WebService public interface UC { @WebMethod double c2f(double degrees); @WebMethod double cm2in(double cm); @WebMethod double f2c(double degrees); @WebMethod double in2cm(double in); }

UCbeschrijft een Service Endpoint Interface (SEI) , een Java-interface die de bewerkingen van een webservice-interface blootlegt in termen van abstracte Java-methoden. Cliënten communiceren met op SOAP gebaseerde webservices via hun SEI's.

UCwordt via de @WebServiceannotatie als een SEI verklaard . Wanneer een Java-interface of -klasse is geannoteerd @WebService, volgen alle publicmethoden waarvan de parameters, retourwaarden en gedeclareerde uitzonderingen de regels bevatten die zijn gedefinieerd in Sectie 5 van de JAX-RPC 1.1-specificatie, die webservicebewerkingen beschrijven. Want alleen publicmethoden in interfaces kunnen worden verklaard, het publicgereserveerd woord is niet nodig wanneer verklaren c2f(), cm2in(), f2c(), en in2cm(). Deze methoden zijn impliciet public.

Elke methode is ook geannoteerd @WebMethod. Hoewel het @WebMethodin dit voorbeeld niet essentieel is, versterkt de aanwezigheid ervan het feit dat de geannoteerde methode een webservicebewerking blootlegt.

Listing 2 presenteert de UCImplklasse van de webservice .

Lijst 2. De service-implementatieboon van de UC-webservice

package ca.javajeff.uc; import javax.jws.WebService; @WebService(endpointInterface = "ca.javajeff.uc.UC") public class UCImpl implements UC { @Override public double c2f(double degrees) { return degrees * 9.0 / 5.0 + 32; } @Override public double cm2in(double cm) { return cm / 2.54; } @Override public double f2c(double degrees) { return (degrees - 32) * 5.0 / 9.0; } @Override public double in2cm(double in) { return in * 2.54; } }

UCImplbeschrijft een Service Implementation Bean (SIB) , die zorgt voor een implementatie van de SEI. Deze klasse wordt via de @WebService(endpointInterface = "ca.javajeff.uc.UC")annotatie tot SIB verklaard . Het endpointInterfaceelement verbindt deze SIB met zijn SEI en is nodig om ongedefinieerde poorttypefouten te vermijden bij het uitvoeren van de later gepresenteerde clienttoepassing.

De implements UCclausule is niet absoluut noodzakelijk. Als deze clausule niet aanwezig is, wordt de UCinterface genegeerd (en is deze redundant). Het is echter een goed idee om te behouden, implements UCzodat de compiler kan verifiëren dat de methoden van de SEI zijn geïmplementeerd in de SIB.

De methodekoppen van de SIB worden niet geannoteerd @WebMethodomdat deze annotatie doorgaans wordt gebruikt in de context van de SEI. Als u echter een publicmethode zou toevoegen (die voldoet aan de regels in Sectie 5 van de JAX-RPC 1.1-specificatie) aan de SIB, en als deze methode geen webservicebewerking blootlegt, zou u de koptekst van de methode annoteren @WebMethod(exclude = true). Door het toewijzen trueaan @WebMethod's excludeelement voorkomt u deze methode van behoort bij een operatie.

Deze webservice is klaar om te worden gepubliceerd, zodat deze toegankelijk is voor klanten. Listing 3 presenteert een UCPublisherapplicatie die deze taak uitvoert in de context van de standaard lichtgewicht HTTP-server.

Lijst 3. UC publiceren

import javax.xml.ws.Endpoint; import ca.javajeff.uc.UCImpl; public class UCPublisher { public static void main(String[] args) { Endpoint.publish("//localhost:9901/UC", new UCImpl()); } }

Als u de webservice publiceert, moet u één keer de EndPointklassemethode van de Endpoint publish(String address, Object implementor)klas aanroepen. De addressparameter identificeert de URI die aan de webservice is toegewezen. Ik heb ervoor gekozen om deze webservice op de lokale host te publiceren door localhost(equivalent aan IP-adres 127.0.0.1) en poortnummer 9901(dat hoogstwaarschijnlijk beschikbaar is) op te geven. Ik heb ook willekeurig gekozen /UCals het publicatiepad. De implementorparameter identificeert een exemplaar van UC's SIB.

De publish()methode creëert en publiceert een eindpunt voor het opgegeven implementorobject op het opgegeven object address, en gebruikt de implementorannotaties van om Web Services Definition Language (WSDL) en XML Schema-documenten te creëren. Het zorgt ervoor dat de noodzakelijke serverinfrastructuur wordt gemaakt en geconfigureerd door de JAX-WS-implementatie op basis van een standaardconfiguratie. Bovendien zorgt deze methode ervoor dat de toepassing voor onbepaalde tijd wordt uitgevoerd. (Druk op Windows-computers tegelijkertijd op de toetsen Ctrl en C om de toepassing te beëindigen.)

Bouwen en verifiëren van de webservice

Het is niet moeilijk om de eerder gedefinieerde UC-webservice te bouwen. Eerst moet u een geschikte directorystructuur maken met de juiste bestanden. Voer deze taak uit door de volgende stappen uit te voeren:

  1. Maak binnen de huidige directory een cadirectory. Binnen ca, het creëren van een javajeffdirectory. javajeffMaak ten slotte een ucmap aan.
  2. Kopieer listing 1 naar een UC.javabronbestand en sla dit bestand op in ca/javajeff/uc.
  3. Kopieer listing 2 naar een UCImpl.javabronbestand en bewaar dit bestand in ca/javajeff/uc.
  4. Kopieer Listing 3 naar een UCPublisher.javabronbestand en sla dit bestand op in de huidige directory, die de cadirectory bevat .

De volgende taak is om deze bronbestanden te compileren. Ervan uitgaande dat u de mappen niet hebt gewijzigd, voert u de volgende opdracht uit om deze bronbestanden in Java SE 9 te compileren (laat weg --add-modules java.xml.wsin Java SE 6, 7 of 8):

javac --add-modules java.xml.ws UCPublisher.java

Als deze bronbestanden met succes zijn gecompileerd, voert u de volgende opdracht uit om deze toepassing in Java 9 uit te voeren (laat weg --add-modules java.xml.wsin Java SE 6, 7 of 8):

java --add-modules java.xml.ws UCPublisher

Gebruik een webbrowser terwijl de toepassing wordt uitgevoerd om te controleren of deze webservice correct werkt en om toegang te krijgen tot het WSDL-document. Start uw favoriete webbrowser en typ de volgende regel in de adresbalk:

//localhost:9901/UC

Figuur 1 toont de resulterende webpagina in de Google Chrome-webbrowser.

Afbeelding 1. De webpagina van UC biedt gedetailleerde informatie over de gepubliceerde webservice

In afbeelding 1 worden de gekwalificeerde service- en poortnamen van het webservice-eindpunt weergegeven. (Merk op dat de pakketnaam is omgekeerd - in uc.javajeff.caplaats van ca.javajeff.uc). Een klant gebruikt deze namen om toegang te krijgen tot de dienst.

Figuur 1 toont ook de adres-URI van de webservice, de locatie van het WSDL-document van de webservice (de webservice-URI met het achtervoegsel van de ?wsdlquerytekenreeks) en de pakketgekwalificeerde naam van de webservice-implementatieklasse.

Het WSDL-document van de webservice interpreteren

De locatie van het WSDL-document van de UC-webservice wordt als een link weergegeven. Klik op deze link om het WSDL-document te bekijken, waarvan de inhoud wordt gepresenteerd in Listing 4.

Lijst 4. UC's WSDL-document

Een WSDL-document is een XML-document met een definitionsroot-element, waardoor een WSDL-document niets meer is dan een set definities. Dit element bevat verschillende xmlnsattributen voor het identificeren van verschillende standaard naamruimten, samen met targetNameSpaceen nameattributen:

  • Het targetNamespaceattribuut maakt een naamruimte aan voor alle door de gebruiker gedefinieerde elementen in het WSDL-document (zoals het c2felement dat is gedefinieerd via het messageelement met deze naam). Deze naamruimte wordt gebruikt om onderscheid te maken tussen de door de gebruiker gedefinieerde elementen van het huidige WSDL-document en door de gebruiker gedefinieerde elementen van geïmporteerde WSDL-documenten, die worden geïdentificeerd via het WSDL- importelement. Op een vergelijkbare manier creëert het targetNamespaceattribuut dat verschijnt op het schemaelement van een XML-schemabestand een naamruimte voor de door de gebruiker gedefinieerde eenvoudige type-elementen, attribuutelementen en complexe type-elementen.
  • Het namekenmerk identificeert de webservice en wordt alleen gebruikt om de service te documenteren.

Genest binnen definitionszijn types, message, portType, binding, en serviceelementen: