Skip to content

8. Version 4 – Client/Server in einer Webservice-Architektur

In dieser neuen Version läuft die Anwendung [Pam] im Client-Server-Modus innerhalb einer Webservice-Architektur. Werfen wir noch einmal einen Blick auf die Architektur der vorherigen Anwendung:

Oben ermöglichte eine Kommunikationsschicht [C, RMI, S] die transparente Kommunikation zwischen der Client-Schicht [ui] und der Remote-Schicht [business]. Wir werden eine ähnliche Architektur verwenden, bei der die Kommunikationsschicht [C, RMI, S] durch eine Schicht [C, HTTP / SOAP, S] ersetzt wird:

Das HTTP/SOAP-Protokoll hat gegenüber dem bisherigen RMI/EJB-Protokoll den Vorteil, dass es plattformübergreifend ist. So kann der Webservice in Java geschrieben und auf dem Glassfish-Server bereitgestellt werden, während der Client ein .NET- oder PHP-Client sein kann.

Wir werden diese Architektur in drei verschiedenen Modi entwickeln:

  1. Der Webservice wird vom EJB [Business] bereitgestellt
  2. Der Webservice wird von einer Webanwendung bereitgestellt, die das [Business]-EJB nutzt
  3. Der Webdienst wird von einer Webanwendung bereitgestellt, die Spring verwendet

Ein Webdienst kann innerhalb eines Java EE-Servers auf verschiedene Arten implementiert werden:

  • durch eine mit @WebService annotierte Klasse, die in einem Web-Container ausgeführt wird
  • durch ein mit @WebService annotiertes EJB, das in einem EJB-Container ausgeführt wird

Wir beginnen mit der letztgenannten Architektur.

8.1. Durch eine EJB implementierter Webservice

8.1.1. Die Serverseite

8.1.1.1. Das NetBeans-Projekt

Beginnen wir damit, ein neues Maven-Projekt zu erstellen, das eine Kopie des EJB-Projekts [mv-pam-ejb-metier-dao-jpa-eclipselink] ist:

  

In der folgenden Architektur:

ist die [Business]-Schicht der Webservice, der von der [UI]-Schicht aufgerufen wird. Diese Klasse muss keine Schnittstelle implementieren. Es sind Annotationen, die ein POJO (Plain Old Java Object) in einen Webservice umwandeln. Die [Business]-Klasse, die die oben genannte [Business]-Schicht implementiert, wird wie folgt umgewandelt:


    <dependency>
      <groupId>org.swinglabs</groupId>
      <artifactId>swing-layout</artifactId>
      <version>1.0.3</version>
</dependency>
  • Zeile 4: Die Annotation @WebService wandelt die Klasse [Business] in einen Webdienst um. Ein Webdienst stellt seinen Clients Methoden zur Verfügung. Diese Methoden müssen mit dem Attribut @WebMethod annotiert werden.
  • Zeilen 19 und 25: Die beiden Methoden der Klasse [Metier] werden zu Methoden des Webdienstes.
  • Zeile 29: Es ist wichtig, dass die Getter und Setter entfernt werden; andernfalls werden sie im Webdienst verfügbar gemacht, was zu Sicherheitsfehlern führt.

Das Hinzufügen dieser Annotationen wird von NetBeans erkannt, woraufhin sich die Art des Projekts ändert:

In [1] ist im Projekt ein [Web Services]-Baum erschienen. Er enthält den Webdienst „Metier“ und dessen zwei Methoden. Die Serveranwendung kann bereitgestellt werden [2]. Der MySQL-Server muss laufen, und seine Datenbank [dbpam_eclipselink] muss vorhanden und gefüllt sein. Möglicherweise ist es erforderlich, zuvor [3] die EJBs aus dem zuvor untersuchten Client/Server-EJB-Projekt zu entfernen, um Namenskonflikte zu vermeiden. Tatsächlich enthält unser neues Projekt dieselben EJBs wie das vorherige Projekt.

