Dieser Blogbeitrag zeigt wie man mit gängigen Java Frameworks einen einfachen Webservice implementiert. Dabei wird nach dem Ansatz vorgegangen zuerst die Java Klassen statt der WSDL zu entwickeln. Um die Implementierung als Webservice zu deployen und die WSDL automatisch generieren zu können, werden die Java Klassen über Annotations mit den notwendigen Metadaten versehen.
Update: Siehe auch Artikel zur WSDL-First Development.
Das hier beschriebene Beispiel basiert auf Apache CXF 2.0, JSR-181, JAXB 2.1, Spring Framework, sowie Jetty als embedded HTTP Server um den Webservice bereitzustellen.
Der komplette Source Code inklusive einem Maven Build Script steht zum Download bereit.
Schritt 1: Anforderungen aufnehmen, dokumentieren und Schnittstelle entwerfen
Der Start für jeden neuen Webservice sind in der Regel neue Anforderungen aus dem Fachbereich. Diese Anforderungen müssen zunächst einmal aufgenommen und dokumentiert werden. Daraus kann man anschließend eine entsprechende Schnittstelle für den Service entwerfen. In diesem Beispiel wird ein einfacher Service zu Verwaltung von Kunden beschrieben. Das folgende UML-Diagramm zeigt die Schnittstelle des Services sowie die Datenobjekte mit denen der Service arbeitet:
Wie man dem Klassendiagramm entnehmen kann, wird unser Beispiel-Service eine einzige Methode anbieten, die eine Kundenummer als Inputparameter entgegennimmt und einen Kunden als Outputobjekt zurück liefert. Die Serviceschnittstelle wurde für dieses Beispiel natürlich stark vereinfacht.
Schritt 2: Datenstrukturen als Java Klassen implementieren
Die Java Klassen für die Datenstrukturen sind einfache POJOs und enthalten nur die entsprechenden Getter- und Setter-Methoden für die Attribute.
Customer.java
Person.java
Gender.java
Address.java
Schritt 3: Service Interface definieren
Als nächstes muss das Service Interface implementiert werden und mit entsprechenden JSR-181 Annotations versehen werden:
@WebServicepublic interface CustomerService {
@WebMethod(action = "getCustomer")
public Customer getCustomer(String customerNumber)
throws BusinessLogicException;
}
Während die Annotation @WebService unbedingt erforderlich ist, ist die @WebMethod Annotation optional. Für die Nutzung von SOAP over JMS sollte jedoch hier die SOAP-Action angegeben werden.
CustomerService.java
BusinessLogicException.java
Schritt 4: Service Interface implementieren
Die eigentliche Implementierung der Businesslogik findet der Klasse CustomerServiceImpl statt welche das Interface ContactService implementiert:
public class CustomerServiceImpl implements CustomerService {
public Customer getCustomer(String customerNumber)
throws BusinessLogicException {
Customer result = null;
if("12345".equals(customerNumber)) {
Person maxMueller = new Person();
maxMueller.setFirstname("Max");
maxMueller.setLastname("Müller");
maxMueller.setGender(Gender.MALE);
Address maxMuellerAddress = new Address();
maxMuellerAddress.setLine1("Mussterstr. 10");
maxMuellerAddress.setLine2("");
maxMuellerAddress.setPostalCode("12345");
maxMuellerAddress.setCity("Musterhausen");
Customer maxMuellerCustomer = new Customer();
maxMuellerCustomer.setPerson(maxMueller);
maxMuellerCustomer.getAddress().add(maxMuellerAddress);
result = maxMuellerCustomer;
}
throws new BusinessLogicException("No such customer");
}
}
Wie man dem Source-Code entnehmen kann, gibt diese Implementierung immer den Kunden „Max Müller“ als Output zurück wenn die Kundennummer „12345“ als Inputparameter übergeben wurde und in allen anderen Fällen wird ein BusinessLogicException mit entsprechender Fehlermeldung geworfen.
Schritt 5: Object-Factory sowie Request- und Response Klassen implementieren
Apache CXF 2.0 verwendet JAXB als Default-Datamapping. Aus diesem Grund ist es notwendig neben den Datenobjekten auch eine Factory für die Erzeugung der Datenobjekten sowie die Request- und Response Klassen zu implementieren.
ObjectFactory.java
GetCustomerRequest.java
GetCustomerResponse.java
Hierbei ist wichtig, dass die Request- und Response Klassen mit @XmlRootElement Annotation versehen sind.
Schritt 6: Service bereitstellen
In diesem Beispiel wird der Service mit Hilfe von Jetty über HTTP bereitgestellt. Die Konfiguration der Komponenten erfolgt über das Spring Framework. Die Spring Konfiguration ist in diesem Beispiel in der Datei server-applicationContext.xml enthalten.
Über die main-Methode in der Klasse ServiceServer wird der Spring Context initialisiert und somit der Jetty Webcontainer gestartet, welcher die Service Implementierung unter http://localhost:9090/customerService verfügbar macht.
Schritt 7: Client für den Service implementieren
Um den Service anzusprechen und testen zu können, empfiehlt es sich ein Client zu implementieren. Die Implementierung von Clients ist mit Apache CXF 2.0 relativ einfach deklarativ mit Hilfe des Spring Frameworks möglich. Die Spring Konfiguration für den Service Client ist in diesem Beispiel in der Datei client-applicationContext.xml enthalten.
Die Klasse ServiceClient enthält eine main-Methode in der Spring Context initialisiert wird und auf das entsprechende Client-Bean zugegriffen wird.
Alternativ eignet sich auch soapUI hervorragend zum Testen von Webservices.
Schritt 8: Projekt kompilieren und WSDL generieren
Um das Projekt einfach kompilieren zu können habe ich diesem Beispiel ein Maven Build Script beigefügt. Beim Kompileren des Projekts wird auch unter Zuhilfenahme des Java2WSDL Tools von Apache CXF die WSDL-Datei automatisch generiert. Diese WSDL-Datei wird im Verzeichnis /target/generated/wsdl/ abgelegt.
Ähnliche Artikel:




15.8.2007 um 21:08:47
einfach, knapp und präzise, gut!
:o)
1.10.2007 um 15:10:38
In the auto-generated WSDL by the CXF API, you would have the service name as “CustomerServiceService”. Is there a way to customerize it as “CustomerService” instead, using JWS annotation or bean configuration XML?
Thanks for the help!
1.10.2007 um 20:10:13
I got what I needed using the annotations as below:
@WebService
public interface CustomerService {
………………………………
}
@WebService(serviceName=”CustomerService”, endpointInterface=”com.mycompany.customerrelations.CustomerService”)
public class CustomerServiceImpl implements CustomerService {
…………………….
}
7.2.2008 um 17:02:23
Hallo,
sehr schönes tut, aber haben Sie schon mal versucht den Webservice im Tomcat zu deployen (als war-Archiv)?
7.2.2008 um 18:02:52
Ja. Auf der Webseite von Apache CXF gibt es bereits Tutorials zum Deployment von Webservices als WAR-Archiv.
8.2.2008 um 09:02:26
Also unter Apache Tomcat/5.5.23 und JVM 1.6.0_04-b12 hatte ich Schwierigkeiten dieses Tut (http://cwiki.apache.org/CXF20DOC/writing-a-service-with-spring.html) zum laufen zu bringen. Die beispiele, die bei CXF dabei waren konnte ich problemlos testen. Aber wenn ich meinen Code mit den Annotations @WebMethod
deployen wollten (in den laufenden Tomcat), kam der Fehler ERROR listenerStart. habe ich die Annotation @WebMethod entfernt, lief es wieder ohne Probleme. Damit dieser Fehler nicht auftritt, wenn ich diese Annotation verwende, muß ich immer den ganzen Tomcat neustarten. Jetzt lädt er auch meinen Webservice korrekt.
Hätten Sie vielleicht eine Idee dazu?
17.4.2008 um 19:04:16
Eine super feines Tutorial. Ich hab alles soweit hinbekommen, bis auf die Dokumentationsannotationen im erzeugeten WSDL.
Soll ja wie hier beschrieben steht auch funktionieren.
http://xfire.codehaus.org/Documenting+WSDL
Aber die WSDL wird nicht um diese Infos aus der CustomerService.doc.xml erweitert.
Jemand eine Idee woran das liegen könnte?
Grüsse
Hans