Anwendungsbeispiel

Im Folgenden wird anhand eines Anwendungsbeispiels demonstriert, wie mittels eines Servlets auf einer Datenbank navigiert werden kann. Die Anwendung beinhaltet die folgenden Schritte:

  1. Ein Spieler ruft eine HTML-Seite auf und entscheidet, ob er eine Liste aller Spieler sehen will, oder ob er sich registrieren will.
  2. Der Spieler ruft bspw. eine HTML-Seite auf, um sich zu registrieren.
  3. Der Spieler kann alternativ die Liste der dem System bekannten Spieler einsehen.
  4. Der Spieler kann weiterhin ein neues Spiel starten, nachdem er sich registriert hat.

Im Folgenden wird das Zusammenspiel der hierzu notwendigen Klassen erläutert. Zunächst wird der Aufbau der HTML-Seite vorgestellt, mittels derer der Spieler entscheiden kann, ob er sich beim System anmelden will, oder ob er eine Liste aller bekannten Spieler einsehen will.

<HTML>

    <HEAD>

      <TITLE>Servlet-Verbindung Spielerdatenbank</TITLE>

    </HEAD>
    <BODY>

      <CENTER>

        <H1> Servlet-Verbindung Spielerdatenbank</H1></CENTER>
        <HR WIDTH="100%">
        <H2>Options</H2>
        <UL>

          <LI> <A HREF="SpielerRegistrierung.html">Spielerregistrierun g Online!</A></LI>
          <LI> <A HREF="/servlets/SpielerDBServlet">Siehe Spielerliste</A></LI>

        </UL>

    </BODY>

</HTML>

In dieser Liste wird das Servlet ohne Parameter gestartet. An späterer Stelle wird ersichtlich, dass ein Aufruf ohne Parameter dazu führt, dass die Liste aller Spieler angezeigt wird. Die Ausgabe des Startfensters ist in Abb. 13-9 angegeben.

index-Seite 

Abb. 13.9: Startseite der Anwendung

Möchte der Spieler sich beim System anmelden, so muss der entsprechende Link ausgewählt werden. Anschließend wird die im Folgenden beschriebene Webseite verwendet. Es sei darauf hingewiesen, dass im Folgenden der Aufruf des Servlets mit einem Parameter erfolgt. Mittels des Parameters kann das Servlet unterscheiden, in welchem Operationsmodus (Registrierung oder Anzeige) gearbeitet werden soll.

code 

<HTML>

    <HEAD>

      <TITLE>Spielerregistrierung</TITLE>

    </HEAD>
    <BODY>

      <CENTER><H1>Spielerregistrierung</H1></CENTER>
      <HR>
      <H2>Anweisungen</H2>
      <OL>

        <LI>Bitte geben Sie die notwendige Information ein.</LI>
        <LI>Klicken Sie <B>Register</B>, um Ihre Daten an die Datenbank zu schicken.</LI>

      </OL>
      <FORM method="GET" action="/servlets/SpielerDBServlet">

        <CENTER><TABLE BORDER=0 CELLPADDING=5 WIDTH="95%" >

          <TR>

            <TD WIDTH="36%"><B>Vorname&nbsp;</B></TD>
            <TD WIDTH="50%"><INPUT type="text" name="Vorname"size="20"></TD>

          </TR>
          <TR>

            <TD WIDTH="43%"><B>Nachname</B></TD>
            <TD WIDTH="57%"><INPUT type="text" name="Nachname"size="20"></TD>

          </TR>
          <TR>

            <TD WIDTH="36%"><B>E-Mail&nbsp;</B></TD><TD WIDTH="50%"><INPUT type="text" name="Email"size="20"></TD>

          </TR>

      </TABLE></CENTER>
      <CENTER><INPUT type="submit" value="Register"name="Register">

        <INPUT type="reset" value="Reset Form"name="B2"></CENTER>

      </FORM>

    </BODY>

</HTML>

In der HTML-Seite wird ein Formular aufgebaut, mit dessen Hilfe das Servlet gestartet werden kann (/servlets/SpielerDBServlet). Des Weiteren werden zwei Buttons angelegt, mit denen die Daten abgeschickt (Register) und zurückgesetzt (Reset) werden können. Die Ausgabe dieser Webseite ist in Abb. 13-10 angegeben.

registrierung 

Abb. 13.10: Anmeldung über eine Webseite

Die Implementierung des Servlets verwendet die zwei Klassen SpielerDBServlet und Spieler. Die eigentliche Funktionalität des Servlets ist in der Klasse SpielerDBServlet realisiert. Die Klasse Spieler dient der Formatierung der Webseiten, die als Ergebnis an den Spieler zurückgesendet werden. Zunächst wird die Implementierung der Klasse SpielerDBServlet vorgestellt.