In [1] sehen wir unsere Serveranwendung, die auf dem GlassFish-Server bereitgestellt wurde. Sobald der Webdienst bereitgestellt ist, kann er getestet werden:

  • In [1] testen wir im aktuellen Projekt den [Metier]-Webdienst
  • Der Webservice ist über verschiedene URLs erreichbar. Über die URL [2] können Sie den Webservice testen
  • In [3] finden Sie einen Link zur XML-Datei, die den Webdienst definiert. Clients des Webdienstes müssen die URL dieser Datei kennen. Die Client-Schicht (Stubs) des Webdienstes wird aus dieser Datei generiert.
  • In [4,5] finden Sie ein Formular zum Testen der vom Webdienst bereitgestellten Methoden. Diese werden zusammen mit ihren Parametern angezeigt, die der Benutzer definieren kann.

Testen wir zum Beispiel die Methode [findAllEmployees], die keine Parameter benötigt:

 

Oben testen wir die Methode. Daraufhin erhalten wir die folgende Antwort (Teilansicht). Wir können tatsächlich die beiden Mitarbeiter mit ihren Sozialleistungen sehen. Der Leser ist eingeladen, die Methode [4] auf die gleiche Weise zu testen, indem er ihr die drei erwarteten Parameter übergibt.

Image

8.1.2. Die Client-Seite

8.1.2.1. Das NetBeans-Projekt des Kunden -console

Wir erstellen nun ein Java-Projekt vom Typ [Java-Anwendung] für die Client-Seite der Anwendung. Stand Juni 2012 war es nicht möglich, ein Maven-Projekt für diesen Client zu erstellen. Es tritt ein Fehler auf, der online bekannt zu sein scheint, aber weiterhin ungelöst ist.

 

Sobald das Projekt erstellt ist, legen wir fest, dass es ein Client des Webdienstes sein soll, den wir gerade auf dem GlassFish-Server bereitgestellt haben:

  • In [2] wählen wir das neue Projekt aus und klicken auf die Schaltfläche [Neue Datei]
  • in [3] geben wir an, dass wir einen Webservice-Client erstellen möchten
  • In [4] wählen wir das NetBeans-Projekt für den Webdienst aus
  • Im Fenster [5] werden alle Projekte mit einem [Web Services]-Zweig aufgelistet; hier nur das Projekt [mv-pam-ws-metier-dao-eclipselink].
  • Ein Projekt kann mehrere Webdienste bereitstellen. In [6] geben wir den Webdienst an, mit dem wir eine Verbindung herstellen möchten.
  • In [7] wird die URL angezeigt, die den Webdienst definiert. Diese URL wird von den Software-Tools verwendet, die die Client-Schicht generieren, die als Schnittstelle zum Webdienst dient.
  • Die Client-Schicht [C] [1], die generiert wird, besteht aus einer Reihe von Java-Klassen, die im selben Paket abgelegt werden. Der Name dieses Pakets wird in [8] festgelegt.
  • Sobald der Assistent zur Erstellung des Webdienst-Clients durch Klicken auf die Schaltfläche [Fertigstellen] abgeschlossen ist, wird die oben beschriebene [C]-Schicht erstellt.

Dies spiegelt sich in einer Reihe von Änderungen im Projekt wider:

  • In [10] oben erscheint ein Baum [Generierte Quellen], der die Klassen der Schicht [C] enthält, die es dem Client [3] ermöglichen, mit dem Webdienst zu kommunizieren. Diese Schicht ermöglicht es dem Client [3], mit der [Business]-Schicht [4] so zu kommunizieren, als wäre sie lokal und nicht remote.
  • In [11] erscheint ein Baum [Web Service References], der die Webdienste auflistet, für die eine Client-Ebene generiert wurde.

Beachten Sie, dass wir in der generierten [C]-Ebene [10] Klassen finden, die auf der Serverseite bereitgestellt wurden: Indemnite, Cotisation, Employe, FeuilleSalaire, ElementsSalaire, Metier. Metier ist der Webdienst, und die anderen Klassen sind Klassen, die von diesem Dienst benötigt werden. Man könnte neugierig sein, ihren Code zu untersuchen. Wir werden sehen, dass die Definition der Klassen – die, wenn sie instanziiert werden, Objekte darstellen, die vom Dienst manipuliert werden – darin besteht, die Klassenfelder und ihre Zugriffsmethoden zu definieren sowie Annotationen hinzuzufügen, die die Serialisierung der Klasse in einen XML-Stream ermöglichen. Die Klasse „Metier“ ist zu einer Schnittstelle geworden, die die beiden mit @WebMethod annotierten Methoden enthält. Jede dieser Methoden führt zur Entstehung von zwei Klassen, zum Beispiel [CalculatePayroll.java] und [CalculatePayrollResponse.java], wobei die eine den Methodenaufruf und die andere dessen Ergebnis kapselt. Schließlich ist die Klasse „MetierService“ die Klasse, die es dem Client ermöglicht, eine Referenz auf den entfernten Webdienst „Metier“ zu erhalten:


package metier;
 
...
@WebService
@Stateless()
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class Metier implements IMetierLocal,IMetierRemote {
  
  // references on layers [DAO]
  @EJB
  private ICotisationDaoLocal cotisationDao = null;
  @EJB
  private IEmployeDaoLocal employeDao=null;
  @EJB
  private IIndemniteDaoLocal indemniteDao=null;
 
 
  // get your payslip
@WebMethod
  public FeuilleSalaire calculerFeuilleSalaire(String SS,
...
  }
 
  // list of employees
@WebMethod
   public List<Employe> findAllEmployes() {
...
  }
// important - no getters and setters for EJB
 }

Die Methode getMetierPort in Zeile 2 ruft eine Referenz auf den Remote-Webdienst „Metier“ ab.

8.1.2.2. Der Konsolen-Client für den Metier-Webdienst

Nun muss nur noch der Client für den Metier-Webdienst geschrieben werden. Wir kopieren die Klasse [MainRemote] aus dem Projekt [mv-pam-client-metier-dao-jpa-eclipselink] – das ein Client eines EJB-Servers war – in das neue Projekt.

  • In [1] die Webservice-Client-Klasse. Die Klasse [MainRemote] enthält Fehler. Um diese zu beheben, entfernen wir zunächst alle vorhandenen [import]-Anweisungen in der Klasse und generieren sie mithilfe der Option [Fix Imports] neu. Der Grund dafür ist, dass einige der von der Klasse [MainRemote] verwendeten Klassen nun Teil des generierten [client]-Pakets sind.
  • In [3] der Codeausschnitt, in dem die [business]-Schicht instanziiert wird [3]. Sie wird mithilfe von JNDI-Code instanziiert, um eine Referenz auf ein Remote-EJB zu erhalten.

Wir aktualisieren den Code wie folgt:

  • Der JNDI-Code wird entfernt
  • Da die Klasse [PamException] auf der Client-Seite nicht existiert, entfernen wir den zugehörigen catch-Block, um nur den catch-Block für die übergeordnete Klasse [Exception] beizubehalten.
  • In [4] müssen wir noch eine Referenz auf den Remote-Webdienst [Metier] abrufen, um dessen Methode [calculatePayroll] aufzurufen.
  • In [5] ziehen wir die Methode [calculerFeuilleSalaire] mit der Maus aus dem Webdienst [Metier] und legen sie in [4] ab. Der Code wird generiert [6]. Dieser generische Code kann dann vom Entwickler angepasst werden.
  • In Zeile 112 sehen wir, dass [calculatePayroll] eine Methode der Klasse [client.Metier] ist (Zeile 111). Da wir nun wissen, wie wir die [metier]-Schicht abrufen können, lässt sich der vorherige Code wie folgt umschreiben:
1
2
3
4
    @WebEndpoint(name = "MetierPort")
    public Metier getMetierPort() {
        return super.getPort(new QName("http://metier/", "MetierPort"), Metier.class);
}

Zeile 7 ruft eine Referenz auf den Metier-Webdienst ab. Danach bleibt der Klassencode unverändert, mit der Ausnahme, dass in Zeile 10 nicht der Typ [Exception] behandelt wird, sondern der allgemeinere Typ Throwable, die Oberklasse der Exception-Klasse. Tritt eine Ausnahme auf, zeigen wir alle ihre verschachtelten Ursachen bis zur Grundursache an.

