3. Einführung in Java-Servlets und JSP-Seiten
In diesem Kapitel finden sich verschiedene Beispiele für Servlets und JSP-Seiten. Sie wurden mit dem Tomcat-Server getestet. Dieser läuft auf Port 8080. Über die Links auf der Startseite gelangt man zu Beispielen für Servlets und JSP-Seiten. Die folgenden Beispiele stammen größtenteils aus den Tomcat-Beispielen. Um sie zu testen, starten Sie einfach Tomcat, rufen Sie die Seite URL http://localhost:8080 mit einem Browser auf und folgen Sie dem Link zu den Servlets.
![]() | ![]() |
3.1. Java-Servlets
3.1.1. Inhalte an einen Web-Client senden
Wir betrachten das obige „Hello World“-Beispiel. Das Servlet lautet wie folgt:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class HelloWorld extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello World!</h1>");
out.println("</body>");
out.println("</html>");
}
}
Bei der Ausführung dieses Servlets wird folgende Anzeige erzeugt:

Beachten Sie folgende Punkte:
- Für Servlets müssen spezielle Klassen importiert werden:
import javax.servlet.*;
import javax.servlet.http.*;
Die Bibliothek javax.servlet ist nicht immer standardmäßig im JDK enthalten. In diesem Fall kann man sie direkt von der Sun-Website herunterladen.
- Ein Servlet leitet sich von der Klasse HttpServlet ab
public class HelloWorld extends HttpServlet {
- Eine an das Servlet gerichtete Anfrage GET wird von der Methode doGet verarbeitet
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
- Ebenso wird eine an das Servlet gerichtete Anfrage POST von der Methode doPost verarbeitet
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
- Das Objekt „HttpServletRequest request“ ist das Objekt, über das wir Zugriff auf die vom Web-Client gestellte Anfrage erhalten. Die Antwort des Servlets erfolgt über das Objekt „HttpServletResponse response“.
- Das Objekt response ermöglicht es uns, die HTTP-Header festzulegen, die an den Client gesendet werden. Beispielsweise wird der Header „Content-Type: text/html“ hier wie folgt festgelegt:
- Um die Antwort an den Client zu senden, verwendet das Servlet einen Ausgabestrom, der ihm vom Objekt response bereitgestellt wird:
- Sobald dieser Ausgabestrom vorliegt, wird der Code „HTML“ darin geschrieben und somit an den Client gesendet:
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello World!</h1>");
out.println("</body>");
out.println("</html>");
3.1.2. Vom Web-Client gesendete Parameter abrufen
Das folgende Beispiel zeigt, wie ein Servlet vom Web-Client gesendete Parameter abrufen kann. Ein Eingabeformular:

Die vom Servlet gesendete Antwort:

Der Quellcode des Servlets lautet wie folgt:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class myRequestParamExample extends HttpServlet {
String title="Récupération des paramètres d'un formulaire";
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
out.println("<h3>" + title + "</h3>");
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
if (firstName != null || lastName != null) {
out.println("firstname= " + firstName + "<br>");
out.println("lastname= " + lastName);
} else {
out.println("pas de paramètres");
}
out.println("<P>");
out.print("<form action=\"RequestParamExample\" method=\"POST\">");
out.println("firstname= <input type=text size=20 name=firstname>");
out.println("<br>");
out.println("lastname= <input type=text size=20 name=lastname>");
out.println("<br>");
out.println("<input type=submit>");
out.println("</form>");
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
}
Im Vergleich zum vorherigen Beispiel sind folgende Neuerungen zu beachten:
- Die vom Browser gesendeten Parameter werden wie folgt abgerufen:
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
Die Methode request.getParameter("nomParamètre") gibt den Zeiger null zurück, wenn der Parameter nomParamètre nicht zu den vom Web-Client gesendeten Parametern gehört.
- Das Formular gibt an, dass der Browser die Parameter über die Methode POST senden muss
- Die empfangenen Parameter werden von der Methode doPost des Servlets verarbeitet. Hier beschränkt sich diese Methode darauf, die Methode doGet aufzurufen. Somit verarbeitet dieses Servlet die Werte des Formulars, unabhängig davon, ob sie von einem GET oder einem POST gesendet wurden.
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
3.1.3. Die von einem Web-Client gesendeten HTTP-Header abrufen
Das folgende Servlet zeigt, wie die vom Web-Client gesendeten HTTP-Header abgerufen werden können:

Der Quellcode des Servlets lautet wie folgt:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class RequestHeaderExample extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
Enumeration e = request.getHeaderNames();
while (e.hasMoreElements()) {
String name = (String)e.nextElement();
String value = request.getHeader(name);
out.println(name + " = " + value);
}
}
}
Wichtige Hinweise:
- Über das Objekt request und dessen Methode getHeaderNames erhalten wir Zugriff auf die vom Browser gesendeten HTTP-Header in Form einer Aufzählung:
- Mit der Methode request.getHeader("Header") lässt sich ein bestimmter HTTP-Header abrufen. Das obige Beispiel zeigt einige davon. Es sei daran erinnert, dass die hier vorgestellten Header vom Browser gesendet werden. Der Server verfügt ebenfalls über eigene HTTP-Header, die manchmal diejenigen des Browsers übernehmen. Die vom Browser gesendeten HTTP-Header dienen dazu, den Server über die Fähigkeiten des Browsers zu informieren.
Header | Bedeutung |
Identität des Browsers | |
Die vom Browser unterstützten Formate MIME. So bedeutet image/gif, dass der Browser Bilder im Format GIF verarbeiten kann | |
im Format hote:port. Gibt an, welchen Rechner und welchen Port der Browser kontaktieren möchte. | |
Vom Browser akzeptiertes Kodierungsformat für vom Server gesendete Dokumente. Wenn ein Server also ein Dokument in normaler, unkomprimierter Form und eines im komprimierten gzip-Format bereitstellt und der Browser angegeben hat, dass er das gzip-Format verarbeiten kann, kann der Server das Dokument im gzip-Format senden, um Bandbreite zu sparen. | |
Vom Browser akzeptierte Sprachen. Verfügt ein Server über dasselbe Dokument in mehreren Sprachen, sendet er eine Version, deren Sprache vom Browser akzeptiert wird. | |
die vom Browser angeforderte URL | |
die vom Browser angeforderte Verbindungsart. Keep-alive bedeutet, dass der Server die Verbindung nicht trennen darf, nachdem er die angeforderte Seite an den Browser übermittelt hat. Stellt der Browser fest, dass die empfangene Seite beispielsweise Links zu Bildern enthält, kann er neue Anfragen an den Server senden, um diese abzurufen, ohne eine neue Verbindung herstellen zu müssen. Der Browser übernimmt dann die Initiative, die Verbindung zu schließen, sobald er alle Elemente der Seite empfangen hat. |
3.1.4. Umgebungsinformationen abrufen
Das folgende Servlet zeigt, wie auf Informationen zur Ausführungsumgebung des Servlets zugegriffen werden kann. Einige dieser Informationen werden vom Browser in Form von HTTP-Headern gesendet und können daher mit der oben genannten Methode abgerufen werden.

Der Code des Servlets lautet wie folgt:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class RequestInfo extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>Request Information Example</title>");
out.println("</head>");
out.println("<body>");
out.println("<h3>Request Information Example</h3>");
out.println("Method: " + request.getMethod());
out.println("Request URI: " + request.getRequestURI());
out.println("Protocol: " + request.getProtocol());
out.println("PathInfo: " + request.getPathInfo());
out.println("Remote Address: " + request.getRemoteAddr());
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
}
Die Informationen werden hier auf verschiedene Weise gewonnen:
out.println("Method: " + request.getMethod());
out.println("Request URI: " + request.getRequestURI());
out.println("Protocol: " + request.getProtocol());
out.println("PathInfo: " + request.getPathInfo());
out.println("Remote Address: " + request.getRemoteAddr());
Im Folgenden finden Sie eine Liste einiger der verfügbaren Methoden und deren Bedeutung:
Methode | Bedeutung |
Name des Webservers | |
der Arbeitsport des Webservers | |
die vom Browser für die Anfrage verwendete Methode GET oder POST | |
der Name des Client-Rechners, von dem aus der Browser seine Anfrage gestellt hat | |
die Adresse IP dieses Rechners | |
der vom Browser gesendete Inhaltstyp (HTTP-Header Content-type) | |
die Anzahl der vom Browser gesendeten Zeichen (HTTP-Header Content-length) | |
die vom Browser angeforderte HTTP-Protokollversion | |
die vom Browser angeforderte URI. Entspricht dem Teil der URL, der nach der Kennung hote:port in „http://hote:port/URI“ steht |
3.1.5. Ein Servlet mit JBuilder erstellen und mit Tomcat bereitstellen
Wir beschreiben nun, wie man ein Java-Servlet erstellt und ausführt. Dazu verwenden wir zwei Tools: JBuilder zum Kompilieren des Servlets und Tomcat zum Ausführen. Tomcat allein würde zwar ausreichen, bietet jedoch nur eingeschränkte Debugging-Funktionen. Wir greifen auf das zuvor entwickelte Beispiel zurück, das die vom Server empfangenen Parameter anzeigt. Das Servlet sendet zunächst das folgende Eingabeformular:

Die vom Servlet gesendete Antwort:

Der Quellcode des Servlets lautet wie folgt:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class myRequestParamExample extends HttpServlet {
String title="Récupération des paramètres d'un formulaire";
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
out.println("<h3>" + title + "</h3>");
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
if (firstName != null || lastName != null) {
out.println("firstname= " + firstName + "<br>");
out.println("lastname= " + lastName);
} else {
out.println("pas de paramètres");
}
out.println("<P>");
out.print("<form action=\"RequestParamExample\" method=\"POST\">");
out.println("firstname= <input type=text size=20 name=firstname>");
out.println("<br>");
out.println("lastname= <input type=text size=20 name=lastname>");
out.println("<br>");
out.println("<input type=submit>");
out.println("</form>");
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
}
- Erstellen Sie mit JBuilder ein Projekt namens myRequestParamExample und fügen Sie das vorherige Programm myRequestParamExample.java darin ein.
- Bei der Kompilierung kann folgendes Problem auftreten: Ihr JBuilder verfügt nicht unbedingt über die Bibliothek javax.servlet, die für die Kompilierung der Servlets erforderlich ist. In diesem Fall müssen Sie JBuilder so konfigurieren, dass es zusätzliche Klassenbibliotheken verwendet. Die Vorgehensweise ist in den Anhängen dieses Dokuments für JBuilder 7 beschrieben. Wir geben sie hier teilweise wieder:
- Aktivieren Sie die Option „Tools/Configure JDKs“ oder „Options/Configure JDK“

Im obigen Abschnitt „JDK-Einstellungen“ steht normalerweise im Feld „Name“ die Version 1.3.1. Wenn Sie eine neuere Version von JDK haben, verwenden Sie die Schaltfläche Change, um das Installationsverzeichnis dieser Version anzugeben. Oben wurde das Verzeichnis E:\Program Files\jdk14 angegeben, in dem ein JDK 1.4 installiert war. Von nun an wird JBuilder dieses JDK für seine Kompilierungen und Ausführungen verwenden. Im Bereich (Class, Source, Documentation) finden Sie die Liste aller Klassenbibliotheken, die von JBuilder durchsucht werden, in diesem Fall die Klassen von JDK 1.4. Die darin enthaltenen Klassen reichen für die Webentwicklung in Java nicht aus. Um weitere Klassenbibliotheken hinzuzufügen, verwendet man die Schaltfläche „Add“ und wählt die zusätzlichen .jar-Dateien aus, die man verwenden möchte. Die .jar-Dateien sind Klassenbibliotheken. Tomcat 4.x enthält alle für die Webentwicklung erforderlichen Klassenbibliotheken. Diese befinden sich in <tomcat>\common\lib, wobei <tomcat> das Installationsverzeichnis von Tomcat ist:

Mit der Schaltfläche Add fügen wir diese Bibliotheken nacheinander zur Liste der von JBuilder durchsuchten Bibliotheken hinzu:

Ab sofort können Java-Programme gemäß dem Standard J2EE kompiliert werden, insbesondere Java-Servlets. JBuilder dient lediglich der Kompilierung, die Ausführung erfolgt anschließend durch Tomcat.
- Nun können Sie das Programm myRequestParamExample.java kompilieren und das Servlet myRequestParamExample.class erstellen. Wo soll dieses Servlet abgelegt werden? Wenn die ursprüngliche Konfiguration von Tomcat nicht geändert wurde, müssen die Servlets im Verzeichnis <tomcat>\webapps\examples\WEB-INF\classes (Tomcat 4.x) abgelegt werden.
- Stellen Sie sicher, dass Tomcat gestartet ist, und rufen Sie mit einem Browser die Seite URL unter http://localhost:8080/examples/servlet/myRequestParamExample auf:

3.1.6. Beispiele
Für die folgenden Beispiele haben wir die zuvor beschriebene Methode verwendet:
- Kompilierung der Servlet-Quelldatei XX.java mit JBuilder
- Bereitstellung des Servlets XX.class in <tomcat>\webapps\examples\WEB-INF\classes
- Tomcat gestartet, mit einem Browser die Seite URL unter http://localhost:8080/examples/servlet/XX aufrufen
3.1.6.1. Dynamische Formularerstellung – 1
Als Beispiel nehmen wir die Erstellung eines Formulars, das nur ein Steuerelement enthält: eine Liste. Der Inhalt dieser Liste wird dynamisch aus Werten aus einem Array zusammengestellt. In der Praxis werden diese Werte häufig aus einer Datenbank abgerufen. Das Formular sieht wie folgt aus:

Wenn man im obigen Beispiel Envoyer eingibt, erhält man folgende Antwort:

Man beachte, dass der Code „URL“, der die Antwort liefert, derselbe ist wie der, der das Formular anzeigt. Hier haben wir ein Servlet, das die Antwort auf das von ihm gesendete Formular selbst verarbeitet. Dies ist ein häufiger Fall. Der Code „HTML“ des Formulars lautet wie folgt:
<html>
<head><title>Génération de formulaire</title></head>
<body>
<h3>Choississez un nombre</h3><hr>
<form method="POST">
<select name="cmbValeurs" size="1">
<option>zéro</option>
<option>un</option>
<option>deux</option>
<option>trois</option>
<option>quatre</option>
<option>cinq</option>
<option>six</option>
<option>sept</option>
<option>huit</option>
<option>neuf</option>
</select>
<input type="submit" value="Envoyer">
</form>
</body>
</html>
Es ist zu beachten, dass die vom Formular gesendeten Werte über die Methode POST übermittelt werden. Der Code HTML in der Antwort:
<html>
<head><title>Voici ma réponse</title></head>
<body>
Vous avez choisi le nombre<h2>neuf</h2>
</body>
</html>
Der Code des Servlets, das dieses Formular und diese Antwort generiert, lautet wie folgt:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class gener1 extends HttpServlet{
// Instanzvariablen
private String title="Génération d'un formulaire";
private final String[] valeurs={"zéro","un","deux","trois","quatre","cinq","six",
"sept","huit","neuf"};
private final String HTML1=
"<html>" +
"<head>" +
"<title>Génération de formulaire</title>"+
"</head>" +
"<body>" +
"<h3>Choississez un nombre</h3>"+
"<hr>" +
"<form method=\"POST\">";
private final String HTML2="<input type=\"submit\" value=\"Envoyer\">";
private final String HTML3="</form>\n</body>\n</html>";
// GET
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// dem Kunden wird der Typ des gesendeten Dokuments mitgeteilt
response.setContentType("text/html");
// Das Formular wird gesendet
PrintWriter out=response.getWriter();
// Start
out.println(HTML1);
// Kombinationsfeld
out.println("<select name=\"cmbValeurs\" size=\"1\">");
for (int i=0;i<valeurs.length;i++){
out.println("<option>"+valeurs[i]+"</option>");
}//für
out.println("</select>");
// Ende des Formulars
out.println(HTML2+HTML3);
}//GET
// POST
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// die Auswahl des Benutzers wird abgerufen
String choix=request.getParameter("cmbValeurs");
if(choix==null) doGet(request,response);
// die Antwort wird vorbereitet
String réponse="<html><head><title>Voici ma réponse</title></head>";
réponse+="<body>Vous avez choisi le nombre <h2>"+choix+"</h2></body></html>";
// dem Kunden wird der Typ des gesendeten Dokuments mitgeteilt
response.setContentType("text/html");
// Das Formular wird gesendet
PrintWriter out=response.getWriter();
out.println(réponse);
}//POST
}//Klassifizierung
Die Methode doGet dient zur Generierung des Formulars. Es gibt einen dynamischen Teil, nämlich den Inhalt der Liste, der hier aus einer Tabelle stammt. Die Methode doPost dient zur Generierung der Antwort. Hier ist der einzige dynamische Teil der Wert der vom Benutzer in der Formularliste getroffenen Auswahl. Dieser Wert wird über request.getParameter("cmbValeurs") ermittelt, wobei cmbValeurs der Name der Liste ist:
Abschließend sind folgende Punkte zu beachten:
- Der Browser sendet die Werte des Formulars an das Servlet, das das Formular generiert hat, da das Tag <form> kein Attribut <action> besitzt. In diesem Fall sendet der Browser die im Formular eingegebenen Daten an das URL, das das Formular bereitgestellt hat.
- Das Tag <form> legt fest, dass die Formulardaten über die Methode POST übermittelt werden müssen. Aus diesem Grund werden diese Werte von der Methode doPost des Servlets abgerufen.
3.1.6.2. Dynamische Formularerstellung – 2
Wir greifen das vorherige Beispiel wieder auf und ändern es wie folgt. Das vorgeschlagene Formular ist weiterhin dasselbe:

Ist die Antwort nun anders:

In der Antwort wird das Formular zurückgesendet, wobei die vom Benutzer gewählte Zahl darunter angegeben ist. Außerdem ist dies die Zahl, die bei der Anzeige der Liste als ausgewählt erscheint. Der Benutzer kann dann eine andere Zahl auswählen:

und anschließend Envoyer aufrufen. Er erhält folgende Antwort:

Der Code des aufgerufenen Servlets gener2.java lautet wie folgt:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class gener2 extends HttpServlet{
// Instanzvariablen
private String title="Génération d'un formulaire";
private final String[] valeurs={"zéro","un","deux","trois","quatre","cinq","six",
"sept","huit","neuf"};
private final String HTML1=
"<html>" +
"<head>" +
"<title>Génération de formulaire</title>"+
"</head>" +
"<body>" +
"<h3>Choisissez un nombre</h3>"+
"<hr>" +
"<form method=\"POST\">";
private final String HTML2="<input type=\"submit\" value=\"Envoyer\"></form>\n";
private final String HTML3="</body>\n</html>";
// GET
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// Die eventuelle Auswahl des Benutzers wird abgerufen
String choix=request.getParameter("cmbValeurs");
if(choix==null) choix="";
// dem Kunden wird der Typ des gesendeten Dokuments mitgeteilt
response.setContentType("text/html");
// Das Formular wird gesendet
PrintWriter out=response.getWriter();
// Anfang
out.println(HTML1);
// Auswahlfeld
out.println("<select name=\"cmbValeurs\" size=\"1\">");
String selected="";
for (int i=0;i<valeurs.length;i++){
if(valeurs[i].equals(choix)) selected="selected"; else selected="";
out.println("<option "+selected+">"+valeurs[i]+"</option>");
}//für
out.println("</select>");
// Fortsetzung des Formulars
out.println(HTML2);
if(! choix.equals("")){
// Die Auswahl des Benutzers wird angezeigt
out.println("<hr>Vous avez choisi le nombre <h2>"+choix+"</h2>");
}//if
// Ende des Formulars
out.println(HTML3);
}//GET
// POST
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// Weiterleitung zu GET
doGet(request,response);
}//POST
}//Klasse
Die Methode doGet übernimmt alle Aufgaben: Sie erstellt das Formular, das sie an den Client sendet, und verarbeitet die vom Client zurückgesendeten Werte. Folgende Punkte sind zu beachten:
- Es wird geprüft, ob der Parameter cmbValeurs einen Wert hat.
- Ist dies der Fall, wird bei der Erstellung des Listeninhalts jedes Element der Liste mit der Auswahl des Benutzers verglichen, um das Attribut selected dem vom Benutzer ausgewählten Element zuzuweisen: <option selected>Element</option>. Außerdem wird unterhalb des Formulars der Wert der Auswahl angezeigt.
3.1.6.3. Dynamische Formularerstellung – 3
Wir greifen dasselbe Problem wie zuvor auf, doch diesmal werden die Werte aus einer Datenbank abgerufen. In unserem Beispiel handelt es sich dabei um die Datenbank MySQL:
- Die Datenbank heißt dbValeurs
- Der Eigentümer ist admDbValeurs mit dem Passwort mdpDbValeurs
- Die Datenbank enthält eine einzige Tabelle namens „tvaleurs“
- Diese Tabelle enthält nur ein Ganzzahlfeld namens „wert“
E:\Program Files\EasyPHP\mysql\bin>mysql --database=dbValeurs --user=admDbValeurs --password=mdpDbVa
leurs
mysql> show tables;
+---------------------+
| Tables_in_dbValeurs |
+---------------------+
| tvaleurs |
+---------------------+
1 row in set (0.00 sec)
mysql> describe tvaleurs;
+--------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------+------+-----+---------+-------+
| valeur | int(11) | | | 0 | |
+--------+---------+------+-----+---------+-------+
mysql> select * from tvaleurs;
+--------+
| valeur |
+--------+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 6 |
| 5 |
| 7 |
| 8 |
| 9 |
+--------+
10 rows in set (0.00 sec)
Die Datenbank MySQL dbValeurs wurde über einen Treiber ODBC für MySQL zugänglich gemacht. Ihr Name DSN (Data Source Name) lautet „odbc-valeurs“. Der Servlet-Code lautet wie folgt:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
import java.util.*;
public class gener3 extends HttpServlet{
// der Seitentitel
private final String title="Génération d'un formulaire";
// die Datenbank mit den Listenwerten
private final String DSNValeurs="odbc-valeurs";
private final String admDbValeurs="admDbValeurs";
private final String mdpDbValeurs="mdpDbValeurs";
// Listenwerte
private String[] valeurs=null;
// Fehlermeldung
private String msgErreur=null;
// Code HTML
private final String HTML1=
"<html>" +
"<head>" +
"<title>Génération de formulaire</title>"+
"</head>" +
"<body>" +
"<h3>Choisissez un nombre</h3>"+
"<hr>" +
"<form method=\"POST\">";
private final String HTML2="<input type=\"submit\" value=\"Envoyer\"></form>\n";
private final String HTML3="</body>\n</html>";
// GET
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// Dem Kunden wird die Art des gesendeten Dokuments mitgeteilt
response.setContentType("text/html");
// Ausgabestrom
PrintWriter out=response.getWriter();
// Ist die Initialisierung des Servlets erfolgreich verlaufen?
if (msgErreur!=null){
// Es ist ein Fehler aufgetreten – es wird eine Fehlerseite generiert
out.println("<html><head><title>"+title+"</title></head>");
out.println("<body><h3>Application indisponible ("+msgErreur+
")</h3></body></html>");
return;
}//if
// Die eventuelle Auswahl des Benutzers wird abgerufen
String choix=request.getParameter("cmbValeurs");
if(choix==null) choix="";
// Das Formular wird gesendet
// Anfang
out.println(HTML1);
// Kombinationsfeld
out.println("<select name=\"cmbValeurs\" size=\"1\">");
String selected="";
for (int i=0;i<valeurs.length;i++){
if(valeurs[i].equals(choix)) selected="selected"; else selected="";
out.println("<option "+selected+">"+valeurs[i]+"</option>");
}//für
out.println("</select>");
// Fortsetzung des Formulars
out.println(HTML2);
if(! choix.equals("")){
// Die Auswahl des Benutzers wird angezeigt
out.println("<hr>Vous avez choisi le nombre <h2>"+choix+"</h2>");
}//if
// Ende des Formulars
out.println(HTML3);
}//GET
// POST
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// Weiterleitung zu GET
doGet(request,response);
}//POST
// Initialisierung des Servlets
public void init(){
// Füllt das Wertearray aus einer Datenbank ODBC
// mit dem Namen DSN: DSNvaleurs
Connection connexion=null;
Statement st=null;
ResultSet rs=null;
try{
// Verbindung zur Datenbank ODBC
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
connexion=DriverManager.getConnection("jdbc:odbc:"+DSNValeurs,admDbValeurs,mdpDbValeurs);
// Statement-Objekt
st=connexion.createStatement();
// Ausführung einer SELECT-Abfrage zum Abrufen der Werte
rs=st.executeQuery("select valeur from Tvaleurs");
// Die Werte werden abgerufen und in ein dynamisches Array gespeichert
ArrayList lstValeurs=new ArrayList();
while(rs.next()){
// Der Wert wird in die Liste geschrieben
lstValeurs.add(rs.getString("valeur"));
}//while
// Umwandlung von Liste in Array
valeurs=new String[lstValeurs.size()];
for (int i=0;i<lstValeurs.size();i++){
valeurs[i]=(String)lstValeurs.get(i);
}
}catch(Exception ex){
// Problem
msgErreur=ex.getMessage();
}finally{
try{rs.close();}catch(Exception ex){}
try{st.close();}catch(Exception ex){}
try{connexion.close();}catch(Exception ex){}
}//try
}//initialisieren
}//Klasse
Folgende wichtige Punkte sind zu beachten:
- Ein Servlet kann über eine Methode initialisiert werden, deren Signatur „public void init()“ lauten muss. Diese Methode wird nur beim ersten Laden des Servlets ausgeführt
- Sobald ein Servlet geladen ist, bleibt es ständig im Speicher. Das bedeutet, dass es nach der Bedienung eines Clients nicht entladen wird. Dadurch reagiert es schneller auf Client-Anfragen.
- In unserem Servlet muss eine Liste von Werten aus einer Datenbank abgerufen werden. Da sich diese Liste im Laufe der Zeit nicht ändert, ist die Methode `init` der ideale Zeitpunkt, um sie abzurufen. Auf die Datenbank wird somit nur einmal vom Servlet aus zugegriffen, nämlich beim ersten Laden des Servlets, und nicht bei jeder Anfrage eines Clients.
- Der Zugriff auf eine Datenbank kann fehlschlagen. Die Methode init unseres Servlets setzt im Falle eines Fehlers eine Fehlermeldung msgErreur. Diese Meldung wird in der Methode doGet geprüft, und falls ein Fehler aufgetreten ist, generiert doGet eine Seite, die darauf hinweist.
- Die Implementierung der Methode „init“ nutzt einen klassischen Datenbankzugriff mit den ODBC-JDBC-Treibern. Bei Bedarf wird der Leser gebeten, die Methoden für den Datenbankzugriff JDBC noch einmal durchzugehen.
Wenn das Servlet ausgeführt wird und der Server MySQL nicht gestartet wurde, erscheint die folgende Fehlerseite:
![]()
Startet man nun den Server MySQL, erhält man die folgende Seite:

Wählt man die Zahl 6 aus und klickt auf „Senden“:

3.1.6.4. Werte aus einem Formular abrufen
Wir greifen ein bereits bekanntes Beispiel wieder auf, nämlich das folgende Webformular:

Der Code HTML des Formulars balises2.htm lautet wie folgt:
<html>
<head>
<title>balises</title>
<script language="JavaScript">
function effacer(){
alert("Vous avez cliqué sur le bouton Effacer");
}//löschen
</script>
</head>
<body background="/images/standard.jpg">
...
<form method="POST" action="http://localhost:8080/examples/servlet/parameters">
<table border="0">
<tr>
<td>Etes-vous marié(e)</td>
<td>
<input type="radio" value="Oui" name="R1">Oui
<input type="radio" name="R1" value="non" checked>Non
</td>
</tr>
<tr>
<td>Cases à cocher</td>
<td>
<input type="checkbox" name="C1" value="un">1
<input type="checkbox" name="C2" value="deux" checked>2
<input type="checkbox" name="C3" value="trois">3
</td>
</tr>
<tr>
<td>Champ de saisie</td>
<td>
<input type="text" name="txtSaisie" size="20" value="qqs mots">
</td>
</tr>
<tr>
<td>Mot de passe</td>
<td>
<input type="password" name="txtMdp" size="20" value="unMotDePasse">
</td>
</tr>
<tr>
<td>Boîte de saisie</td>
<td>
<textarea rows="2" name="areaSaisie" cols="20">
ligne1
ligne2
ligne3
</textarea>
</td>
</tr>
<tr>
<td>combo</td>
<td>
<select size="1" name="cmbValeurs">
<option>choix1</option>
<option selected>choix2</option>
<option>choix3</option>
</select>
</td>
</tr>
<tr>
<td>liste à choix simple</td>
<td>
<select size="3" name="lst1">
<option selected>liste1</option>
<option>liste2</option>
<option>liste3</option>
<option>liste4</option>
<option>liste5</option>
</select>
</td>
</tr>
<tr>
<td>liste à choix multiple</td>
<td>
<select size="3" name="lst2" multiple>
<option selected>liste1</option>
<option>liste2</option>
<option selected>liste3</option>
<option>liste4</option>
<option>liste5</option>
</select>
</td>
</tr>
<tr>
<td>bouton</td>
<td>
<input type="button" value="Effacer" name="cmdEffacer" onclick="effacer()">
</td>
</tr>
<tr>
<td>envoyer</td>
<td>
<input type="submit" value="Envoyer" name="cmdRenvoyer">
</td>
</tr>
<tr>
<td>rétablir</td>
<td>
<input type="reset" value="Rétablir" name="cmdRétablir">
</td>
</tr>
</table>
<input type="hidden" name="secret" value="uneValeur">
</form>
</body>
</html>
Das Formular-Tag <form> wurde wie folgt definiert:
Der Browser „sendet“ die Werte des Formulars an das URL http://localhost:8080/examples/servlet/parameters, bei dem es sich um das URL eines von Tomcat verwalteten Servlets handelt, das die Werte des vorherigen Formulars anzeigt. Ruft man das Servlet parameters direkt auf, erhält man folgende Ergebnisse:

Wenn das eingegebene Formular balises2.htm wie folgt lautet:

und die Schaltfläche „Senden“ (vom Typ submit) angeklickt wird, wird diesmal das Servlet parameters mit Parametern aufgerufen. Es gibt dann die folgende Antwort zurück:

In dieser Antwort sind die im Formular eingegebenen Werte tatsächlich enthalten. Der Code des Servlets lautet wie folgt:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class parameters extends HttpServlet{
// Instanzvariablen
String title="Récupération des paramètres d'un formulaire";
private String getParameter(HttpServletRequest request, String contrôle){
// gibt den Wert request.getParameter (Prüfung) oder "" zurück, falls sie nicht vorhanden ist
String valeur=request.getParameter(contrôle);
if(valeur==null) return ""; else return valeur;
}//getParameter
// GET
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException
{
// Zunächst werden die Parameter des Formulars abgerufen
String R1=getParameter(request,"R1");
String C1=getParameter(request,"C1");
String C2=getParameter(request,"C2");
String C3=getParameter(request,"C3");
String txtSaisie=getParameter(request,"txtSaisie");
String txtMdp=getParameter(request,"txtMdp");
String areaSaisie=getParameter(request,"areaSaisie");
String[] lignes=areaSaisie.split("\\r\\n");
String cmbValeurs=getParameter(request,"cmbValeurs");
String lst1=getParameter(request,"lst1");
String[] lst2=request.getParameterValues("lst2");
String secret=getParameter(request,"secret");
// Anschließend wird der Inhalt des Dokuments angegeben
response.setContentType("text/html");
// Das Dokument wird gesendet
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
out.println("<h3>" + title + "</h3>");
out.println("<hr>");
out.println("<table border=\"1\">");
out.println("<tr><td>R1</td><td>"+R1+"</td></tr>");
out.println("<tr><td>C1</td><td>"+C1+"</td></tr>");
out.println("<tr><td>C2</td><td>"+C2+"</td></tr>");
out.println("<tr><td>C3</td><td>"+C3+"</td></tr>");
out.println("<tr><td>txtSaisie</td><td>"+txtSaisie+"</td></tr>");
out.println("<tr><td>txtMdp</td><td>"+txtMdp+"</td></tr>");
for(int i=0;i<lignes.length;i++)
out.println("<tr><td>areaSaisie["+i+"]</td><td>"+lignes[i]+"</td></tr>");
out.println("<tr><td>cmbValeurs</td><td>"+cmbValeurs+"</td></tr>");
out.println("<tr><td>lst1</td><td>"+lst1+"</td></tr>");
if(lst2==null)
out.println("<tr><td>lst2</td><td></td></tr>");
else
for(int i=0;i<lst2.length;i++)
out.println("<tr><td>lst2</td><td>"+lst2[i]+"</td></tr>");
out.println("<tr><td>secret</td><td>"+secret+"</td></tr>");
out.println("</body>");
out.println("</html>");
}
// POST
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException
{
// leitet weiter zu GET
doGet(request,response);
}
}
In diesem Code finden sich die zuvor in einem anderen Beispiel vorgestellten Techniken wieder. Dabei sind zwei Punkte zu beachten:
- Das Steuerelement lst2 ist eine Mehrfachauswahlliste, sodass mehrere Elemente ausgewählt werden können. Dies ist in unserem Beispiel der Fall, in dem die Elemente liste1 und liste3 ausgewählt wurden. Die Werte von lst2 wurden vom Browser in der Form lst2=liste1&lst2=liste3 an den Server übermittelt. Das Java-Servlet kann diese Werte mit der Methode getParameterValues in ein Array abrufen: Hier liefert request.getParameterValues("lst2") ein Array mit zwei Zeichenketten ["liste1","liste3"].
- Das Steuerelement areaSaisie ist ein mehrzeiliges Eingabefeld. request.getParameter("areaSaisie") gibt den Inhalt des Feldes in Form einer einzigen Zeichenkette zurück. Wenn man daraus die einzelnen Zeilen extrahieren möchte, kann man die Funktion split der Klasse String verwenden. Der folgende Code
extrahiert die Zeilen aus dem Eingabefeld. Diese Zeilen enden mit den Zeichen \r\n (0D0A).
Für die Tests haben wir:
- das Servlet parameters mit JBuilder erstellt und kompiliert, wie zuvor erläutert
- die generierte Klasse in <tomcat>\webapps\examples\WEB-INF\classes abgelegt, wobei <tomcat> das Installationsverzeichnis von Tomcat ist.
- die Seite URL http://localhost:81/html/balises2.htm aufgerufen, deren Code oben vorgestellt wurde
- das Formular ausgefüllt und auf die Schaltfläche Envoyer geklickt.
3.1.6.5. Abrufen der Header von einem Webclient
Wir greifen das gleiche Beispiel wie zuvor auf, senden dem Webclient, der die Formularwerte übermittelt hat, jedoch als Antwort die Header HTTP zurück, die er gleichzeitig gesendet hat. Wir nehmen eine einzige Änderung an unserem Formular vor:
Die Formularwerte werden über die Methode GET an ein Java-Servlet namens headers gesendet, das sich in <tomcat>\webapps\examples\WEB-INF\classes befindet. Das Servlet headers wurde zusammen mit JBuilder erstellt und kompiliert:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class headers extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
// Die Art des Dokuments wird festgelegt
response.setContentType("text/html");
// ein Schreibstrom wird generiert
PrintWriter out = response.getWriter();
// Anzeige der Kopfzeilenliste HTTP
Enumeration e = request.getHeaderNames();
while (e.hasMoreElements()) {
String name = (String)e.nextElement();
String value = request.getHeader(name);
out.println("<b>"+name + "</b> = " + value + "<br>");
}
}//GET
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
//GET
doGet(request,response);
}//POST
}
Man fragt „URLhttp://localhost:81/html/balises2.htm“ ab und führt „Envoyer“ aus, ohne das Formular zu ändern. Man erhält folgende Antwort:

Man beachte den im Feld Address des Browsers angezeigten Wert URL, der die Art und Weise (GET) zeigt, wie die Parameter übermittelt wurden. Wir nehmen dasselbe Beispiel wieder auf, ändern jedoch die Art und Weise, wie die Parameter gesendet werden (POST):
Wir erhalten die folgende neue Antwort:

Zu beachten sind die Kopfzeilen HTTP, content-type und content-length, die für eine Übermittlung über POST charakteristisch sind. Außerdem ist zu beachten, dass im Feld Address des Browsers die Werte des Formulars nicht mehr angezeigt werden.
3.2. JSP-Seiten
Die Seiten JSP (Java Server Pages) stellen eine weitere Möglichkeit dar, Webserver-Anwendungen zu schreiben. Tatsächlich werden diese Seiten JSP vor ihrer Ausführung in Servlets übersetzt, sodass hier die Servlet-Technologie zum Einsatz kommt. Die JSP-Seiten ermöglichen es, die Struktur der generierten HTML-Seiten besser hervorzuheben. Im Folgenden stellen wir Beispiele vor, von denen einige über den Link JSP auf der Tomcat-Startseite aufgerufen werden können:
![]() | ![]() |
3.2.1. Umgebungsinformationen abrufen
Wir greifen hier ein bereits mit einem Servlet behandeltes Beispiel wieder auf: die Anzeige der Umgebungsvariablen eines Servlets. Es handelt sich um das Beispiel snoop aus den Beispielen JSP:

Der Quellcode der Seite JSP befindet sich unter <tomcat>\jakarta-tomcat\examples\jsp\snp\snoop.jsp (Tomcat 3.x) oder unter <tomcat>\examples\jsp\snp\snoop.jsp (Tomcat 4.x)
<html>
<!--
Copyright (c) 1999 The Apache Software Foundation. All rights
reserved.
-->
<body bgcolor="white">
<h1> Request Information </h1>
<font size="4">
JSP Request Method: <%= request.getMethod() %>
<br>
Request URI: <%= request.getRequestURI() %>
<br>
Request Protocol: <%= request.getProtocol() %>
<br>
Servlet path: <%= request.getServletPath() %>
<br>
Path info: <%= request.getPathInfo() %>
<br>
Path translated: <%= request.getPathTranslated() %>
<br>
Query string: <%= request.getQueryString() %>
<br>
Content length: <%= request.getContentLength() %>
<br>
Content type: <%= request.getContentType() %>
<br>
Server name: <%= request.getServerName() %>
<br>
Server port: <%= request.getServerPort() %>
<br>
Remote user: <%= request.getRemoteUser() %>
<br>
Remote address: <%= request.getRemoteAddr() %>
<br>
Remote host: <%= request.getRemoteHost() %>
<br>
Authorization scheme: <%= request.getAuthType() %>
<hr>
The browser you are using is <%= request.getHeader("User-Agent") %>
<hr>
</font>
</body>
</html>
Folgendes ist zu beachten:
- Hier handelt es sich um einen Code, der stark an HTML erinnert. Es sind jedoch Tags wie <%= Ausdruck %> vorhanden, die für die Sprache JSP spezifisch sind. Der Compiler JSP ersetzt im Text HTML das gesamte Tag durch den Wert von expression.
- In diesem Beispiel werden die Methoden des Java-Objekts request verwendet, bei dem es sich um das Objekt request handelt, das bereits bei der Behandlung von Servlets vorgestellt wurde. Es handelt sich also um ein Objekt HttpServletRequest. Somit wird das Tag <%= request.getRemoteHost() %> im Code HTML durch den Namen des Rechners des Web-Clients ersetzt, der die Anfrage gestellt hat.
- Man kann das gleiche Ergebnis auch mit einem Servlet erzielen, aber hier ist die Struktur der Webseite übersichtlicher.
3.2.2. Vom Web-Client gesendete Parameter abrufen
Wir greifen hier das bereits mit einem Servlet behandelte Beispiel wieder auf. Dem Browser wird ein Formular angezeigt:

Als Antwort auf die obige Anfrage erhält der Browser die folgende Seite:

Der Code der Seite JSP lautet wie folgt:
<%
// lokale Variablen der Hauptprozedur
String title="Récupération des paramètres d'un formulaire";
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
%>
<!-- Code HTML -->
<html>
<head>
<title><%= title %></title>
</head>
<body bgcolor="white">
<h3><%= title %></h3>
<%
if (firstName != null || lastName != null) {
out.println("firstname= " + firstName + "<br>");
out.println("lastname= " + lastName);
} else {
out.println("pas de paramètres");
}
%>
<P>
<form method="POST">
firstname= <input type="text" size="20" name="firstname">
<br>
lastname= <input type="text" size="20" name="lastname">
<br>
<input type="submit">
</form>
</body>
</html>
- Neben dem Tag <%= Ausdruck %>, das bereits im vorherigen Beispiel vorkam, taucht nun ein neues Tag auf: <% Java-Anweisungen; %>. Das Tag <% leitet Java-Code ein. Dieser Code endet an der Stelle, an der das schließende Code-Tag %> auftritt.
- Der gesamte vorstehende Code (HTML + JSP) wird in ein Java-Servlet umgewandelt. Er wird in einer einzigen Methode zusammengefasst, die als Hauptmethode der Seite JSP bezeichnet wird. Aus diesem Grund sind die zu Beginn der Seite JSP deklarierten Java-Variablen in den anderen Codeabschnitten JSP bekannt, die im Code HTML verstreut sind: Diese Variablen und Codeabschnitte werden Teil derselben Java-Methode sein. Sollte unser Code JSP jedoch Methoden enthalten, wären die Variablen title, firstname und lastname dort aufgrund der Isolation zwischen den Methoden nicht bekannt. Man müsste sie entweder zu globalen Variablen machen oder als Parameter an die Methoden übergeben. Wir werden darauf zurückkommen.
- Um dynamische Teile in den Code HTML einzubinden, gibt es zwei Möglichkeiten: <%= Ausdruck %> oder out.println(Ausdruck). Das Objekt out ist ein Ausgabestrom, der dem gleichnamigen aus den Servlet-Beispielen ähnelt, jedoch nicht vom gleichen Typ ist: Es handelt sich um ein JspWriter-Objekt und nicht um ein PrintWriter-Objekt. Es ermöglicht das Schreiben in den Stream HTML mit den Methoden print und println.
- Die Seite JSP spiegelt die Struktur der generierten Seite HTML besser wider als das entsprechende Servlet.
3.2.3. Die Tags JSP
Hier finden Sie eine Liste der Tags, die in einer Seite JSP vorkommen können, sowie deren Bedeutung.
Tag | Bedeutung |
Kommentar HTML. Wird an den Client gesendet. | |
Kommentar JSP. Wird nicht an den Kunden gesendet. | |
Deklariert globale Variablen und Methoden. Die Variablen sind in allen Methoden bekannt. | |
Der Wert des Ausdrucks wird anstelle des Tags in die Seite HTML eingebunden | |
enthält Java-Code, der Teil der Hauptmethode der Seite JSP sein wird | |
legt Attribute für die Seite JSP fest. Beispiel: import="java.util.*,java.sql.*", um die für die Seite JSP erforderlichen Bibliotheken anzugeben extends="eineÜberklasse", um die JSP-Seite von einer anderen Klasse ableiten zu lassen |
3.2.4. Die impliziten Objekte JSP
In den vorangegangenen Beispielen sind wir auf zwei nicht deklarierte Objekte gestoßen: request und out. Dies sind zwei der Objekte, die automatisch in dem Servlet definiert werden, in das die Seite JSP konvertiert wird. Man bezeichnet sie als implizite oder vordefinierte Objekte. Es gibt noch weitere, doch diese werden zusammen mit dem Objekt response am häufigsten verwendet:
Objekt | Bedeutung |
Das Objekt, über das man Zugriff auf die Anfrage des Web-Clients hat (getParameter, getParameterNames, getParameterValues) | |
das Objekt, mit dem die Antwort des Webservers an seinen Client erstellt werden kann. Ermöglicht die Festlegung der HTTP-Header, die an den Webclient gesendet werden sollen. | |
Der Ausgabestrom, über den wir den Code HTML an den Client senden können (print, println) |
3.2.5. Die Umwandlung einer Seite JSP in ein Servlet
Nehmen wir den Code JSP aus myRequestParamExample.jsp wieder auf:
<%
// lokale Variablen der Hauptprozedur
String title="Récupération des paramètres d'un formulaire";
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
%>
<!-- Code HTML -->
<html>
<head>
<title><%= title %></title>
</head>
<body bgcolor="white">
<h3><%= title %></h3>
<%
if (firstName != null || lastName != null) {
out.println("firstname= " + firstName + "<br>");
out.println("lastname= " + lastName);
} else {
out.println("pas de paramètres");
}
%>
<P>
<form method="POST">
firstname= <input type="text" size="20" name="firstname">
<br>
lastname= <input type="text" size="20" name="lastname">
<br>
<input type="submit">
</form>
</body>
</html>
Wenn der Browser diese Seite JSP vom Tomcat-Server anfordert, wandelt dieser sie in ein Servlet um. Wenn die angeforderte Seite URL
http://localhost:8080/examples/jsp/perso/intro/myRequestParamExample.jsp, legt Tomcat das generierte Servlet im Verzeichnis <tomcat>\work\localhost\examples\jsp\perso\intro ab:

In diesem Namen findet sich das „URL“http://localhost:8080/examples/jsp/perso/intro/myRequestParamExample.jsp, das der Seite „JSP“ entspricht. Oben ist zu sehen, dass wir Zugriff auf den Java-Code des für die Seite JSP generierten Servlets haben. In unserem Beispiel lautet dieser wie folgt:
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;
public class myRequestParamExample$jsp extends HttpJspBase {
static {
}
public myRequestParamExample$jsp( ) {
}
private static boolean _jspx_inited = false;
public final void _jspx_init() throws org.apache.jasper.runtime.JspException {
}
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
JspFactory _jspxFactory = null;
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
String _value = null;
try {
if (_jspx_inited == false) {
synchronized (this) {
if (_jspx_inited == false) {
_jspx_init();
_jspx_inited = true;
}
}
}
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=ISO-8859-1");
pageContext = _jspxFactory.getPageContext(this, request, response,
"", true, 8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
// lokale Variablen der Hauptprozedur
String title="Récupération des paramètres d'un formulaire";
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
out.write("\r\n\r\n<!-- code HTML -->\r\n<html>\r\n <head>\r\n <title>");
out.print( title );
out.write("</title>\r\n </head>\r\n <body bgcolor=\"white\">\r\n <h3>");
out.print( title );
out.write("</h3>\r\n ");
if (firstName != null || lastName != null) {
out.println("firstname= " + firstName + "<br>");
out.println("lastname= " + lastName);
} else {
out.println("pas de paramètres");
}
out.write("\r\n <P>\r\n <form method=\"POST\">\r\n firstname= <input type=\"text\" size=\"20\" name=\"firstname\">\r\n <br>\r\n lastname= <input type=\"text\" size=\"20\" name=\"lastname\">\r\n <br>\r\n <input type=\"submit\">\r\n </form>\r\n </body>\r\n</html>\r\n");
} catch (Throwable t) {
if (out != null && out.getBufferSize() != 0)
out.clearBuffer();
if (pageContext != null) pageContext.handlePageException(t);
} finally {
if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
}
}
}
Der generierte Code ist recht komplex. Wir beschränken uns daher auf die folgenden Punkte:
- Die Hauptmethode des Servlets lautet wie folgt:
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
Diese Methode wird beim Start des Servlets aufgerufen. Man sieht, dass sie zwei Parameter erhält: die Anfrage request vom Client und ein Objekt response, um die Antwort an den Web-Client zu generieren.
- In der Hauptmethode wird ein Objekt JspWriter namens „out“ deklariert und anschließend initialisiert. Dieses Objekt ermöglicht es, Code HTML über die Anweisung out.print("codeHTML") an den Client zu senden.
- Der Java-Code
<%
// lokale Variablen der Hauptprozedur
String title="Récupération des paramètres d'un formulaire";
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
%>
wurde vollständig in die Hauptmethode _jspService des Servlets übernommen. Gleiches gilt für den gesamten Code innerhalb der Tags <%… %>
- Der Code HTML der Seite JSP ist Gegenstand der Anweisungen out.print("codeHTML") oder out.write(...). Zum Beispiel
out.write("</title>\r\n </head>\r\n <body bgcolor=\"white\">\r\n <h3>");
- In diesem Beispiel gibt es keine anderen Methoden als die Hauptmethode _jspService.
3.2.6. Methoden und globale Variablen einer Seite JSP
Betrachten wir die folgende Seite JSP:
<%!
// Das vorherige Tag leitet den Abschnitt „Globale Variablen und Methoden“ ein
// Dieser Abschnitt wird unverändert in das Servlet übernommen
// eine globale Variable
String prenom="inconnu";
// eine Methode
private String sonChien(){
return "milou";
}//sonChien
// eine weitere Methode
private void afficheAmi(JspWriter out) throws Exception{
out.println("<p>Son ami s'appelle Haddock</p>");
}//afficheAmi
// Ende des globalen Teils des Servlets
%>
<%
// Das vorhergehende Tag gibt an, dass der nachfolgende Code gespeichert wird
// in der Hauptmethode des Servlets
// lokale Variable der Hauptmethode
String nom="tintin";
%>
<%-- Code HTML --%>
<html>
<head>
<title>Page JSP</title>
</head>
<body>
<center>
<h2>Page JSP</h2>
<p>Son nom est <%= nom %></p>
<p>Son prénom est <%= prenom %></p>
<p>Son chien s'appelle <%= sonChien() %></p>
<%
// der Name seines Freundes
afficheAmi(out);
%>
</center>
</body>
</html>
Diese Seite JSP generiert die folgende Webseite:

Schauen wir uns einmal an, wie die vier obigen Zeilen generiert werden:
<p>Son nom est <%= nom %></p>
<p>Son prénom est <%= prenom %></p>
<p>Son chien s'appelle <%= sonChien() %></p>
<%
// der Name seines Freundes
afficheAmi(out);
%>
Die obigen Zeilen befinden sich innerhalb eines <%..%>-Tags und sind somit Teil der Hauptmethode _jspService des Servlets, das generiert wird. Wie greifen sie auf die Variablen nom, prenom und die Methoden sonChien und afficheAmi zu?
ist eine lokale Variable der Hauptmethode der Seite JSP und daher in dieser bekannt | |
ist eine globale Variable der Seite JSP und daher in der Hauptmethode bekannt | |
ist eine öffentliche Methode der Seite JSP und somit von der Hauptmethode aus zugänglich | |
ist eine öffentliche Methode der Seite JSP und somit von der Hauptmethode aus zugänglich. Es ist zu beachten, dass das Objekt out als Parameter an die Methode übergeben wird. Dies ist hier zwingend erforderlich. Das Objekt out wird nämlich in der Hauptmethode des Servlets deklariert und initialisiert und ist keine globale Variable. |
Sehen wir uns nun den Code des Java-Servlets an, das aus dieser Seite JSP generiert wurde, nachdem der überflüssige Code entfernt wurde:
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;
public class tintin$jsp extends HttpJspBase {
// Das vorherige Tag leitet den Abschnitt „Globale Variablen und Methoden“ ein
// Dieser Abschnitt wird unverändert in das Servlet übernommen
// eine globale Variable
String prenom="inconnu";
// eine Methode
private String sonChien(){
return "milou";
}//sonChien
// eine weitere Methode
private void afficheAmi(JspWriter out) throws Exception{
out.println("<p>Son ami s'appelle Haddock</p>");
}//afficheAmi
// Ende des globalen Teils des Servlets
static {
}
public tintin$jsp( ) {
}
private static boolean _jspx_inited = false;
public final void _jspx_init() throws org.apache.jasper.runtime.JspException {
}
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
JspFactory _jspxFactory = null;
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
String _value = null;
try {
if (_jspx_inited == false) {
synchronized (this) {
if (_jspx_inited == false) {
_jspx_init();
_jspx_inited = true;
}
}
}
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=ISO-8859-1");
pageContext = _jspxFactory.getPageContext(this, request, response,
"", true, 8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
out.write(" \r\n\r\n");
// Das vorhergehende Tag gibt an, dass der nachfolgende Code gespeichert wird
// in der Hauptmethode des Servlets
// lokale Variable der Hauptmethode
String nom="tintin";
out.write("\r\n\r\n\r\n");
out.write("\r\n<html>\r\n <head>\r\n <title>Page JSP</title>\r\n </head>\r\n <body>\r\n <center>\r\n <h2>Page JSP</h2>\r\n <p>Son nom est ");
out.print( nom );
out.write("</p>\r\n <p>Son prénom est ");
out.print( prenom );
out.write("</p>\r\n <p>Son chien s'appelle ");
out.print( sonChien() );
out.write("</p>\r\n ");
// der Name seines Freundes
afficheAmi(out);
out.write("\r\n </center>\r\n </body>\r\n</html>\r\n");
} catch (Throwable t) {
if (out != null && out.getBufferSize() != 0)
out.clearBuffer();
if (pageContext != null) pageContext.handlePageException(t);
} finally {
if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
}
}
}
Wie oben zu sehen ist, wurde der Java-Code, der sich zwischen den Tags JSP <%! .. %> befand, vollständig übernommen und ist nicht Teil der Hauptmethode _jspService des Servlets. Die in diesem Abschnitt deklarierten Variablen sind somit Instanzvariablen und gelten daher global für alle Methoden; außerdem können hier auch andere Methoden als _jspService definiert werden.
// Dieser Teil wird unverändert in das Servlet übernommen
// eine globale Variable
String prenom="inconnu";
// eine Methode
private String sonChien(){
return "milou";
}//sonChien
// eine weitere Methode
private void afficheAmi(JspWriter out) throws Exception{
out.println("<p>Son ami s'appelle Haddock</p>");
}//afficheAmi
// Ende des globalen Teils des Servlets
3.2.7. Bereitstellung und Debugging von JSP-Seiten auf dem Tomcat-Server
Wenn man eine Seite JSP erstellen und mit dem Tomcat-Server verwenden möchte, stellt sich die Frage, wo die Seite in der Verzeichnisstruktur des Servers abgelegt werden soll. Es gibt verschiedene Möglichkeiten, auf die wir später noch eingehen werden. Vorerst ist es am einfachsten, die Seite JSP in einem Ordner der Verzeichnisstruktur <tomcat>\webapps\examples\jsp (Tomcat 4.x) abzulegen, wobei <tomcat> das Installationsverzeichnis von Tomcat ist. So lautete beispielsweise die Adresse für URL aus dem vorherigen Beispiel http://localhost:8080/examples/jsp/perso/tintin/tintin.jsp. Das bedeutet, dass sich die Seite tintin.jsp im Ordner <tomcat>\webapps\examples\jsp\perso\tintin befand.
Eine Seite mit dem Namen JSP wird in eine Java-Quelldatei übersetzt, die anschließend von Tomcat kompiliert wird, wenn die Seite JSP (mit der ID URL) von einem Browser angefordert wird. Dabei können Kompilierungsfehler auftreten. Tomcat meldet diese in seiner Antwort an den Browser. Dabei werden insbesondere die fehlerhaften Zeilen der .java-Datei angegeben. Die Fehler können verschiedene Ursachen haben:
- Der Code JSP der Seite ist fehlerhaft (z. B. Fehler in den verwendeten JSP-Tags)
- der in die Seite eingebundene Java-Code JSP ist fehlerhaft
Die erste Ursache lässt sich durch Überprüfung des JSP-Codes der Seite beheben. Die zweite Ursache lässt sich durch Überprüfung des Java-Codes beheben. Dies kann erfolgen, indem die für die Seite JSP generierte .java-Datei direkt mit einem Tool wie JBuilder kompiliert wird, das erweiterte Debugging-Funktionen bietet, die über die von Tomcat hinausgehen.
3.2.8. Beispiele
Wir greifen das bereits behandelte Beispiel mit einem Servlet wieder auf, bei dem ein Benutzer eine Zahl aus einer Liste auswählt und der Server ihm mitteilt, welche Zahl er ausgewählt hat, während er ihm gleichzeitig dieselbe Liste zurücksendet, in der das vom Benutzer ausgewählte Element als ausgewähltes Element markiert ist:

Um diese Seite zu erstellen, haben wir den Code des Servlets übernommen und wie folgt geändert:
- Wir haben den Java-Code, der keinen Code HTML erzeugte, unverändert beibehalten
- Der Java-Code, der den Code HTML erzeugte, wurde in eine Kombination aus dem Code HTML und dem Code JSP umgewandelt
Daraus ergibt sich die folgende Seite JSP:
<%@ page import="java.sql.*, java.util.*" %>
<%!
// globale Variablen der Anwendung
// der Seitentitel
private final String title="Génération d'un formulaire";
// Datenbank mit den Listenwerten
private final String DSNValeurs="odbc-valeurs";
private final String admDbValeurs="admDbValeurs";
private final String mdpDbValeurs="mdpDbValeurs";
// Listenwerte
private String[] valeurs=null;
// Fehlermeldung
private String msgErreur=null;
// Initialisierung der Seite JSP – wird nur einmal ausgeführt
public void jspInit(){
// füllt das Wertetableau aus einer Datenbank ODBC
// mit dem Namen DSN: DSNvaleurs
Connection connexion=null;
Statement st=null;
ResultSet rs=null;
try{
// Verbindung zur Datenbank ODBC
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
connexion=DriverManager.getConnection("jdbc:odbc:"+DSNValeurs,admDbValeurs,mdpDbValeurs);
// Statement-Objekt
st=connexion.createStatement();
// Ausführung einer SELECT-Abfrage zum Abrufen der Werte
rs=st.executeQuery("select valeur from Tvaleurs");
// Die Werte werden abgerufen und in ein dynamisches Array gespeichert
ArrayList lstValeurs=new ArrayList();
while(rs.next()){
// Der Wert wird in die Liste geschrieben
lstValeurs.add(rs.getString("valeur"));
}//while
// Umwandlung von Liste in Array
valeurs=new String[lstValeurs.size()];
for (int i=0;i<lstValeurs.size();i++){
valeurs[i]=(String)lstValeurs.get(i);
}
}catch(Exception ex){
// Problem
msgErreur=ex.getMessage();
}finally{
try{rs.close();}catch(Exception ex){}
try{st.close();}catch(Exception ex){}
try{connexion.close();}catch(Exception ex){}
}//try
}//Initialisierung
%>
<%
// Code von _jspService, der bei jeder Client-Anfrage ausgeführt wird
// Ist bei der Initialisierung der Seite JSP ein Fehler aufgetreten?
if(msgErreur!=null){
%>
<!-- Code HTML -->
<html>
<head>
<title>Erreur</title>
</head>
<body>
<h3>Application indisponible (<%= msgErreur %></h3>
</body>
</html>
<%
// Ende von jspService
return;
}//if
// wird die eventuelle Auswahl des Benutzers abgerufen
String choix=request.getParameter("cmbValeurs");
if(choix==null) choix="";
%>
<%-- kein Fehler – Code HTML der normalen Seite --%>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h3>Choisissez une valeur</h3>
<form method="POST">
<select name="cmbValeurs">
<%
// Dynamische Anzeige der Werte
String selected="";
for (int i=0;i<valeurs.length;i++){
if(valeurs[i].equals(choix)) selected="selected"; else selected="";
out.println("<option "+selected+">"+valeurs[i]+"</option>");
}//für
%>
</select>
<input type="submit" value="Envoyer">
</form>
<%
// Wurde ein Wert ausgewählt?
if(! choix.equals("")){
// Die Auswahl des Benutzers wird angezeigt
%>
<hr>Vous avez choisi le nombre<h2><%= choix %></h2>
<%
}//if
%>
</body>
</html>
Beachten Sie bitte Folgendes:
- Die Anweisungen import des Servlets wurden mit einer <% page import="..." %>-Anweisung umgeben
- Das Tag <%! ... %> umschließt die globalen Variablen und die Java-Methoden der Anwendung
- Die Methode init des Servlets, die nur einmal beim Laden des Servlets ausgeführt wird, heißt für eine Seite JSP: jspInit. Diese beiden Methoden haben dieselbe Funktion. Daher wurde hier der Code der Methode init des Servlets vollständig übernommen.
- Die Instanzvariablen des Servlets, die in mehreren Methoden bekannt sein müssen, wurden identisch übernommen. Dabei handelt es sich im Wesentlichen um die Variablen „title“, „valeurs“ und „msgErreur“, die anschließend im Code „JSP“ verwendet werden.
- Die Tags <% ... %> umschließen Java-Code, der in die Methode _jspService eingebunden wird, die bei einer Anfrage eines Clients ausgeführt wird.
- Wie beim Servlet überprüft die Methode _jspService zunächst den Wert der Variablen msgErreur, um festzustellen, ob eine Fehlerseite generiert werden muss. Liegt ein Fehler vor, generiert sie die Fehlerseite und bricht ab (return).
- Liegt kein Fehler vor, generiert sie das Formular mit der Werteliste
- Anschließend prüft sie, ob der Benutzer eine Zahl ausgewählt hat; in diesem Fall zeigt sie diese Zahl auf der generierten Seite an
Was haben wir im Vergleich zum Servlet gewonnen? Zweifellos einen besseren Überblick über den generierten Code HTML. Aber es bleibt immer noch viel Java-Code, der diese Ansicht „überfrachtet“. Wir werden später eine weitere Methode namens Delegation kennenlernen, bei der wir den Großteil des Java-Codes in ein Servlet auslagern können, während die Seite JSP nur noch den Code HTML und JSP enthält. Dadurch wird der Verarbeitungsteil klar vom Darstellungsteil getrennt.
3.3. Bereitstellung einer Webanwendung auf dem Tomcat-Server
Im Folgenden wird erläutert, wie Java-Webanwendungen auf dem Tomcat-Server bereitgestellt werden. Auch wenn die folgenden Ausführungen spezifisch für diesen Server gelten, weist die Bereitstellung einer Java-Webanwendung in einem anderen Container J2EE ähnliche Merkmale auf wie die hier beschriebenen.
3.3.1. Die Konfigurationsdateien server.xml und web.xml
Bisher haben wir zum Testen unserer Servlets und Seiten JSP
- die Servlets im Ordner <tomcat>\webapps\examples\WEB-INF\classes abgelegt. Sie waren dann über die URL URL http://localhost:8080/examples/servlet/nomServlet
- die Seiten JSP im Verzeichnisbaum <tomcat>\webapps\examples\jsp. Sie waren damals über die Seite URL http://localhost:8080/examples/jsp/nomPageJSP erreichbar
Wir haben nie erklärt, warum das so war. Die Konfiguration des Tomcat-Servers erfolgt in einer Textdatei namens server.xml, die sich im Ordner <tomcat>\conf befindet:

Diese Textdatei ist eigentlich eine XML-Datei (eXtended Markup Language). Ein XML-Dokument ist ein Textdokument, das Tags enthält, genau wie ein HTML-Dokument. Während jedoch die Tags der Sprache HTML klar definiert sind, ist dies bei denen der Sprache XML nicht der Fall. Somit ist das folgende Dokument ein XML-Dokument:
Ein XML-Dokument ist einfach ein „ausgezeichnetes“ Dokument, das bestimmten Auszeichnungsregeln folgt:
- Ein Text, der in der Form <xx att1="val1" att2="val2" ....>Text</xx> markiert ist
- Ein Tag kann auch allein stehen und die Form <xx att1="val1" att2="val2" ..../> haben
Die Felder „atti“ werden als Attribute des Tags „xx“ bezeichnet, und die Felder „vali“ sind die diesen Attributen zugeordneten Werte. Manche HTML-Dokumente sind keine gültigen XML-Dokumente. Beispielsweise ist das HTML-Tag <br> kein gültiges XML-Tag. Es müsste wie folgt geschrieben werden: <br/>, um gültig zu sein und die Regel einzuhalten, wonach jedes XML-Tag geschlossen werden muss. Eine Variante von HTML namens XHTML wurde erstellt, um jedes XHTML-Dokument zu einem gültigen XML-Dokument zu machen. Einige der neueren Browser sind in der Lage, XML-Dateien anzuzeigen. Wenn wir also das oben als Beispiel gezeigte Dokument XML als personne.xml bezeichnen und es mit IE6 anzeigen, erhalten wir folgende Darstellung:

IE6 erkennt die Tags und färbt sie ein. Anhand der Tags erkennt es auch die Struktur des Dokuments. Wenn wir also das folgende Dokument als personne2.xml bezeichnen:
und es mit IE6 anzeigen, erhalten wir dieselbe Darstellung:

IE6 hat die Struktur und den Inhalt des Dokuments korrekt erkannt. Der ganze Vorteil des Dokuments XML liegt in dieser Eigenschaft: Es ist einfach, die Struktur und den Inhalt eines Dokuments XML wiederzufinden. Dies geschieht mit einem Programm, das als XML-Parser bezeichnet wird. XML-Dokumente entwickeln sich zunehmend zum Standard beim Dokumentenaustausch im Internet. Nehmen wir an, ein Rechner A soll ein DOC-Dokument an einen Rechner B senden. Das DOC-Dokument wird aus den Informationen einer DB-A-Datenbank erstellt. Rechner B muss das Dokument DOC in einer Datenbank DB-B speichern. Der Austausch kann wie folgt erfolgen:
- Maschine A ruft die Daten aus der Datenbank DB-A ab und kapselt diese in ein Textdokument XML ein
- Das Dokument XML wird über das Netzwerk an Maschine B gesendet
- Rechner B analysiert das empfangene Dokument mit einem Parser XML und extrahiert daraus sowohl die Struktur als auch die Daten (wie es IE6 in unserem Beispiel getan hat). Anschließend kann er die empfangenen Daten in der Datenbank DB-B speichern
Mehr werden wir zur Sprache XML nicht sagen, die ein ganzes Buch für sich verdient.
Hier wird Tomcat also über die Datei XML server.xml konfiguriert. Wenn wir diese mit IE6 anzeigen, erhalten wir ein komplexes Dokument. Wir werden uns lediglich auf die folgenden Zeilen konzentrieren:

Hier interessiert uns das Tag <Context ...>. Es dient zur Definition von Webanwendungen. Zwei seiner Attribute sind besonders hervorzuheben:
- path: Dies ist der Name der Webanwendung
- docBase: Dies ist der Ordner, in dem sie sich befindet. Hier handelt es sich um einen relativen Namen: examples. Relativ zu welchem Ordner? Die Antwort findet sich ebenfalls in der Datei server.xml in der folgenden Zeile:

Die obige Zeile definiert den Webserver:
- name: Name des Webservers
- appBase: Stammverzeichnis der von ihm bereitgestellten Dokumente. Auch hier handelt es sich um einen relativen Namen: webapps. Er bezieht sich auf das Installationsverzeichnis des Tomcat-Servers <tomcat>. Es handelt sich also um den Ordner <tomcat>\webapps.
Die Webanwendung „examples“ hat ihre Dokumente im Ordner examples (siehe docBase weiter oben). Dieser Name bezieht sich auf das Stammverzeichnis der Web-Verzeichnisstruktur des Servers, c.a.d. <tomcat>\webapps. Es handelt sich also um den Ordner <tomcat>\webapps\examples. Schauen wir uns diesen Ordner einmal genauer an:

Dort finden wir den Ordner „WEB-INF\classes“, in dem wir unsere Servlets zum Testen abgelegt haben. Der Ordner „WEB-INF“ enthält eine Datei namens „web.xml“:

Diese Datei dient zur Konfiguration der Webanwendung examples. Wir werden vorerst nicht näher auf diese zu komplexe Datei eingehen. Wir beschränken uns lediglich auf die folgenden Zeilen:
<servlet>
<servlet-name>
servletToJsp
</servlet-name>
<servlet-class>
servletToJsp
</servlet-class>
</servlet>
Das Tag <servlet> dient dazu, ein Servlet innerhalb einer Webanwendung zu definieren. Zur Erinnerung: Die betreffende Webanwendung lautet examples. Das Tag servlet enthält hier zwei weitere Tags:
- <servlet-name>servletToJsp</servlet-name>: definiert den Namen des Servlets
- <servlet-name>servletToJsp</servlet-name>: Definiert den Namen der Klasse, die ausgeführt werden soll, wenn das Servlet angefordert wird. In diesem Beispiel tragen das Servlet und seine Klasse denselben Namen. Dies ist jedoch nicht zwingend erforderlich.
Wie wird das Servlet „servletToJsp“ von einem Browser beim Tomcat-Server angefordert?
- Der Browser fordert das Servlet URL unter http://localhost:8080/examples/servlet/servletToJsp an.
- Tomcat analysiert den Pfad des Servlets /examples/servlet/servletToJsp. Es interpretiert den ersten Teil des Pfads /examples als Namen einer Webanwendung und sucht in deren Konfigurationsdatei server.xml nach dem Speicherort der Dokumente dieser Anwendung. Wie wir zuvor gesehen haben, befindet sich dieser im Ordner <tomcat>\webapps\examples.
- Tomcat verwendet den Rest des Servlet-Pfads, um das Servlet in der Webanwendung examples zu finden. Dieser Pfad /servlet/servletToJsp gibt an, dass das Servlet mit dem Namen servletToJsp ausgeführt werden soll. Tomcat liest daraufhin die Konfigurationsdatei web.xml der Anwendung examples, die sich unter <tomcat>\webapps\examples\WEB-INF befindet. In dieser Datei stellt er fest, dass das Servlet servletToJsp mit der Java-Klasse servletToJsp verknüpft ist (siehe Datei web.xml oben). Anschließend sucht er diese Klasse im Ordner „WEB-INF\classes“ der Webanwendung „examples, c.a.d“. in <tomcat>\webapps\examples\WEB-INF\classes und führt sie aus.

3.3.2. Beispiel: Bereitstellung der Webanwendung „Liste“
Wir greifen auf ein bereits behandeltes Servlet zurück, das dem Benutzer eine Liste von Zahlen anzeigte, aus der er eine auswählen konnte. Das Servlet bestätigte ihm anschließend die von ihm gewählte Zahl:

Wie das Feld Address im obigen Browser zeigt, hieß die Klassendatei des Servlets gener3. Gemäß den zuvor gegebenen Erläuterungen:
- URL und /examples/servlet/gener3 zeigen, dass es sich um ein Servlet namens gener3 der Webanwendung examples handelt
- In der Datei web.xml der Anwendung examples findet man nichts, was auf ein Servlet namens gener3 hindeutet. Wie hat Tomcat es dann gefunden? Nachdem ich die gesamte Datei web.xml durchgesehen habe, kann ich diese Frage nicht mit Sicherheit beantworten... Die Frage bleibt offen...
Wir entscheiden uns, das Servlet gener3.class unter dem Namen lstValeurs in einer Webanwendung namens „liste“ im Ordner E:\data\serge\Servlets\lstValeurs bereitzustellen:

Wir legen die Datei „gener3.class“ im oben genannten Ordner „WEB-INF\classes“ ab:

Wir konfigurieren die Webanwendung „liste“, indem wir in der Datei server.xml die folgenden Zeilen oberhalb der Zeilen hinzufügen, die die Webanwendung manager definieren:
<!-- Benutzer: lstValeurs -->
<Context path="/liste" docBase="e:/data/serge/servlets/lstValeurs" />
<!-- Tomcat-Manager-Kontext -->
<Context path="/manager" docBase="manager" debug="0" privileged="true" />
<!-- Tomcat-Beispiele-Kontext -->
<Context path="/examples" docBase="examples" debug="0" reloadable="true" crossContext="true">
........
Die Zeile, die die Anwendungsliste definiert, gibt an, dass sie sich im Ordner e:/data/serge/servlets/lstValeurs befindet. Nun müssen wir die Datei web.xml dieser Anwendung definieren. Diese Datei definiert das einzige Servlet der Anwendung:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>lstValeurs</servlet-name>
<servlet-class>gener3</servlet-class>
</servlet>
</web-app>
Die obige Datei gibt an, dass das Servlet mit dem Namen lstValeurs der Klassendatei gener3.class zugeordnet ist. Diese Datei „web.xml“ muss erstellt und im Ordner „WEB-INF“ der Anwendung „Liste“ gespeichert werden:

Der obige Screenshot zeigt einen Ordner „src“, in dem die Quelldatei „gener3.java“ abgelegt wurde. Dieser Ordner muss nicht unbedingt vorhanden sein. Für die vorliegende Demonstration spielt er keine Rolle. Wir sind bereit für die Tests:
- Beenden Sie Tomcat und starten Sie es neu, damit es seine Konfigurationsdatei server.xml neu einliest. Wir arbeiten hier unter Windows. Unter Unix kann man Tomcat zwingen, seine Konfigurationsdatei neu einzulesen, ohne es dabei zu beenden.
- Rufen Sie mit einem Browser die Seite URL unter http://localhost:8080/liste/servlet/lstValeurs auf.

Man sieht, dass die vorherige URL das Schlüsselwort servlet enthält, genau wie alle bisher verwendeten URL-Servlets. Darauf kann man verzichten, indem man in der Datei web.xml der Anwendung das Servlet lstValeurs mit einer Vorlage von URL (url-pattern) verknüpft:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>lstValeurs</servlet-name>
<servlet-class>gener3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>lstValeurs</servlet-name>
<url-pattern>/valeurs</url-pattern>
</servlet-mapping>
</web-app>
Im Tag <servlet-mapping> ordnen wir den Pfad /valeurs dem Servlet lstValeurs zu, das in den vorangegangenen Zeilen definiert wurde. Wir speichern die neue Datei web.xml und rufen die Dateien URL und http://localhost:8080/liste/valeurs auf:

3.3.3. Bereitstellung der öffentlichen Seiten einer Webanwendung
Wir haben gerade die Bereitstellung einer Webanwendung gesehen, die aus einem einzigen Servlet besteht. Eine Webanwendung kann zahlreiche Komponenten umfassen: Servlets, JSP-Seiten, HTML-Dateien, Java-Applets usw. Wo werden diese Anwendungselemente abgelegt? Wenn <application> der Ordner der Webanwendung ist, der durch das Attribut docBase der Anwendung in der Tomcat-Konfigurationsdatei server.xml definiert ist, haben wir gesehen, dass die Servlets in <application>\WEB-INF\classes abgelegt wurden. Die übrigen Elemente der Anwendung können an beliebiger Stelle in der Verzeichnisstruktur des Ordners <application> abgelegt werden, außer im Ordner WEB-INF. Betrachten wir die bereits behandelte Anwendung JSP listvaleurs.jsp:

Diese Seite JSP war im Ordner <tomcat>\webapps\examples\jsp\perso\listvaleurs gespeichert worden. Diese Seite könnte ein Bestandteil der zuvor bereitgestellten Anwendung „liste“ sein. Legen wir die Datei listvaleurs.jsp direkt im Ordner dieser Anwendung ab:

Erinnern wir uns an die Konfiguration der Anwendung liste in der Datei server.xml:
Jede Datei URL, deren Pfad mit /liste beginnt, wird als Teil der Anwendung liste betrachtet und im angegebenen Ordner gesucht. Rufen wir die Datei „URL“ unter http://localhost:8080/liste/listvaleurs.jsp mit einem Browser auf:

Wir haben tatsächlich die erwartete Seite JSP erhalten.
3.3.4. Initialisierungsparameter eines Servlets
Wir haben gesehen, dass ein Servlet über die Datei <application>\WEB-INF\web.xml konfiguriert wird, wobei <application> der Ordner der Webanwendung ist, zu der es gehört. Es ist möglich, in dieser Datei Initialisierungsparameter für das Servlet anzugeben. Kehren wir zu unserem Servlet lstValeurs der Webanwendung liste zurück, dessen Konfigurationsdatei wie folgt aussah:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>lstValeurs</servlet-name>
<servlet-class>gener3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>lstValeurs</servlet-name>
<url-pattern>/valeurs</url-pattern>
</servlet-mapping>
</web-app>
Die dem Servlet zugeordnete Klasse ist die Klasse gener3. Im Quellcode dieser Klasse finden sich die Definitionen einiger Konstanten:
public class gener3 extends HttpServlet{
// Der Titel der Seite
private final String title="Génération d'un formulaire";
// Die Datenbank mit den Listenwerten
private final String DSNValeurs="odbc-valeurs";
private final String admDbValeurs="admDbValeurs";
private final String mdpDbValeurs="mdpDbValeurs";
Zur Erinnerung: Die Bedeutung der vier oben definierten Konstanten lautet wie folgt:
Titel des vom Servlet generierten Dokuments HTML | |
Name der Datenbank DSN, aus der das Servlet Daten abruft | |
Name eines Benutzers mit Leserechten für die oben genannte Datenbank | |
sein Passwort |
Wenn der Administrator der Datenbank DSNValeurs das Passwort des Benutzers admDbValeurs ändert, muss der Quellcode des Servlets geändert und neu kompiliert werden. Das ist nicht sehr praktisch. Die Servlet-Konfigurationsdatei web.xml bietet uns eine Alternative, indem sie die Definition von Initialisierungsparametern für das Servlet mit dem Tag <init-param> ermöglicht:
ermöglicht die Festlegung des Parameternamens | |
legt den Wert fest, der dem vorherigen Parameter zugeordnet ist |
Das Servlet kann über die folgenden Methoden auf seine Initialisierungsparameter zugreifen:
Methode der Klasse Servlet, von der die für die Webprogrammierung verwendete Klasse HttpServlet abgeleitet ist. Gibt ein Objekt vom Typ ServletConfig zurück, das Zugriff auf die Konfigurationsparameter des Servlets gewährt. | |
Methode der Klasse ServletConfig, die den Wert des Initialisierungsparameters „paramètre“ zurückgibt |
Wir konfigurieren die Anwendung liste mit der folgenden neuen Datei web.xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>lstValeurs</servlet-name>
<servlet-class>gener3</servlet-class>
</servlet>
<servlet>
<servlet-name>lstValeurs2</servlet-name>
<servlet-class>gener5</servlet-class>
<init-param>
<param-name>title</param-name>
<param-value>Génération d'un formulaire</param-value>
</init-param>
<init-param>
<param-name>DSNValeurs</param-name>
<param-value>odbc-valeurs</param-value>
</init-param>
<init-param>
<param-name>admDbValeurs</param-name>
<param-value>admDbValeurs</param-value>
</init-param>
<init-param>
<param-name>mdpDbValeurs</param-name>
<param-value>mdpDbValeurs</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>lstValeurs</servlet-name>
<url-pattern>/valeurs</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>lstValeurs2</servlet-name>
<url-pattern>/valeurs2</url-pattern>
</servlet-mapping>
</web-app>
In der Anwendung liste definieren wir ein zweites Servlet namens lstValeurs2, das mit der Klassendatei gener5 verknüpft ist. Letztere wurde im Verzeichnis <application>\WEB-INF\classes abgelegt:

Das Servlet lstValeurs2 verfügt über vier Initialisierungsparameter: title, DSNValeurs, admDbValeurs, mdpDbValeurs. Außerdem wurde für das Servlet mithilfe des Tags <servlet-mapping> der Alias /valeurs2 definiert. Somit ist das Servlet lstValeurs2 der Anwendung liste über URL und http://localhost:8080/liste/valeurs2 erreichbar.
Der Quellcode des Servlets wurde wie folgt geändert, um die Initialisierungsparameter des Servlets abzurufen:
public class gener5 extends HttpServlet{
// Seitentitel
private String title=null;
// Datenbank für Listenwerte
private String DSNValeurs=null;
private String admDbValeurs=null;
private String mdpDbValeurs=null;
...............
// Initialisierung des Servlets
public void init(){
// Die Initialisierungsparameter des Servlets werden abgerufen
ServletConfig config=getServletConfig();
title=config.getInitParameter("title");
DSNValeurs=config.getInitParameter("DSNValeurs");
admDbValeurs=config.getInitParameter("admDbValeurs");
mdpDbValeurs=config.getInitParameter("mdpDbValeurs");
//Wurden alle Parameter abgerufen?
if(title==null || DSNValeurs==null || admDbValeurs==null
|| mdpDbValeurs==null){
msgErreur="Configuration incorrecte";
return;
}
// Das Wertearray wird aus einer Datenbank mit dem Namen ODBC gefüllt
// mit dem Namen DSN: DSNvaleurs
...............
Um das Servlet zu testen, muss Tomcat neu gestartet werden, damit die neue Konfigurationsdatei web.xml der Anwendung liste berücksichtigt wird. Mit einem Browser ruft man die Seite URL des Servlets http://localhost:8080/liste/valeurs2 auf:

Fehlt einer der für das Servlet erforderlichen Initialisierungsparameter in der Datei web.xml, wird die folgende Seite angezeigt:

3.3.5. Initialisierungsparameter einer Webanwendung
Im vorangegangenen Beispiel hat nur das Servlet lstValeurs2 Zugriff auf die Parameter title, DSNValeurs, admDbValeurs und mdpDbValeurs. Man könnte sich vorstellen, dass ein anderes Servlet derselben Anwendung, nämlich liste, Daten aus derselben Datenbank benötigt, die auch das Servlet lstValeurs2 verwendet. In diesem Fall müssten die Parameter DSNValeurs, admDbValeurs und mdpDbValeurs im Konfigurationsteil der Datei web.xml des neuen Servlets neu definiert werden. Eine andere Lösung besteht darin, die für mehrere Servlets gemeinsamen Parameter auf Anwendungsebene und nicht mehr auf Servlet-Ebene zu definieren. Die neue Datei web.xml der Anwendung sieht dann wie folgt aus:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<context-param>
<param-name>DSNValeurs</param-name>
<param-value>odbc-valeurs</param-value>
</context-param>
<context-param>
<param-name>admDbValeurs</param-name>
<param-value>admDbValeurs</param-value>
</context-param>
<context-param>
<param-name>mdpDbValeurs</param-name>
<param-value>mdpDbValeurs</param-value>
</context-param>
<servlet>
<servlet-name>lstValeurs</servlet-name>
<servlet-class>gener3</servlet-class>
</servlet>
<servlet>
<servlet-name>lstValeurs3</servlet-name>
<servlet-class>gener6</servlet-class>
<init-param>
<param-name>title</param-name>
<param-value>Génération d'un formulaire</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>lstValeurs</servlet-name>
<url-pattern>/valeurs</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>lstValeurs3</servlet-name>
<url-pattern>/valeurs3</url-pattern>
</servlet-mapping>
</web-app>
Das neue Servlet heißt lstValeurs3, ist mit der Klassendatei gener6 verknüpft und wurde dem Alias /valeurs3 zugeordnet (Servlet-Mapping). Der Parameter title ist der einzige Parameter, der in der Servlet-Definition beibehalten wurde. Die anderen wurden in der Anwendungskonfiguration in Tags mit der Bezeichnung <context-param> platziert. Dieser Tag dient dazu, anwendungsspezifische Informationen zu definieren und nicht solche, die sich auf ein bestimmtes Servlet oder eine bestimmte Seite JSP beziehen. Wie erhält das Java-Servlet Zugriff auf diese Parameter, die oft als Kontextparameter bezeichnet werden? Die verfügbaren Methoden zum Abrufen der Kontextinformationen sind denen sehr ähnlich, die zum Abrufen der servletspezifischen Initialisierungsparameter verwendet werden:
Methode der Klasse Servlet, von der die für die Webprogrammierung verwendete Klasse HttpServlet abgeleitet ist. Gibt ein Objekt ServletContext zurück, das Zugriff auf die Konfigurationsparameter der Anwendung gewährt | |
Methode der Klasse ServletContext, die den Wert des Initialisierungsparameters „paramètre“ zurückgibt |
Die Klasse gener6.java führt lediglich die folgenden Änderungen am zuvor verwendeten Java-Code von gener5.java ein:
// Die Initialisierungsparameter des Servlets werden abgerufen
ServletConfig config=getServletConfig();
title=config.getInitParameter("title");
ServletContext context=getServletContext();
DSNValeurs=context.getInitParameter("DSNValeurs");
admDbValeurs=context.getInitParameter("admDbValeurs");
mdpDbValeurs=context.getInitParameter("mdpDbValeurs");
//Wurden alle Parameter abgerufen?
if(title==null || DSNValeurs==null || admDbValeurs==null
|| mdpDbValeurs==null){
msgErreur="Configuration incorrecte";
return;
}
// Das Array wird anhand einer Datenbank mit Werten gefüllt ODBC
// mit dem Namen DSN: DSNvaleurs
...............
Der servlet-spezifische Parameter title wird über ein Objekt ServletConfig abgerufen. Die drei anderen auf Anwendungsebene definierten Parameter werden über ein Objekt ServletContext abgerufen. Wir kompilieren diese Klasse und legen sie wie die anderen in <application>\WEB-INF\classes ab:

Wir starten Tomcat neu, damit die neue Datei web.xml der Anwendung berücksichtigt wird, und rufen die Dateien URL und http://localhost:8080/liste/valeurs3 auf:

3.3.6. Initialisierungsparameter einer Seite JSP
Wir haben gesehen, wie man Initialisierungsparameter für ein Servlet oder eine Webanwendung definiert. Lässt sich das auch für eine Seite JSP tun? Kehren wir zum Anfang des Codes der bereits behandelten Seite listvaleurs.jsp zurück:
<%@ page import="java.sql.*, java.util.*" %>
<%!
// globale Variablen der Anwendung
// der Seitentitel
private final String title="Génération d'un formulaire";
// Datenbank mit den Listenwerten
private final String DSNValeurs="odbc-valeurs";
private final String admDbValeurs="admDbValeurs";
private final String mdpDbValeurs="mdpDbValeurs";
.........
Die vier Konstanten title, DSNValeurs, admDbValeurs und mdpDbValeurs sind in der Datei web.xml der Anwendung definiert. Die Konstanten DSNValeurs, admDbValeurs und mdpDbValeurs wurden nun auf Anwendungsebene definiert, sodass davon ausgegangen werden kann, dass eine Seite JSP, die Teil dieser Anwendung ist, darauf zugreifen kann. Dies ist der Fall. Wir wissen, dass die Seite JSP in ein Servlet übersetzt wird. Dieses hat über die Methode getServletContext() Zugriff auf den Kontext. Komplizierter ist der Fall der Konstante title. Wir haben sie nämlich auf Servlet-Ebene und nicht auf Anwendungsebene wie folgt definiert:
<servlet>
<servlet-name>lstValeurs3</servlet-name>
<servlet-class>gener6</servlet-class>
<init-param>
<param-name>title</param-name>
<param-value>Génération d'un formulaire</param-value>
</init-param>
</servlet>
Für die Seite JSP ist die vorherige Syntax nicht mehr geeignet, da es den Begriff der Klassendatei nicht mehr gibt. Die Konfigurationssyntax einer Seite JSP ähnelt jedoch stark der eines Servlets. Sie lautet wie folgt:
<servlet>
<servlet-name>JSPlstValeurs</servlet-name>
<jsp-file>/listvaleurs2.jsp</jsp-file>
...
</servlet>
Tatsächlich wird eine Seite mit dem Namen JSP einem Servlet zugeordnet, dem ein Name (servlet-name) zugewiesen wird. Anstatt diesem Servlet eine Klassendatei zuzuordnen, wird die auszuführende Quelldatei der Seite JSP (jsp-file) zugeordnet. Somit definieren die vorangegangenen Zeilen ein Servlet namens JSPlstvaleurs, das der Seite JSP /listvaleurs2.jsp zugeordnet ist. Der Pfad /listvaleurs2.jsp wird relativ zum Stammverzeichnis der Anwendung gemessen. Im Fall unserer Anwendung liste befände sich die Datei listvaleurs2.jsp im Ordner docBase (siehe server.xml) der Anwendung liste:

Die Konfiguration der Seite JSP sieht in der Datei web.xml der Anwendung wie folgt aus:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<context-param>
<param-name>DSNValeurs</param-name>
<param-value>odbc-valeurs</param-value>
</context-param>
<context-param>
<param-name>admDbValeurs</param-name>
<param-value>admDbValeurs</param-value>
</context-param>
<context-param>
<param-name>mdpDbValeurs</param-name>
<param-value>mdpDbValeurs</param-value>
</context-param>
.......
<servlet>
<servlet-name>JSPlstValeurs</servlet-name>
<jsp-file>/listvaleurs2.jsp</jsp-file>
<init-param>
<param-name>JSPtitle</param-name>
<param-value>Génération d'un formulaire</param-value>
</init-param>
</servlet>
..........
<servlet-mapping>
<servlet-name>JSPlstValeurs</servlet-name>
<url-pattern>/jspvaleurs</url-pattern>
</servlet-mapping>
<servlet-mapping>
........
</web-app>
Die Seite JSP listvaleurs2.jsp befindet sich im Stammverzeichnis der Anwendung liste und ist dem Servlet-Namen JSPlstValeurs (Servlet-Name) zugeordnet, der wiederum dem Alias /jspvaleurs (Servlet-Mapping) zugeordnet ist. Somit ist unsere Seite JSP über URL und http://localhost:8080/liste/jspvaleurs erreichbar.
Die ursprüngliche Seite JSP (listvaleurs.jsp) wird in listvaleurs2.jsp geändert und ruft ihre vier Initialisierungsparameter in der Methode jspInit() ab:
<%!
// globale Anwendungsvariablen
// Seitentitel
private String title=null;
// die Datenbank mit den Listenwerten
private String DSNValeurs=null;
private String admDbValeurs=null;
private String mdpDbValeurs=null;
// Listenwerte
private String[] valeurs=null;
// Fehlermeldung
private String msgErreur=null;
// Initialisierung der Seite JSP – wird nur einmal ausgeführt
public void jspInit(){
// Die Initialisierungsparameter des Servlets werden abgerufen
ServletConfig config=getServletConfig();
title=config.getInitParameter("JSPtitle");
ServletContext context=getServletContext();
DSNValeurs=context.getInitParameter("DSNValeurs");
admDbValeurs=context.getInitParameter("admDbValeurs");
mdpDbValeurs=context.getInitParameter("mdpDbValeurs");
//– Wurden alle Parameter abgerufen?
if(title==null || DSNValeurs==null || admDbValeurs==null
|| mdpDbValeurs==null){
msgErreur="Configuration incorrecte";
return;
}
// Das Array wird anhand einer Datenbank mit dem Namen ODBC gefüllt
// mit dem Namen DSN: DSNvaleurs
..............
Die Seite JSP ruft ihre Initialisierungsparameter auf dieselbe Weise ab wie die Servlets. Die vorstehende Datei wird im Stammverzeichnis der Webanwendung liste gespeichert:

Der Tomcat-Server wird neu gestartet, damit er die neue Konfigurationsdatei web.xml der Anwendung erneut einliest. Anschließend kann die Seite URL http://localhost:8080/liste/jspvaleurs aufgerufen werden:

3.3.7. Zusammenarbeit von Servlets und Seiten JSP innerhalb einer Webanwendung
Wenn ein Client eine Anfrage an einen Webserver sendet, kann die Antwort von mehreren Servlets und Seiten (JSP) zusammengestellt werden. Bislang wurde die Antwort von einem einzigen Servlet oder einer einzigen Seite (JSP) zusammengestellt. Wir haben gesehen, dass die Seite JSP eine bessere Lesbarkeit der Struktur des generierten Dokuments HTML ermöglicht. Allerdings enthält sie in der Regel auch viel Java-Code. Man kann dies verbessern, indem man
- den Java-Code, der nicht den HTML-Code der Antwort generiert, in ein oder mehrere Servlets
- in Seiten JSP den Code zur Generierung der verschiedenen Dokumente HTML, die als Antwort an den Client gesendet werden
Auf diese Weise lässt sich hoffentlich die Trennung zwischen Java-Code und HTML-Code verbessern. Wir werden diese neue Strukturierung auf unsere Anwendung liste anwenden: Ein Java-Servlet lstValeurs4 wird beim Start die Werte aus der Datenbank lesen und anschließend die Anfragen der Kunden analysieren. Je nach Ergebnis dieser Analyse wird die Anfrage des Kunden entweder an eine Fehlerseite erreur.jsp oder an die Seite zur Anzeige der Zahlenliste liste.jsp weitergeleitet. Die Anwendung liste besteht somit aus einem Servlet und zwei Seiten JSP.
Wie kann ein Servlet die von einem Client empfangene Anfrage an ein anderes Servlet oder an eine Seite JSP weiterleiten? Wir verwenden dazu die folgenden Methoden:
Methode der Klasse ServletContext, die ein Objekt vom Typ RequestDispatcher zurückgibt. Der Parameter url ist der Name des URL, an das die Anfrage des Clients weitergeleitet werden soll. Diese Weiterleitung der Anfrage kann nur innerhalb derselben Anwendung erfolgen. Daher ist der Parameter url ein relativer Pfad zur Webstruktur dieser Anwendung. | |
Methode der Schnittstelle RequestDispatcher, die die Anfrage request des Clients sowie das Objekt response, das zur Erstellung der Antwort verwendet werden soll, an die vorhergehende Methode URL übergibt. | |
Wenn ein Servlet oder eine Seite JSP eine Anfrage an ein anderes Servlet oder eine andere Seite JSP weiterleitet, muss es diesem in der Regel neben der reinen Kundenanfrage weitere Informationen übermitteln, die aus der eigenen Bearbeitung der Anfrage stammen. Die Methode setAttribute der Klasse ServletRequest ermöglicht es, dem request-Objekt des Clients Attribute in einer Form hinzuzufügen, die einem Wörterbuch aus Paaren (Attribut, Wert), wobei attribut der Name des Attributs und valeur ein beliebiges Objekt ist, das dessen Wert darstellt. | |
ermöglicht das Abrufen der Attributwerte einer Anfrage. Diese Methode wird von dem Servlet oder der Seite JSP verwendet, an das bzw. die eine Anfrage weitergeleitet wurde, um die darin enthaltenen Informationen abzurufen. |
Das für die Verarbeitung des Formulars zuständige Servlet wird in der Datei web.xml wie folgt konfiguriert:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<context-param>
<param-name>DSNValeurs</param-name>
<param-value>odbc-valeurs</param-value>
</context-param>
<context-param>
<param-name>admDbValeurs</param-name>
<param-value>admDbValeurs</param-value>
</context-param>
<context-param>
<param-name>mdpDbValeurs</param-name>
<param-value>mdpDbValeurs</param-value>
</context-param>
............
<servlet>
<servlet-name>lstValeurs4</servlet-name>
<servlet-class>gener7</servlet-class>
<init-param>
<param-name>title</param-name>
<param-value>Génération d'un formulaire</param-value>
</init-param>
<init-param>
<param-name>JSPerreur</param-name>
<param-value>/erreur.jsp</param-value>
</init-param>
<init-param>
<param-name>JSPliste</param-name>
<param-value>/liste.jsp</param-value>
</init-param>
<init-param>
<param-name>URLservlet</param-name>
<param-value>/liste/valeurs4</param-value>
</init-param>
</servlet>
...........
<servlet-mapping>
<servlet-name>lstValeurs4</servlet-name>
<url-pattern>/valeurs4</url-pattern>
</servlet-mapping>
.......
</web-app>
Das Servlet lstValeurs4 verfügt über vier eigene Initialisierungsparameter:
den Titel des zu generierenden Dokuments HTML | |
die Fehler-ID URL der Fehlerseite JSP | |
URL der Seite JSP mit der Zahlenliste | |
die Seite URL, die dem Attribut „action“ des Formulars zugeordnet ist, das auf der Seite JSPliste dargestellt wird. Diese Seite URL entspricht dem Servlet lstValeurs4 |
Das Servlet erhält den Alias /valeurs4 (Servlet-Mapping) und ist somit über URL und http://localhost:8080/liste/valeurs4 erreichbar. Es ist mit der Klassendatei gener7.java verknüpft, deren vollständiger Quellcode wie folgt lautet:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
import java.util.*;
public class gener7 extends HttpServlet{
// den Seitentitel
private String title=null;
// die Datenbank mit den Listenwerten
private String DSNValeurs=null;
private String admDbValeurs=null;
private String mdpDbValeurs=null;
// die Anzeigeseiten JSP
private String JSPerreur=null;
private String JSPliste=null;
// das URL des Servlets
private String URLservlet=null;
// Listenwerte
private String[] valeurs=null;
// Fehlermeldung
private String msgErreur=null;
// -----------------------------------------------------------------
// GET
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// „msgErreur,title“ wird in die Anfrageattribute gesetzt
request.setAttribute("msgErreur",msgErreur);
request.setAttribute("title",title);
request.setAttribute("URLservlet",URLservlet);
// Ist beim Laden des Servlets ein Fehler aufgetreten?
if(msgErreur!=null){
// Es wird auf eine Fehlerseite JSP weitergeleitet
getServletContext().getRequestDispatcher(JSPerreur).forward(request,response);
// Ende
return;
}
// Es ist kein Fehler aufgetreten
// Die Liste der Werte wird in die Anfrageattribute gesetzt
request.setAttribute("valeurs",valeurs);
// Die eventuelle Auswahl des Benutzers wird abgerufen
String choix=request.getParameter("cmbValeurs");
if(choix==null) choix="";
request.setAttribute("choix",choix);
// die Seite JSP zur Darstellung der Liste wird aufgerufen
getServletContext().getRequestDispatcher(JSPliste).forward(request,response);
// Ende
return;
}//GET
// -----------------------------------------------------------------
// POST
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// verweist auf GET
doGet(request,response);
}//POST
// -----------------------------------------------------------------
// Initialisierung des Servlets
public void init(){
// Abruf der Initialisierungsparameter des Servlets
ServletConfig config=getServletConfig();
title=config.getInitParameter("title");
JSPerreur=config.getInitParameter("JSPerreur");
JSPliste=config.getInitParameter("JSPliste");
URLservlet=config.getInitParameter("URLservlet");
ServletContext context=getServletContext();
DSNValeurs=context.getInitParameter("DSNValeurs");
admDbValeurs=context.getInitParameter("admDbValeurs");
mdpDbValeurs=context.getInitParameter("mdpDbValeurs");
//Wurden alle Parameter abgerufen?
if(title==null || DSNValeurs==null || admDbValeurs==null
|| mdpDbValeurs==null || JSPerreur==null || JSPliste==null || URLservlet==null){
msgErreur="Configuration incorrecte";
return;
}
// Das Array wird anhand einer Datenbank mit Werten gefüllt ODBC
// mit dem Namen DSN: DSNvaleurs
Connection connexion=null;
Statement st=null;
ResultSet rs=null;
try{
// Verbindung zur Datenbank ODBC
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
connexion=DriverManager.getConnection("jdbc:odbc:"+DSNValeurs,admDbValeurs,mdpDbValeurs);
// Statement-Objekt
st=connexion.createStatement();
// Ausführung einer SELECT-Abfrage zum Abrufen der Werte
rs=st.executeQuery("select valeur from Tvaleurs");
// Die Werte werden abgerufen und in ein dynamisches Array gespeichert
ArrayList lstValeurs=new ArrayList();
while(rs.next()){
// Der Wert wird in die Liste geschrieben
lstValeurs.add(rs.getString("valeur"));
}//while
// Umwandlung von Liste in Array
valeurs=new String[lstValeurs.size()];
for (int i=0;i<lstValeurs.size();i++){
valeurs[i]=(String)lstValeurs.get(i);
}
}catch(Exception ex){
// Problem
msgErreur=ex.getMessage();
}finally{
try{rs.close();}catch(Exception ex){}
try{st.close();}catch(Exception ex){}
try{connexion.close();}catch(Exception ex){}
}//try
}//initialisieren
}//Klasse
Neu in dieser Klasse ist, dass die Anfrage des Clients im Fehlerfall an die Seite JSPerreur und andernfalls an die Seite JSPliste weitergeleitet wird. Die Klasse erstellt die Antwort nicht selbst. Dies übernehmen die Seiten JSP, JSPerreur und JSPliste. Zuvor fügte das Servlet der Client-Anfrage Attribute (setAttribute) hinzu:
- eine Fehlermeldung msgErreur im Falle eines Fehlers auf der Seite JSPerreur
- die anzuzeigenden Werte (valeurs)), der vom Benutzer ausgewählte Wert (choix), der Titel (title) des Formulars, der URL (URLservlet) des Attributs „action“ des Formulars für die Seite JSPliste
Diese Klasse wird kompiliert und in die Klassen der Anwendung aufgenommen:

Die Seite JSP, die eine Fehlermeldung anzeigt, ist wie folgt konfiguriert:
<servlet>
<servlet-name>JSPerreur</servlet-name>
<jsp-file>/erreur.jsp</jsp-file>
<init-param>
<param-name>mainServlet</param-name>
<param-value>/valeurs4</param-value>
</init-param>
</servlet>
.........
<servlet-mapping>
<servlet-name>JSPerreur</servlet-name>
<url-pattern>/JSPerreur</url-pattern>
</servlet-mapping>
Die zur Fehlerseite gehörende Datei JSP heißt erreur.jsp und befindet sich im Stammverzeichnis der Anwendung:

Sie hat den Alias /JSPerreur, wodurch sie über die URL http://localhost:8080/liste/JSPerreur zugänglich ist. Sie verfügt über einen Initialisierungsparameter namens mainServlet, dessen Wert der Alias des zuvor beschriebenen Haupt-Servlets ist. Es ist zu beachten, dass dieser Alias relativ zum Stammverzeichnis der Anwendung liste, ist; andernfalls wäre es /liste/valeurs4.. Der Code der Seite erreur.jsp lautet wie folgt:
<%
// Code von _jspService
// wird der Initialisierungsparameter mainServlet abgerufen
String servletListValeurs=config.getInitParameter("mainServlet");
// das Attribut wird abgerufen: msgErreur
String msgErreur=(String)request.getAttribute("msgErreur");
// Ist das Attribut gültig?
if(msgErreur!=null){
%>
<!-- Code HTML -->
<html>
<head>
<title>Erreur</title>
</head>
<body>
<h3>Application indisponible (<%= msgErreur %>)</h3>
</body>
</html>
<%
} else { // Ungültiges Attribut msgErreur – Rückkehr zum Haupt-Servlet
%>
<jsp:forward page="<%= servletListValeurs %>" />
<%
}
%>
Diese Seite sollte normalerweise vom vorherigen Servlet aufgerufen werden, das ihr das Attribut msgErreur übergeben muss. Es spricht jedoch nichts dagegen, sie direkt aufzurufen, wenn man ihr URL kennt. Wenn festgestellt wird, dass das Attribut msgErreur fehlt, wird die Anfrage an das Haupt-Servlet weitergeleitet. Hier wird ein für JSP-Seiten spezifisches Tag verwendet, dessen Syntax wie folgt lautet:
wobei URL das URL des Servlets ist, an das die Anfrage des Clients weitergeleitet wird. Ist das Attribut msgErreur vorhanden, wird die Fehlerseite angezeigt.
Die Seite JSP, auf der die Liste der Zahlen angezeigt wird, ist wie folgt konfiguriert:
<servlet>
<servlet-name>JSPliste</servlet-name>
<jsp-file>/liste.jsp</jsp-file>
<init-param>
<param-name>mainServlet</param-name>
<param-value>/valeurs4</param-value>
</init-param>
.........
<servlet-mapping>
<servlet-name>JSPliste</servlet-name>
<url-pattern>/JSPliste</url-pattern>
</servlet-mapping>
Die zur Fehlerseite gehörende Datei JSP heißt liste.jsp und befindet sich im Stammverzeichnis der Anwendung:

Das Servlet hat den Alias /JSPliste, wodurch es über die Adresse http://localhost:8080/liste/JSPliste erreichbar ist. Es verfügt über einen Initialisierungsparameter namens mainServlet, dessen Wert der Alias des Haupt-Servlets ist. Der Code der Seite liste.jsp lautet wie folgt:
<%-- Seite zur Anzeige der Werteliste --%>
<%
// Code von jspService
// Der Initialisierungsparameter wird abgerufen
String servletListValeurs=config.getInitParameter("mainServlet");
// Abruf der Attribute der Anfrage vom Haupt-Servlet
String title=(String) request.getAttribute("title");
String[] valeurs=(String[]) request.getAttribute("valeurs");
String choix=(String) request.getAttribute("choix");
String URLservlet=(String) request.getAttribute("URLservlet");
// Gültige Attribute?
if(title==null || valeurs==null || choix==null){
// Es gibt ein ungültiges Attribut – wir übergeben die Kontrolle an das Servlet
%>
<jsp:forward page="<%= servletListValeurs %>" />
<%
}//if
%>
<%-- Code HTML --%>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h3>Choisissez une valeur</h3>
<form method="POST" action="<%= URLservlet %>">
<select name="cmbValeurs">
<%
// dynamische Anzeige der Werte
String selected="";
for (int i=0;i<valeurs.length;i++){
if(valeurs[i].equals(choix)) selected="selected"; else selected="";
out.println("<option "+selected+">"+valeurs[i]+"</option>");
}//for
%>
</select>
<input type="submit" value="Envoyer">
</form>
<%
// Wurde ein Wert ausgewählt?
if(! choix.equals("")){
// Die Auswahl des Benutzers wird angezeigt
%>
<hr>Vous avez choisi le nombre<h2><%= choix %></h2>
<%
}//if
%>
</body>
</html>
Diese Seite verhält sich wie die Seite erreur.jsp. Sie muss normalerweise vom Servlet /liste/valeurs4 aufgerufen werden und die Attribute title, valeurs und choix erhalten. Fehlt einer dieser Parameter, wird an das Servlet URLservlet (/liste/valeurs4) weitergeleitet. Sind alle Parameter vorhanden, wird die Liste der Zahlen angezeigt sowie die vom Benutzer ausgewählte Zahl, falls er eine ausgewählt hat.
Ruft man das Servlet URL des Hauptservlets auf, erhält man folgendes Ergebnis:

mit folgendem Quellcode (View/Source):
<html>
<head>
<title>Génération d'un formulaire</title>
</head>
<body>
<h3>Choisissez une valeur</h3>
<form method="POST" action="/liste/valeurs4">
<select name="cmbValeurs">
<option >0</option>
<option >1</option>
<option >2</option>
<option >3</option>
<option >4</option>
<option >6</option>
<option >5</option>
<option >7</option>
<option >8</option>
<option >9</option>
</select>
<input type="submit" value="Envoyer">
</form>
</body>
</html>
Dieses Dokument HTMl wurde von der Seite JSP liste.jsp generiert. Es ist ersichtlich, dass die Attribute title, valeurs und URLservlet korrekt übernommen wurden.
Abschließend lässt sich zur Zusammenarbeit zwischen Servlets und Seiten JSP feststellen, dass die Seiten JSP hier sehr kurz sind und keinen Java-Code enthalten, der nicht direkt zur Erstellung der Antwort HTML beiträgt. Dadurch wird die Struktur der generierten Dokumente besser sichtbar.
3.4. Lebenszyklus der Servlets und Seiten JSP
3.4.1. Der Lebenszyklus
Wir befassen uns hier mit dem Lebenszyklus von Servlets. Der Lebenszyklus der Seiten JSP leitet sich daraus ab. Betrachten wir ein Servlet, das zum ersten Mal aufgerufen wird. Der Webserver erstellt dann eine Instanz der Klasse und lädt sie in den Arbeitsspeicher. Diese wird anschließend zur Bearbeitung der Anfrage verwendet. Danach wird das Servlet nicht aus dem Arbeitsspeicher entladen. Es verbleibt dort, um weitere Anfragen zu bedienen und so die Antwortzeiten des Servers zu optimieren. Es wird erst entladen, wenn eine ausreichend lange Zeit verstrichen ist, ohne dass es neue Anfragen bearbeitet hat. Diese Zeitspanne ist in der Regel im Webserver konfigurierbar.
Solange es sich im Speicher befindet, kann das Servlet mehrere Anfragen gleichzeitig bearbeiten. Der Webserver erstellt pro Anfrage einen Thread, die alle dieselbe Servlet-Instanz nutzen:
![]() |
Alle oben genannten Threads teilen sich die Variablen der Servlet-Instanz. Es kann erforderlich sein, die Threads zu synchronisieren, um eine Beschädigung der Servlet-Daten zu vermeiden. Wir werden darauf zurückkommen.
Beim Laden eines Servlets wird eine bestimmte Methode des Servlets ausgeführt:
Für eine Seite mit dem Namen JSP ist dies die Methode
public void jspInit(){
}
ausgeführt. Hier ist ein Beispiel für eine Seite JSP, die die Methode jspInit verwendet:
<html>
<head>
<title>Compteur synchronisé</title>
</head>
<body>
Compteur= <%= getCompteur() %>
</body>
</html>
<%!
// globale Variablen und Methoden der Seite JSP
// Instanzvariable
int compteur;
// Methode zum Inkrementieren des Zählers
public int getCompteur(){
// Der Zähler wird erhöht
int myCompteur=compteur;
myCompteur++;
compteur=myCompteur;
// wird zurückgesetzt
return compteur;
}
// die beim ersten Laden der Seite ausgeführte Methode
public void jspInit(){
// Zähler initialisieren
compteur=100;
}
%>
Die vorherige Seite JSP setzt einen Zähler in jspInit auf 100. Jede nachfolgende Anfrage an das Servlet erhöht diesen Zähler um eins und zeigt anschließend den Wert an:
Beim ersten Mal:

Beim zweiten Mal:

Wie oben deutlich zu sehen ist, wurde das Servlet zwischen den beiden Anfragen nicht entladen, da sonst der Zähler bei der zweiten Anfrage den Wert 101 gehabt hätte. Wenn das Servlet entladen wird, wird die Methode
ausgeführt, sofern sie vorhanden ist. Für die Seiten JSP ist es die Methode
public void jspDestroy(){
}
In diesen Methoden können beispielsweise Datenbankverbindungen geschlossen werden, die in den entsprechenden Methoden init geöffnet wurden.
3.4.2. Synchronisation der Anfragen mit einem Servlet
Kehren wir zur vorherigen Seite JSP zurück, die einen Zähler inkrementiert und diesen an den Web-Client zurückgibt. Nehmen wir an, es liegen zwei gleichzeitige Anfragen vor. Dann werden zwei Threads erstellt, um diese auszuführen; diese Threads nutzen dieselbe Servlet-Instanz und somit hier denselben Zähler. Hier noch einmal der Code, der den Zähler inkrementiert:
public int getCompteur(){
// Der Zähler wird erhöht
int myCompteur=compteur;
myCompteur++;
compteur=myCompteur;
// wird zurückgegeben
return compteur;
}
Die Inkrementierung des Zählers wurde absichtlich ungeschickt geschrieben. Nehmen wir an, die Ausführung der beiden Threads verläuft wie folgt:
![]() |
- Zum Zeitpunkt T1 wird der Thread TH1 ausgeführt. Er liest den Zähler (=145) in myCompteur aus, wird dann unterbrochen und verliert die Prozessorsteuerung. Er hatte also keine Zeit, myCompteur zu inkrementieren und den neuen Wert in compteur zu kopieren.
- Zu diesem Zeitpunkt wird der Thread T2 ausgeführt. Er liest den Zähler (=145) aus myCompteur aus, wird dann unterbrochen und verliert die Prozessorsteuerung. Es ist zu beachten, dass die beiden Threads unterschiedliche Variablen myCompteur haben. Sie teilen sich lediglich die Instanzvariablen, also diejenigen, die für alle Methoden global sind.
- Zum Zeitpunkt T3 übernimmt der Thread TH1 wieder die Kontrolle und wird beendet. Er gibt daher 146 an seinen Client zurück.
- Zum Zeitpunkt T4 übernimmt der Thread TH2 wieder die Kontrolle und beendet seine Ausführung. Auch er gibt 146 an seinen Client zurück, obwohl er eigentlich 147 hätte zurückgeben müssen.
Hier liegt ein Problem bei der Thread-Synchronisation vor. Wenn TH1 den Zähler erhöhen will, müsste verhindert werden, dass ein anderer Thread dies ebenfalls tut. Um dieses Problem zu verdeutlichen, schreiben wir die Seite JSP wie folgt um:
<html>
<head>
<title>Compteur synchronisé</title>
</head>
<body>
Compteur= <%= getCompteur() %>
</body>
</html>
<%!
// globale Variablen und Methoden der Seite JSP
// Instanzvariable
int compteur;
// Methode zum Inkrementieren des Zählers
public int getCompteur(){
// Der Zähler wird ausgelesen
int myCompteur=compteur;
// 10 Sekunden Pause
try{
Thread.sleep(10000);
}catch (Exception ignored){}
// Zähler wird erhöht
compteur=myCompteur+1;
// den Wert zurückgeben
return compteur;
}
// die Methode, die beim ersten Laden der Seite ausgeführt wird
public void jspInit(){
// Zähler initialisieren
compteur=100;
}
%>
Hier haben wir den Thread dazu gezwungen, 10 Sekunden nach dem Auslesen des Zählers anzuhalten. Er sollte daher die Prozessorauslastung freigeben, sodass ein anderer Thread seinerseits einen Zähler auslesen kann, der nicht inkrementiert wurde. Wenn wir Anfragen mit einem Browser stellen, sehen wir keinen Unterschied, abgesehen von der Wartezeit von 10 Sekunden, bis wir das Ergebnis erhalten.

Wenn wir nun zwei Browserfenster öffnen und zwei Anfragen in ausreichend kurzem zeitlichen Abstand stellen:


erhalten wir denselben Zählerwert. Wir können das Problem besser verdeutlichen, wenn wir statt eines manuellen Clients wie dem Browser einen programmierten Client verwenden. Es folgt ein Perl-Client, der wie folgt aufgerufen wird:
Programm URL N
wobei
URL die ID des Zähl-Servlets ist
N die Anzahl der an dieses Servlet zu sendenden Anfragen
Hier sind die Ergebnisse für 5 Anfragen, die das Problem der schlechten Synchronisation der Threads deutlich machen: Sie erhalten alle denselben Zählerstand.
DOS>java clientCompteurJSP http://localhost:8080/examples/jsp/perso/compteur/compteur2.jsp 5
Compteur=121
Compteur=121
Compteur=121
Compteur=121
Compteur=121
Der Java-Client-Code lautet wie folgt.
import java.net.*;
import java.util.regex.*;
import java.io.*;
public class clientCompteurJSP {
public static void main(String[] params){
// Daten
String syntaxe="Syntaxe : pg URL nbAppels";
// Parameterprüfung
if(params.length!=2){
System.err.println(syntaxe);
System.exit(1);
}//if
// URL
URL urlCompteur=null;
try{
urlCompteur=new URL(params[0]);
String query=urlCompteur.getQuery();
if(query!=null) throw new Exception();
}catch (Exception ex){
System.err.println(syntaxe);
System.err.println("URL ["+params[0]+" incorrecte");
System.exit(2);
}//try-catch
// Anzahl der Aufrufe
int nbAppels=0;
try{
nbAppels=Integer.parseInt(params[1]);
if(nbAppels<=0) throw new Exception();
}catch(Exception ex){
System.err.println(syntaxe);
System.err.println("Nombre d'appels ["+params[1]+" incorrect");
System.exit(3);
}//try-catch
// Die Parameter sind korrekt – die Verbindungen zu URL können hergestellt werden
try{
getCompteurs(urlCompteur,nbAppels);
}catch(Exception ex){
System.err.println(syntaxe);
System.err.println("L'erreur suivante s'est produite : "+ex.getMessage());
System.exit(4);
}//try-catch
}//main
private static void getCompteurs (URL urlCompteur, int nbAppels)
throws Exception {
// führt nbAppels zum URL urlCompteur aus
// zeigt jedes Mal den vom Webserver zurückgegebenen Zählerwert an
// aus urlCompteur werden die für die Verbindung zum Steuer-Server erforderlichen Informationen entnommen
String path=urlCompteur.getPath();
if(path.equals("")) path="/";
String host=urlCompteur.getHost();
int port=urlCompteur.getPort();
if(port==-1) port=urlCompteur.getDefaultPort();
// Es werden die Aufrufe an URL durchgeführt
Socket[] clients=new Socket[nbAppels];
for(int i=0;i<nbAppels;i++){
// Es wird eine Verbindung zum Server hergestellt
clients[i]=new Socket(host,port);
// Es wird ein Schreib-Stream zum Server erstellt
PrintWriter OUT=new PrintWriter(clients[i].getOutputStream(),true);
// Anforderung des URL – Senden der Kopfdaten HTTP
OUT.println("GET " + path + " HTTP/1.1");
OUT.println("Host: " + host + ":" + port);
OUT.println("Connection: close");
OUT.println("");
}//für
// lokale Daten
String réponse=null; // Antwort des Servers
// das gesuchte Muster in der Antwort HTML des Servers
Pattern modèleCompteur=Pattern.compile("^\\s*Compteur= (\\d+)");
// das Muster einer korrekten Antwort
Pattern réponseOK=Pattern.compile("^.*? 200 OK");
// das Ergebnis des Vergleichs mit dem Muster
Matcher résultat=null;
for(int i=0;i<nbAppels;i++){
// Jeder Client liest die Antwort, die ihm der Server sendet
// Es werden die Ein- und Ausgabeströme des Clients erstellt: TCP
BufferedReader IN=new BufferedReader(new InputStreamReader(clients[i].getInputStream()));
// Die erste Zeile der Antwort wird gelesen
réponse=IN.readLine();
// Die Zeile HTTP wird mit dem Muster der korrekten Antwort verglichen
résultat=réponseOK.matcher(réponse);
if(! résultat.find()){
// Es liegt ein Problem mit URL vor
throw new Exception("Client n° " + i + " - Le serveur a répondu : URL ["+ urlCompteur + "] inconnue");
}//if
// wird die Antwort bis zum Ende der Kopfzeilen gelesen
while((réponse=IN.readLine())!=null && ! réponse.equals("")){
}//während
// die Header sind fertig HTTP – wir gehen zum Code über HTML
// um den Zählerstand abzurufen
boolean compteurTrouvé=false;
while((réponse=IN.readLine())!=null){
// die Zeile wird mit dem Zählermuster verglichen
if(! compteurTrouvé){
résultat=modèleCompteur.matcher(réponse);
if(résultat.find()){
// Zähler gefunden
System.out.println("Compteur="+résultat.group(1));
compteurTrouvé=true;
}//if
}//if
}//while
// Fertig
clients[i].close();
}//for
}//getCompteurs
}//Klasse
Erläutern wir den obigen Code:
- Das Programm akzeptiert zwei Parameter:
- die URL der Seite JSP des Zählers
- die Anzahl der Kunden, die für diese URL angelegt werden sollen
- Das Programm überprüft daher zunächst die Gültigkeit der Parameter: ob tatsächlich zwei vorhanden sind, ob der erste syntaktisch einem URL entspricht und ob der zweite eine ganze Zahl > 0 ist. Um zu überprüfen, ob der URL syntaktisch korrekt ist, verwenden wir die Klasse URL und ihren Konstruktor URL (String), der ein Objekt URL aus einer Zeichenkette wie http://istia.univ-angers.fr erstellt. Es wird eine Ausnahme ausgelöst, wenn die Zeichenkette kein syntaktisch gültiges URL ist. Auf diese Weise können wir die Gültigkeit des ersten Parameters überprüfen.
- Sobald die Parameter überprüft wurden, wird die Kontrolle an die Prozedur getCompteurs übergeben. Diese erstellt nbAppels-Clients, die sich alle gleichzeitig (oder fast gleichzeitig) mit dem URL urlCompteur verbinden.
- Der Port und der Rechner, mit dem sich die Clients verbinden sollen, werden aus den Prozeduren URL und urlCompteur entnommen: [URL].Mit getHost() lässt sich der Name des Rechners ermitteln, und mit [URL].getPort() lässt sich der Port ermitteln.
- Eine erste Schleife ermöglicht es jedem Client:
- eine Verbindung zum Webserver herzustellen
- eine Anfrage an den Server zu stellen
In dieser Schleife wartet der Client nicht auf die Antwort des Servers. Denn das Ziel ist es, den Server dazu zu bringen, nahezu gleichzeitige Anfragen zu empfangen.
- Eine zweite Schleife ermöglicht es jedem Client, die vom Server gesendete Antwort zu empfangen und zu verarbeiten. Die Verarbeitung besteht darin, in der Antwort die Zeile zu finden, die den Zählerstand enthält, und diese anzuzeigen.
Um das zuvor aufgezeigte Problem (derselbe Zähler wird an alle fünf Clients gesendet) zu lösen, müssen wir die Threads des Zählerservices auf ein und dasselbe Objekt synchronisieren, bevor wir in den kritischen Abschnitt zum Lesen und Aktualisieren des Zählers eintreten. Die neue Seite JSP sieht wie folgt aus:
<html>
<head>
<title>Compteur synchronisé</title>
</head>
<body>
Compteur= <%= getCompteur() %>
</body>
</html>
<%!
// globale Variablen und Methoden der Seite JSP
// Instanzvariablen
int compteur;
Object verrou=new Object();
// Methode zum Inkrementieren des Zählers
public int getCompteur(){
// Der kritische Abschnitt wird synchronisiert
synchronized(verrou){
// Der Zähler wird gelesen
int myCompteur=compteur;
// 10 Sekunden Pause
try{
Thread.sleep(10000);
}catch (Exception ignored){}
// Der Zähler wird erhöht
compteur=myCompteur+1;
}//synchronisiert
// wird zurückgesetzt
return compteur;
}//getCompteur
// die beim ersten Laden der Seite ausgeführte Methode
public void jspInit(){
// Zähler initialisieren
compteur=100;
}
%>
Bei der Ausführung erhält man dann folgende Ergebnisse:
dos>c:\perl\bin\perl.exe client2.pl http://localhost:8080/examples/jsp/perso/compteur/compteur3.jsp 5
Compteur= 104
Compteur= 106
Compteur= 105
Compteur= 107
Compteur= 108
In der Dokumentation wird darauf hingewiesen, dass der Webserver manchmal mehrere Instanzen desselben Servlets erstellen kann. In diesem Fall funktioniert die bisherige Synchronisation nicht mehr, da die Variable verrou lokal auf eine Instanz beschränkt ist und den anderen Instanzen daher nicht bekannt ist. Gleiches gilt für die Variable compteur. Um sie für alle Instanzen global zu machen, schreibt man:
// Klassenvariable
static int compteur;
static Object verrou=new Object();
Der Rest des Codes bleibt unverändert.