Zu Beginn der Klasse werden zuerst die notwendigen Importierungen vorgenommen. Anschließend werden die Variablen definiert, die zum späteren Datenbankzugriff notwendig sind.

code 

import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
import java.io.*;
import java.util.*;
public class SpielerDBServlet extends HttpServlet {

    // data members
    protected Connection dbConnection;
    protected PreparedStatement displayStatement;
    protected PreparedStatement registerStatement;
    protected String dbURL = "jdbc:odbc:SpielerDatabase";
    protected String userID = "";
    protected String passwd = "";
    protected String CR = "\n";
    protected final int FIRST_NAME_POSITION = 1;
    protected final int LAST_NAME_POSITION  = 2;
    protected final int EMAIL_POSITION      = 3;

Anschließend wird eine Variable angelegt, mit der später das Spiel gestartet werden kann, falls gewünscht. Die Funktion der init-Methode wurde im Rahmen dieses Kapitels bereits beschrieben.

code 

    Server derSchiffeServer;
    protected Thread myThread;
    public String[] leer = {""};
    public void init(ServletConfig config) throws ServletException {

      super.init(config);

    }

Die nun folgende doGet-Methode realisiert den Datenbankzugriff und stellt die Namen der bereits enthaltenen Spieler fest bzw. regelt das Einfügen eines neuen Namens in die Datenbank.

code 

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{

      // Verbinden mit der Datenbank
      try {

        Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
        dbConnection = DriverManager.getConnection(dbURL, userID, passwd);

        displayStatement =  dbConnection.prepareStatement("select * from SpielerDatabase");

        registerStatement = dbConnection.prepareStatement("insert into SpielerDatabase"  + "(Vorname, Nachname, Email)" + " values (?, ?, ?)");

      } catch (Exception e){

        cleanUp();
        e.printStackTrace();

      }

In Abhängigkeit dessen, ob der Spieler den Parameter Register übergeben hat, wird nun anschließend der Spieler registriert und das Spiel gestartet oder die Liste aller Spieler ausgegeben.

code 

      String userOption = null;
      userOption = request.getParameter("Register");
      if (userOption != null) {

        // hidden form field "Register" was present
        registerSpieler(request, response);

        // Beim Registrieren wird der Server (Schiffe versenken) gestartet

        if(myThread == null) {

          myThread = new StartTheSchiffeServer();
          myThread.start();

        }

      } else {

        // simply display the Players
        displaySpieler(request, response);

      }

      // close database connectivity
      cleanUp();

    }

Im Anschluss daran muss die Methode doPost implementiert werden. Da vorab unbekannt ist, ob doPost oder doGet verwendet werden, wird doPost auf doGet abgebildet.

code 

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

      doGet(request, response);

    }

Hat der Spieler entschieden, sich die Namen und die Spielstände der anderen Spieler ausgeben zu lassen, so wird im Anschluss die Methode displaySpieler aufgerufen, die die Datenbankabfrage vornimmt und eine HTML-Datei erzeugt, die an den Spieler zurückgesendet wird.