Wir sind bereit für den Test:

  • Stellen Sie sicher, dass das DBMS MySQL5 läuft und dass die Datenbank dbpam_eclipselink erstellt und initialisiert ist
  • Stellen Sie sicher, dass der Webdienst auf dem GlassFish-Server bereitgestellt ist
  • Erstellen Sie den Client (Clean und Build)
  • Konfigurieren Sie den Client für die Ausführung
  
  • Starten Sie den Client

Die Ergebnisse in der Konsole lauten wie folgt:

...    
// it's okay - we can ask for the payslip
    FeuilleSalaire feuilleSalaire = null;
    Metier metier = null;
    try {
       // instantiation layer [metier]
      metier = new MetierService().getMetierPort();
       // wage sheet calculation
      feuilleSalaire = metier.calculerFeuilleSalaire(args[0], nbHeuresTravaillées, nbJoursTravaillés);
    } catch (Throwable th) {
       // exception chain
      System.out.println("Chaîne des exceptions --------------------------------------");
      System.out.println(th.getClass().getName() + ":" + th.getMessage());
      while (th.getCause() != null) {
        th = th.getCause();
        System.out.println(th.getClass().getName() + ":" + th.getMessage());
      }
      System.exit(1);
    }
     // quick viewing
...

Mit der folgenden Konfiguration:

Image

erhalten wir folgende Ergebnisse:

...
Valeurs saisies :
N° de sécurité sociale de l'employé : 254104940426058
Nombre d'heures travaillées : 150
Nombre de jours travaillés : 20

Informations Employé : 
Nom : Jouveinal
Prénom : Marie
Adresse : 5 rue des oiseaux
...

Beachten Sie, dass der [Metier]-Webdienst zwar eine Ausnahme vom Typ [PamException] sendet, die vom Client empfangene Ausnahme jedoch vom Typ [SOAPFaultException] ist. Auch in der Ausnahmekette taucht der Typ [PamException] nicht auf.

8.1.3. Der Swing-Client für den Metier-Webdienst


Aufgabe: Portieren Sie den Swing-Client aus dem Projekt [mv-pam-client-ejb-metier-dao-jpa-eclipselink] in das neue Projekt, sodass auch dieser zu einem Client des auf dem GlassFish-Server bereitgestellten Webdienstes wird.


8.2. Von einer Webanwendung implementierter Webdienst

Wir arbeiten nun innerhalb des folgenden Architektur-Frameworks:

Der Webdienst wird von einer Webanwendung bereitgestellt, die im Webcontainer des GlassFish-Servers läuft. Dieser Webdienst stützt sich auf das [Metier]-EJB, das im EJB3-Container bereitgestellt wird.

8.2.1. Die Serverseite

Wir erstellen eine Webanwendung:

  • In [1] erstellen wir ein neues Projekt
  • in [2] ist dieses Projekt vom Typ [Webanwendung]
  • in [3] nennen wir es [mv-pam-ws-ejb-metier-dao-eclipselink]
  • in [4] wählen wir Java EE 6
  • in [6] wird das Projekt erstellt

In der folgenden Abbildung wird die erstellte Webanwendung im Web-Container ausgeführt. Sie nutzt das [Metier]-EJB, das im EJB-Container des Servers bereitgestellt wird.

Um sicherzustellen, dass die erstellte Webanwendung Zugriff auf die mit dem [Metier]-EJB verbundenen Klassen hat, fügen wir die Abhängigkeit für den EJB-Server [mv-pam-ejb-metier-dao-eclipselink] – den wir bereits behandelt haben – zu den Bibliotheken der Webanwendung [mv-pam-ws-ejb-metier-dao-eclipselink] hinzu.

  • In [1] fügen wir ein Projekt zu den Abhängigkeiten des Webprojekts hinzu;
  • in [2] wählen wir das Projekt [mv-pam-ejb-metier-dao-eclipselink] aus;
  • in [3] ist der Abhängigkeitstyp ejb,
  • in [4] wird der Geltungsbereich der Abhängigkeit angegeben, was bedeutet, dass sie von der Laufzeitumgebung bereitgestellt wird,
  • in [5] wurde die Abhängigkeit hinzugefügt.

Um denselben Webdienst wie zuvor zu erstellen, müssen wir:

  • eine Klasse erstellen, die mit @WebService annotiert ist
  • mit zwei Methoden, calculerFeuilleSalaire und findAllEmployes, die mit @WebMethod annotiert sind

