Im Folgenden wird anhand eines Anwendungsbeispiels demonstriert, wie mittels eines Servlets auf einer Datenbank navigiert werden kann. Die Anwendung beinhaltet die folgenden Schritte: Ein Spieler ruft eine HTML-Seite auf und entscheidet, ob er eine Liste aller Spieler sehen will, oder ob er sich registrieren will. Der Spieler ruft bspw. eine HTML-Seite auf, um sich zu registrieren. Der Spieler kann alternativ die Liste der dem System bekannten Spieler einsehen. 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. 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. <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. 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. 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. 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. 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. 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. 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. 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. // 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. 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. // 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. Abb. 13.11: Ausgabe einer Spielerliste 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. 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. // 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){} } } } 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. 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. 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. // 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. // 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; } }