code 

    public void displaySpieler(HttpServletRequest request,  HttpServletResponse response){

      Spieler aSpieler = null;
      try {

        response.setContentType("text/html");
        PrintWriter out = response.getWriter();

Zuerst wird eine Instanz der Klasse Spieler erstellt, mit der die Ausgabe formatiert werden kann. Anschließend wird der MIME-Datentyp auf text/html gesetzt und ein Ausgabestrom erzeugt, mit dessen Hilfe das Ergebnis an den Client zurückgegeben werden kann.

code 

      // build the html page heading
      String htmlHead = "<html><head><title>Liste aller Spieler</title></head>" + CR;

      // build the html body
      String htmlBody = "<body><center>" + CR;
      htmlBody += "<h1>Liste aller Spieler</h1>" + CR;
      htmlBody += "<hr></center><p>" + CR;

      // build the table heading
      String tableHead = "<center><table border width=100% cellpadding=5>" + CR;
      tableHead += "<tr>" + CR;
      tableHead += "<th> </th>" + CR;
      tableHead += "<th>Name des Spielers</th>" + CR;
      tableHead += "<th>E-mail</th>" + CR;
      tableHead +="<th>Gespielt</th>" + CR;
      tableHead +="<th>Gewonnen</th>" + CR;
      tableHead += "</tr>" + CR;

      // execute the query to get a list of the Players
      ResultSet dataResultSet = displayStatement.executeQuery();

      // build the table body
      String tableBody = "";
      int rowNumber = 1;

Zuerst werden die statischen HTML-Daten aufgebaut, die Informationen wie Gewonnen oder Gespielt enthalten. Anschließend wird die Datenbankanfrage ausgeführt. Die Ergebnisse der Datenbankanfrage werden im Folgenden in eine HTML-Tabelle eingefügt. Hierzu wird eine while-Schleife verwendet, in der jede Datenbankzeile mittels der Klasse Spieler formatiert wird. Nach dem Einsetzen der Daten kann die Verbindung zur Datenbank geschlossen werden.

code 

      while (dataResultSet.next()){

        aSpieler = new Spieler(dataResultSet);
        tableBody +=  aSpieler.toTableString(rowNumber);
        rowNumber++;

      }
      dataResultSet.close();

      // build the table bottom
      String tableBottom = "</table></center>";

      // build html page bottom
      String htmlBottom = "</body></html>";

      // build complete html page
      htmlBody += tableHead + tableBody + tableBottom;
      htmlBody += "<p><hr>";

      // add the copyright statement
      htmlBody += "<p><i>" + this.getServletInfo() + "</i>";
      htmlBody += "</center>";
      String htmlPage = htmlHead + htmlBody + htmlBottom;

Den Abschluss dieser Methode bildet das Schreiben der nun fertigen HTML-Seite auf den Stream, der anschließend geschlossen werden kann. Eine Antwort, die von dieser Methode generiert wurde, ist in Abb. 13-11 angegeben.

code 

      // now let's send this dynamic data
      // back to the browser
      out.println(htmlPage);

    }

    catch (Exception e){

      cleanUp();
      e.printStackTrace();

    }

    }

In der nun folgenden Registrierung müssen zuerst die Daten ausgewertet werden, die über das HTML-Formular an den Server geschickt wurden. Hierzu werden wiederum Funktionen der Klasse Spieler verwendet. Im Anschluss daran muss die HTML-Seite aufgebaut werden, die dem Client das Ergebnis der Operation anzeigt. Generell ist die Funktionalität, mittels derer die HTML-Seite aufgebaut wird, der der Methode displaySpieler sehr ähnlich. Auch hier wird ein Stream erzeugt, in den die fertige HTML-Seite geschrieben wird.

spielerliste 

Abb. 13.11: Ausgabe einer Spielerliste

code 

    public void registerSpieler(HttpServletRequest  request, HttpServletResponse  response) {

      try {

        response.setContentType("text/html");
        PrintWriter out = response.getWriter();

        // create a new Spieler based on the form data
        Spieler aSpieler = new Spieler(request);

        // set sql parameters
        registerStatement.setString(LAST_NAME_POSITION, aSpieler.getLastName());

        registerStatement.setString(FIRST_NAME_POSITION,  aSpieler.getFirstName());

        registerStatement.setString(EMAIL_POSITION,   aSpieler.getEmail());

        // execute sql
        registerStatement.executeUpdate();

        // build confirmation page
        String htmlPage =  "<html><head><title>Confirmation Page</title></head>";
        htmlPage += "<body>";
        htmlPage += "<center><h1>Confirmation  Page</h1></center><hr>";
        htmlPage += "Folgende Informationen wurden bearbeitet";
        htmlPage += aSpieler.toWebString();
        htmlPage += "<hr>";

        // add the copyright statement
        htmlPage += "<a href=/servlets/SpielerDBServlet>Siehe Liste aller Spieler</a>";
        htmlPage += "<p><i>" + this.getServletInfo() + "</i>";
        htmlPage += "</center></body></html>";

        // now let's send this dynamic data
        // back to the browser
        out.println(htmlPage);

      }

      catch (Exception e){

        cleanUp();
        e.printStackTrace();

      }

    }

Die im Folgenden beschriebenen Methoden erfüllen Hilfsfunktionen, die bspw. die korrekte Beendigung der Aufrufe umsetzen.

code 

    public void cleanUp(){

      try {

        System.out.println("Closing database connection");
        dbConnection.close();

      }

      catch (SQLException e) {

        e.printStackTrace();

      }

    }
    public void destroy(){

      System.out.println("SpielerDBServlet: destroy");
      cleanUp();
      myThread.stop();

    }
    public String getServletInfo() {

      return "<i>Spielerregistrierung-Servlet, v.1 <br> (c) OpenJava 1999</i>";

    }