Wir erstellen eine Klasse [PamWsEjbMetier] im Paket [pam.ws]:

  

Die Klasse [PamWsEjbMetier] sieht wie folgt aus:

1
2
3
4
Chaîne des exceptions --------------------------------------
javax.xml.ws.soap.SOAPFaultException:L'employé de n°[xx] est introuvable
com.sun.xml.internal.ws.developer.ServerSideException:L'employé de n°[xx] est introuvable
Java Result: 1
  • Zeilen 7–10: Die Klasse importiert Klassen aus dem EJB-Modul [pam-serveurws-metier-dao-jpa-eclipselink], dessen Maven-Projekt zu den Abhängigkeiten des Projekts hinzugefügt wurde.
  • Zeile 12: Die Klasse ist ein Webservice
  • Zeile 13: Sie implementiert die im EJB-Modul definierte Schnittstelle IMetier
  • Zeilen 18–19: Die Methode `calculerFeuilleSalaire` wird als Webservice-Methode bereitgestellt
  • Zeilen 23–24: Die Methode `findAllEmployees` wird als Webservice-Methode bereitgestellt
  • Zeilen 15–16: Die lokale Schnittstelle des EJB [Metier] wird in das Feld in Zeile 16 injiziert. Wir verwenden die lokale Schnittstelle, da die Webanwendung und das EJB-Modul in derselben JVM laufen.
  • Zeilen 20 und 25: Die Methoden `calculerFeuilleSalaire` und `findAllEmployees` delegieren ihre Verarbeitung an die gleichnamigen Methoden im [Metier]-EJB. Die Klasse dient daher lediglich dazu, die Methoden des [Metier]-EJBs als Webdienstmethoden für Remote-Clients verfügbar zu machen.

In NetBeans wird die Webanwendung als Anbieter eines Webdienstes erkannt:

Um den Webdienst auf dem GlassFish-Server bereitzustellen, müssen wir beides bereitstellen:

  • das Webmodul im Webcontainer des Servers
  • das EJB-Modul im EJB-Container des Servers

Dazu müssen wir eine [Enterprise-Anwendung] erstellen, die beide Module gleichzeitig bereitstellt. Dazu müssen beide Projekte in NetBeans geladen werden [2].

Sobald dies geschehen ist, erstellen wir ein neues Projekt [3].

  • In [4] wählen wir den Projekttyp [Enterprise-Anwendung] aus.
  • In [5] benennen wir das Projekt
  • In [6] konfigurieren wir das Projekt. Die Java EE-Version ist Java EE 6. Ein Enterprise-Projekt kann mit zwei Modulen erstellt werden: einem EJB-Modul und einem Web-Modul. Hier kapselt das Enterprise-Projekt das Web-Modul und das EJB-Modul, die bereits erstellt und in NetBeans geladen wurden. Daher fordern wir keine Erstellung neuer Module an.
  • In [7] wird das Unternehmensprojekt [mv-pam-webapp-ear] erstellt. Gleichzeitig wurde ein weiteres Maven-Projekt erstellt [mv-pam-webapp]. Damit werden wir uns nicht befassen.
  • In [8] fügen wir dem Enterprise-Projekt Abhängigkeiten hinzu
  • In [9] fügen wir das Webprojekt vom Typ WAR hinzu,
  • In [10] fügen wir das EJB-Projekt vom Typ ejb hinzu,
  • In [11] das Enterprise-Projekt mit seinen beiden Abhängigkeiten.

Wir erstellen das Unternehmensprojekt mit Clean und Build. Wir sind fast bereit, es auf dem GlassFish-Server bereitzustellen. Zuvor kann es erforderlich sein, bereits auf dem Server ausgeführte Anwendungen zu beenden, um mögliche EJB-Namenskonflikte zu vermeiden [11]:

Der MySQL-Server muss laufen, und die Datenbank [dbpam_eclipselink] muss verfügbar und gefüllt sein. Sobald dies erledigt ist, kann die Unternehmensanwendung bereitgestellt werden [12]. In [13] sehen wir, dass sie erfolgreich auf dem GlassFish-Server bereitgestellt wurde.

Wir können den soeben bereitgestellten Webdienst testen:

  • In [1] fordern wir den Webdienst [PamWsEjbMetier]
  • in [2], der Testseite. Wir überlassen es dem Leser, die Tests durchzuführen.

8.2.2. Die Client-Seite


Aufgabe: Erstellen Sie gemäß der in Abschnitt 8.1.2.1 beschriebenen Vorgehensweise einen Konsolen-Client für den oben genannten Webdienst.


8.3. Mit Spring und Tomcat implementierter Webservice

Wir arbeiten nun innerhalb des folgenden Architektur-Frameworks:

Der Webdienst wird von einer Webanwendung bereitgestellt, die im Webcontainer des Tomcat-Servers läuft. Die Anwendungsarchitektur sieht wie folgt aus:

Wir werden auf dem in Abschnitt 5.11 erstellten Projekt [mv-pam-spring-hibernate] aufbauen:

  

8.3.1. Die Serverseite

Wir erstellen eine webbasierte Maven-Anwendung mit dem Namen [mv-pam-ws-spring-tomcat] [1]:

Wir ändern die Datei [pom.xml] und fügen die folgenden Abhängigkeiten hinzu [2]:

package pam.ws;

import java.util.List;
import javax.ejb.EJB;
import javax.jws.WebMethod;
import javax.jws.WebService;
import jpa.Employe;
import metier.FeuilleSalaire;
import metier.IMetier;
import metier.IMetierLocal;

@WebService
public class PamWsEjbMetier implements IMetier{

  @EJB
  private IMetierLocal metier;

  @WebMethod
  public FeuilleSalaire calculerFeuilleSalaire(String SS, double nbHeuresTravaillées, int nbJoursTravaillés) {
    return metier.calculerFeuilleSalaire(SS, nbHeuresTravaillées, nbJoursTravaillés);
  }