Den Abschluss der Klasse bildet die innere Klasse StartTheSchiffeServer, mittels derer nach einer erfolgreichen Registrierung das Spiel gestartet werden kann. Nach erfolgreicher Registrierung ergibt sich die in Abb. 13-12 dargestellte Ausgabe.

code 

    // inner class to start the server
    public class StartTheSchiffeServer extends Thread {

      public StartTheSchiffeServer(){

        super();

      }
      public void run() {

        try{

          derSchiffeServer = new Server();
          derSchiffeServer.main(leer);
          myThread.sleep(1000);

        } catch (Exception ie){}

      }

    }

}

confirmation 

Abb. 13.12: Erfolgreiche Registrierung

Aufgabe der im Folgenden beschriebenen Klasse Spieler ist die Auswertung der Formularinformation bzw. der Aufbau von HTML-Tabellen zur Darstellung des Ergebnisses. Zuerst wird die Klasse definiert bzw. Variablen deklariert.

code 

import java.sql.*;
import javax.servlet.http.*;
public class Spieler{

    // data members
    protected String lastName;
    protected String firstName;
    protected String email;
    protected int  gespielt;
    protected int gewonnen;
    protected int verloren;
    protected final String CR = "\n";     // carriage return

    // constructors
    public Spieler(){

    }

In den nun folgenden Konstruktoren wird in Abhängigkeit vom Argument eine Auswertung des Formulars bzw. der Datenbankantwort vorgenommen.

code 

    public Spieler(HttpServletRequest request){

      lastName = request.getParameter("Nachname");
      firstName = request.getParameter("Vorname");
      email = request.getParameter("Email");

    }
    public Spieler(ResultSet dataResultSet) {

      try {

        // assign data members
        lastName =  dataResultSet.getString("Nachname");
        firstName =  dataResultSet.getString("Vorname");
        email = dataResultSet.getString("Email");
        gespielt = dataResultSet.getInt("Gespielt");
        gewonnen = dataResultSet.getInt("Gewonnen");
        verloren = dataResultSet.getInt("Verloren");

      }

      catch (SQLException e){

        e.printStackTrace();

      }

    }

Anschließend folgen die Methoden, mit denen auf einzelne Variablen zugegriffen werden kann. Es wurde bereits mehrfach erläutert, dass geschützte Variablen nur mit Zugriffsmethoden ausgelesen werden können. Auch wenn diese Methoden sehr kurz sind, erfüllen sie dennoch einen wichtigen Zweck.

code 

    //  accessors
    public String getLastName() {

      return lastName;

    }
    public String getFirstName(){

      return firstName;

    }
    public String getEmail() {

      return email;

    }
    public int getGespielt() {

      return gespielt;

    }
    public int getGewonnen() {

      return gewonnen;

    }
    public int getVerloren() {

      return verloren;

    }

Den Abschluss der Klasse bilden Hilfsroutinen, die bspw. den Aufbau von Strings realisieren.

code 

    //  methods
    //  normal text string representation
    public String toString() {

      String replyString = "";
      replyString += "Name: " + lastName + ", " + firstName + CR;
      replyString += "E-mail: " + email + CR;
      replyString += "Gespielt: " + gespielt  + CR;
      replyString += "Gewonnen: " + gewonnen  + CR;
      replyString += "Verloren: " + verloren  + CR;
      replyString +=  CR+ CR;
      return replyString;

    }

    //  returns data as HTML formatted un-ordered list
    public String toWebString() {

      String replyString = "<ul>";
      replyString += "<li><B>Name:</B> " + lastName + ", " + firstName + CR;
      replyString += "<li><B>E-mail:</B> " + email + CR;
      replyString += "<li><B>Gespielt:</B> " + gespielt  +CR;
      replyString += "<li><B>Gewonnen:</B> " + gewonnen  +CR;
      replyString += "<li><B>Verloren:</B> " + verloren  +CR;
      replyString += "</ul>" + CR;
      return replyString;

    }

    // returns data formatted for an HTML table row
    public String toTableString(int rowNumber) {

      String replyString = "";
      String tdBegin = "<td>";
      String tdEnd = "</td>" + CR;
      replyString += "<tr>" + CR;
      replyString += tdBegin + rowNumber + tdEnd;
      replyString += tdBegin + lastName + ", " + firstName + tdEnd;
      replyString += tdBegin + "<a href=mailto:" + email + "> "  + email + "</a>" + tdEnd;

      replyString += tdBegin + gespielt + tdEnd;
      replyString += tdBegin + gewonnen + tdEnd;
      replyString += "</tr>" + CR;
      return replyString;

    }

}


SPNavRight SPNavRight SPNavRight
BuiltByNOF