  @WebMethod
  public List<Employe> findAllEmployes() {
    return metier.findAllEmployes();
  }

}
  • Zeilen 3–7: die Abhängigkeit vom Projekt [spring-pam-jpa-hibernate],
  • Zeilen 8–17: Abhängigkeiten vom Apache CXF-Framework [http://cxf.apache.org/]. Dieses Framework erleichtert die Erstellung von Webdiensten.

Diese [pom.xml]-Datei enthält zahlreiche Abhängigkeiten [2].

Kehren wir zur Anwendungsarchitektur zurück:

Aufrufe des Webdienstes, den wir erstellen werden, werden von einem Servlet aus dem CXF-Framework verarbeitet. Dies spiegelt sich in der Datei [WEB-INF/web.xml] wie folgt wider:


  <dependencies>
    <dependency>
      <groupId>${project.groupId}</groupId>
      <artifactId>mv-pam-spring-hibernate</artifactId>
      <version>${project.version}</version>
    </dependency>
    <!-- Apache CXF dependencies -->
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-frontend-jaxws</artifactId>
      <version>2.2.12</version>
    </dependency>
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-transports-http</artifactId>
      <version>2.2.12</version>
    </dependency>
</dependencies>
  • Das CXF-Framework ist von Spring abhängig. Zeilen 4–6: Ein Listener wird deklariert. Die entsprechende Klasse wird gleichzeitig mit der Webanwendung geladen. Sie verwendet die Spring-Konfigurationsdatei [WEB-INF/applicationContext.xml]:
  • Zeilen 8–12: Das CXF-Servlet, das Aufrufe an den Webdienst verarbeitet, den wir erstellen werden,
  • Zeilen 13–16: URLs, die vom CXF-Servlet verarbeitet werden, haben die Form /ws/*. Andere werden nicht von CXF verarbeitet.

Um den Webdienst zu definieren, definieren wir eine Schnittstelle und deren Implementierung:

Die Schnittstelle [IWsMetier] sieht wie folgt aus:


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <display-name>mv-pam-ws-spring-tomcat</display-name>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
<!--   CXF configuration -->
  <servlet>
    <servlet-name>CXFServlet</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>CXFServlet</servlet-name>
    <url-pattern>/ws/*</url-pattern>
  </servlet-mapping>
  <session-config>
    <session-timeout>
      30
    </session-timeout>
  </session-config>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
  • Zeile 7: Die Schnittstelle [IWsMetier] leitet sich von der Schnittstelle [IMetier] in der [business]-Schicht des Projekts [mv-pam-spring-hibernate] ab,
  • Zeile 6: Die Schnittstelle [IWsMetier] ist die eines Webdienstes.

Die Implementierungsklasse für diese Schnittstelle lautet wie folgt:


package pam.ws;
 
import javax.jws.WebService;
import metier.IMetier;
 
@WebService
public interface IWsMetier extends IMetier{
 
}
  • Zeile 11: Die Klasse [PamWsMetier] implementiert die zuvor definierte Schnittstelle,
  • Zeile 10: definiert die Klasse als Webservice,
  • Zeile 14: Die [business]-Schicht wird von Spring injiziert,
  • Zeilen 21, 26: Die Annotation @WebMethod macht eine Methode zu einer vom Webservice bereitgestellten Methode,
  • Zeilen 23, 28: Die Methoden werden unter Verwendung der [business]-Schicht implementiert.

Wir müssen noch den Inhalt der Spring-Konfigurationsdatei [applicationContext.xml] definieren:

Der Inhalt lautet wie folgt:


package pam.ws;
 
import java.util.List;
import javax.jws.WebMethod;
import javax.jws.WebService;
import jpa.Employe;
import metier.FeuilleSalaire;
import metier.IMetier;
 
@WebService
public class PamWsMetier implements IWsMetier {
 
  // business layer
  private IMetier metier;
 
  // manufacturer
  public PamWsMetier(){
 
  }
 
  @WebMethod
  public FeuilleSalaire calculerFeuilleSalaire(String SS, double nbHeuresTravaillees, int nbJoursTravailles) {
    return metier.calculerFeuilleSalaire(SS, nbHeuresTravaillees, nbJoursTravailles);
  }
 
  @WebMethod
  public List<Employe> findAllEmployes() {
    return metier.findAllEmployes();
  }
 
  // getters and setters
 
  public void setMetier(IMetier metier) {
    this.metier = metier;
  }
 
}
  • Zeilen 13–15: Apache-CXF-Konfigurationsdateien werden importiert. Diese werden im Klassenpfad des Projekts gesucht (Attribut „classpath“),
  • Zeilen 4, 9, 10: Apache-CXF-spezifische Namespaces werden deklariert,
  • Zeile 18: Die Spring-Konfigurationsdatei für das Projekt [mv-pam-spring-hibernate] wird importiert,
  • Zeilen 21–23: definieren die Webservice-Bean mit ihrer Abhängigkeit von der [business]-Schicht (Zeile 22),
  • Zeilen 24–27: definieren den Webservice selbst,
    • Zeile 25: Die Spring-Bean, die den Webservice implementiert, ist die in Zeile 21 definierte;
    • Zeile 26: definiert die URL, unter der der Webservice verfügbar sein wird, hier /business. In Kombination mit dem für von Apache CXF verarbeitete URLs erforderlichen Format (siehe Datei web.xml) wird diese URL zu /ws/business.

Unser Projekt ist bereit zur Ausführung. Wir führen es aus (Run) und rufen die URL [http://localhost:8080/mv-pam-ws-spring-tomcat/ws] in einem Browser auf:

Image

Die Seite listet alle bereitgestellten Webdienste auf. Hier gibt es nur einen. Wir folgen dem WSDL-Link:

Der angezeigte Text [1] stammt aus einer XML-Datei, die die Funktionalität des Webdienstes, die Art und Weise seines Aufrufs und die von ihm gesendeten Antworten definiert. Beachten Sie die URL [2] dieser WSDL-Datei. Alle Clients des Webdienstes müssen diese kennen.

8.3.2. Die Client-Seite


Aufgabe: Erstellen Sie gemäß der in Abschnitt 8.1.2.1 beschriebenen Vorgehensweise einen Konsolen-Client für den oben genannten Webdienst.


Hinweis: Um die URL der WSDL-Datei des Webdienstes anzugeben, gehen Sie wie folgt vor:

Geben Sie die zuvor unter [2] notierte URL in [3] ein.