Filterprogrammierung: Beispiel
package de.rainer_klute.servlet;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
/**
* <p>This demo filter replaces a configurable hostname in a
* {@link ServletRequest} by a replacement string.</p>
*/
public class HostChangeFilter implements Filter
{
FilterConfig config;
String hostname;
String replacement;
public void init(FilterConfig config)
{
/* Could be used to fetch the ServletContext. */
this.config = config;
hostname = config.getInitParameter("Hostname");
replacement = config.getInitParameter("Replacement");
}
Web−Anwendungen mit Java
351
Filterprogrammierung: Beispiel
public void doFilter(ServletRequest req,
ServletResponse res,
FilterChain chain)
throws IOException, ServletException
{
ServletRequest wrapper =
new HttpServletRequestWrapper((HttpServletRequest) req)
{
public String getRemoteHost()
{
final String s =
getRequest().getRemoteHost();
if (s.equals(hostname))
return replacement;
else
return s;
}
};
chain.doFilter(wrapper, res);
}
public void destroy()
{}
Web−Anwendungen mit Java
}
352
Filterprogrammierung
Zentrale Methode:
FilterChain.doFilter(ServletRequest
request, ServletResponse response)
Ruft nächsten Filter in der Filterkette oder Ressource
Parameter: Wrapper oder Original−Request/Response
ServletRequestWrapper, ServletResponseWrapper
HttpServletRequestWrapper, HttpServletResponseWrapper
Implementieren ServletRequest, ServletResponse,
HttpServletRequest, HttpServletResponse
Tomcat 4.0.3 erwartet HttpServletRequest und
HttpServletResponse.
Methoden überschreiben, neue definieren
Web−Anwendungen mit Java
353
Filterkonfiguration
Konfiguration im Deployment descriptor
Definition:
<filter>
<filter−name>Filter 1</filter−name>
<filter−class>
de.rainer_klute.servlet.HostChangeFilter
</filter−class>
<init−param>
<param−name>Hostname</param−name>
<param−value>mark.rainer−klute.de</param−value>
</init−param>
<init−param>
<param−name>Replacement</param−name>
<param−value>foo.bar.de</param−value>
</init−param>
</filter>
Web−Anwendungen mit Java
354
Filterkonfiguration
Mapping:
<filter−mapping>
<filter−name>Filter 1</filter−name>
<servlet−name>Snoop</servlet−name>
</filter−mapping>
<filter−mapping>
<filter−name>Filter 2</filter−name>
<servlet−name>Snoop</servlet−name>
</filter−mapping>
Aufrufreihenfolge entspricht der Reihenfolge im
Deployment descriptor
Im Beispiel: Filter 1 → Filter 2 → Snoop
Web−Anwendungen mit Java
355
Anwendungsereignisse
Ereignisse, die eine Web−Anwendung als ganzes
betreffen
Servlet−Kontext
Sessions
potentiell alle Servlets der Anwendung
Web−Anwendungen mit Java
356
Anwendungsereignisse: Interfaces
Listener−Interfaces
javax.servlet.ServletContextListener
Erzeugen und Beenden des Servlet−Kontexts
javax.servlet.ServletContextAttributeListener
Änderungen an ServletContext−Attributen
javax.servlet.http.HttpSessionActivationListener
Aktivieren und Deaktivieren von Sessions
javax.servlet.http.HttpSessionListener
Erzeugen und Beenden von Sessions
javax.servlet.http.HttpSessionAttributeListener
Änderungen an Session−Attributen
Servlet−Container stellt den Implementierungen
Event−Objekte zu.
Web−Anwendungen mit Java
357
Anwendungsereignisse: Beispiel
package de.rainer_klute.servlet;
import javax.servlet.*;
import javax.servlet.http.*;
public class SessionListener implements HttpSessionListener
{
public void sessionCreated(HttpSessionEvent e)
{
// ...
}
public void sessionDestroyed(HttpSessionEvent e)
{
// ...
}
}
Web−Anwendungen mit Java
358
Listener−Klassen registrieren
Registrierung im Deployment Descriptor nötig
Beispiel:
<listener>
<listener−class>
de.rainer_klute.servlet.SessionListener
</listener−class>
</listener>
<listener>
<listener−class>
de.rainer_klute.servlet.FooListener
</listener−class>
</listener>
Web−Anwendungen mit Java
359
JDBC
JDBC
Web−Anwendungen mit Java
360
JDBC
Standard−API für den Java−Zugriff auf relationale
Datenbanksysteme
Oracle, DB2, Informix, Adabas D
PostgreSQL, MySQL
usw.
Web−Anwendungen mit Java
361
Erwartungen
Was Sie nicht erwarten können
Einführung in relationale Datenbanksysteme
(Relationenalgebra, Relationenkalkül)
Anfragesprache SQL
Was Sie erwarten können
Einführung in JDBC
Beispiele mit Datenbanksystem PostgreSQL
Web−Anwendungen mit Java
362
Vertiefung
Dokumentation zu PostgreSQL lesen
Beschreibt nicht nur PostgreSQL selbst, sondern auch...
Relationale Datenbanksysteme
Anfragesprache SQL
Literaturverweise
Web−Anwendungen mit Java
363
DBMS−Typen
Database Management System
Relationales DBMS (RDBMS)
Speichert Daten in Tabellen (Relationen).
Abfragesprache SQL
Objektorientiertes DBMS (OODBMS)
Speichert Objekte unmittelbar.
Objektrelationales DBMS (ORDBMS)
Oberbegriff für Datenbanksysteme
Bietet sowohl Objekt− als auch Relationensicht.
JDBC unterstützt (objekt−)relationale
Datenbanksysteme.
Web−Anwendungen mit Java
364
Datenbank
Tabellen (Relationen)
Daten
Beispiele: Artikel eines Katalogs, Bestellungen
Views
Sichten auf Daten
Beispiel: Artikel sortiert nach Umsatz
Indizes
»Vorsortierungen« von Tabellen
Stored Procedures
In der Datenbank gespeicherte Programme
Web−Anwendungen mit Java
365
Tabellen
Darstellung von Relationen (siehe Fachliteratur)
Beispiele:
PostgreSQL
»The most advanced open source database
management system«
Läuft unter Unix (diverse Varianten, u.a. Linux) und
Windows (mit Cygwin)
Fast vollständige Unterstützung des Standards SQL92
Transaktionen (im Unterschied zu MySQL)
Zusätzliche Features
ORDBMS, max. Zellengröße 1 GB, Tupelgröße
unbegrenzt u.v.a.m.
Geringer Hauptspeicherbedarf
Sehr gute Dokumentation
Web−Anwendungen mit Java
367
PostgreSQL als Client−/Server−System
Client−/Server−System
Prozeß postmaster
Läuft permanent auf Server−Maschine.
Nimmt Verbindungsaufbauwünsche über das Netz
entgegen.
Datenbank−Client baut Verbindung zum Postmaster
auf.
Postmaster startet Datenbank−Server−Prozeß
postgres für den Client.
Web−Anwendungen mit Java
368
PostgreSQL als Client−/Server−System
Sitzung
Client: schickt SQL−Anweisung zum Server.
Server: schickt Ergebnis zum Client.
usw.
Client beendet Verbindung.
Server−Prozeß terminiert.
Web−Anwendungen mit Java
369
SQL−Monitor »psql«
Zu PostgreSQL gehörender Datenbank−Client
Interaktives Arbeiten mit Datenbanken
SQL−Anweisungen.
Datenbanken anlegen, Tabellen definieren, Daten
ändern, Datenbankanfragen absetzen usw. usw.
Baut Verbindung zum Datenbank−Server auf
(genauer: zum Postmaster−Prozeß).
Beispiel: psql −h carne01 eshop
Baut Verbindung zum Postmaster auf Rechner carne01
auf und öffnet Datenbank eshop.
Weitere Informationen: Kommando »man psql«
Web−Anwendungen mit Java
370
SQL−Monitor »psql«
SQL−Anweisungen an Datenbank−Server
SELECT * FROM artikel;
SQL−Anweisungen mit »;« beenden
Hilfe zu SQL−Anweisungen
Kommando »man create_table« usw.
psql−Anweisung »\h create table«
Anweisungen an psql
Beispiel: \H schaltet HTML−Modus ein oder aus
Beispiel: \i datei.sql
SQl−Anweisungen aus datei.sql lesen und ausführen
Hilfe zu allen psql−Anweisungen mit »\?«
Web−Anwendungen mit Java
371
E−Shop−Datenbank einrichten
SQL−Monitor psql starten
psql −h carne01 template1
Siehe unten: PostgreSQL−Umgebung
Öffnet Datenbank template1 (in PostgreSQL immer
vorhanden)
Datenbank eshop erzeugen
CREATE DATABASE eshop;
Statt eshop sollte jeder Benutzer einen anderen
Datenbanknamen verwenden.
Beispiel: CREATE DATABASE eshop_pkjf123;
Zu neuer Datenbank eshop wechseln
\c eshop
Web−Anwendungen mit Java
372
E−Shop−Datenbank einrichten
Tabelle artikel definieren
CREATE TABLE artikel
(id INTEGER PRIMARY KEY,
bezeichnung CHARACTER VARYING NOT NULL UNIQUE,
text CHARACTER VARYING,
preis DECIMAL(10,2) NOT NULL CHECK (preis > 0));
PRIMARY KEY: Wert identifiziert Artikel eindeutig.
CHARACTER VARYING: Textfeld variabler Länge
NOT NULL: Feld darf nicht leer sein.
UNIQUE: Feldwert ist für gesamte Tabelle eindeutig.
DECIMAL(10,2): Dezimalwert mit 10 Stellen Genauigkeit
und 2 Nachkommastellen
CHECK (preis > 0): Wert von preis muß größer 0 sein.
Web−Anwendungen mit Java
373
E−Shop−Datenbank einrichten
Tabelle artikel mit Daten füllen
INSERT INTO artikel (id, bezeichnung, preis)
VALUES (4711, ’Duftwasser’, 15.95);
INSERT INTO artikel (id, bezeichnung, preis)
VALUES (0815, ’ISDN−Telefon’, 123.45);
INSERT INTO artikel (id, bezeichnung, preis)
VALUES (1234, ’Notebook’, 2500);
INSERT INTO artikel (id, bezeichnung, preis)
VALUES (538, ’Lolly’, 0.05);
DBMS prüft Daten auf Gültigkeit.
INSERT INTO artikel (id, bezeichnung, preis)
VALUES (0815, ’Lolly’, 0);
ExecAppend: rejected due to CHECK constraint
artikel_preis
Web−Anwendungen mit Java
374
E−Shop−Datenbank einrichten
Tabelle kunden definieren und mit Daten füllen
CREATE TABLE kunden
(id INTEGER PRIMARY KEY,
konto INTEGER NOT NULL,
blz INTEGER NOT NULL,
name CHARACTER VARYING);
INSERT INTO kunden VALUES
(10017, 123456700, 38070724, ’Karl Käufer’);
INSERT INTO kunden VALUES
(12659, 234567890, 44050199, ’Karin Kunde’);
Weitere Kundendaten wie Rechnungsadresse,
Lieferanschrift, Bonität, Rabattklasse usw. werden hier
nicht unterstützt.
Web−Anwendungen mit Java
375
E−Shop−Datenbank einrichten
Tabelle bestellungen definieren
CREATE TABLE bestellungen
(artikel INTEGER REFERENCES artikel (id),
kunde INTEGER REFERENCES kunden (id),
anzahl INTEGER NOT NULL);
REFERENCES artikel (id): Feld ist Fremdschlüssel.
Referenziert Schlüssel id in Tabelle artikel.
Referenzierte Zeilen können nicht gelöscht werden
(Voreinstellung).
Tabelle mit Daten füllen
INSERT INTO bestellungen VALUES ( 815, 10017, 1);
INSERT INTO bestellungen VALUES (1234, 10017, 1);
INSERT INTO bestellungen VALUES ( 815, 12659, 2);
Web−Anwendungen mit Java
376
Referentielle Integrität
Versuch scheitert, eine referenzierte Zeile zu löschen.
DELETE FROM artikel WHERE id = 0815;
ERROR: <unnamed> referential integrity violation −
key in artikel still referenced from bestellungen
Web−Anwendungen mit Java
377
Daten abfragen
Tabelle anzeigen: alle Artikel auflisten
SELECT * FROM artikel;
id | bezeichnung | text | preis
−−−−−−+−−−−−−−−−−−−−−+−−−−−−+−−−−−−−−−
4711 | Duftwasser
|
|
15.95
815 | ISDN−Telefon |
| 123.45
1234 | Notebook
|
| 2500.00
538 | Lolly
|
|
0.05
(4 rows)
SELECT−Anweisung stellt Datenbank−Anfrage
(»Query«).
Stern (*) selektiert alle Spalten der Tabelle.
Web−Anwendungen mit Java
378
Daten abfragen
Tabellen kombinieren
SELECT * FROM artikel, bestellungen;
Kombiniert jede Zeile der ersten Tabelle mit jeder Zeile
der zweiten Tabelle (kartesisches Produkt).
Daten abfragen
Ergebnisrelation auf interessante Tupel einschränken
(Selektion)
Bestellte Artikel
SELECT * FROM artikel, bestellungen
WHERE artikel.id = bestellungen.artikel;
Web−Anwendungen mit Java
380
Daten abfragen
Ergebnisspalten auswählen (Projektion)
Bezeichnung der Ergebnisspalten wählen
Spalteninhalt dynamisch berechnen
SELECT name AS "Name", bezeichnung AS "Artikel",
anzahl AS "Stückzahl", preis AS "Einzelpreis",
(anzahl * preis) AS "Gesamtpreis"
FROM bestellungen, artikel, kunden
WHERE artikel.id = bestellungen.artikel
AND kunden.id = bestellungen.kunde;
PostgreSQL auf den Übungsrechnern
PostgreSQL 7.2 installiert in
/home/pkjf/pkjf000/postgresql
Unterverzeichnisse:
bin: Programme, z.B. psql, postmaster
lib: Shared libraries, JDBC−Implementierung
doc/html: Dokumentation
man: Manualseiten
Web−Anwendungen mit Java
382
PostgreSQL auf den Übungsrechnern
Umgebung(svariablen) für PostgreSQL einrichten
Kommandos für Shell sh bzw. bash:
Zum automatischen Ausführen beim Einloggen in Datei
~/.bashrc aufnehmen!
# Installationsverzeichnis
PGROOT="/home/pkjf/pkjf000/postgresql"
# Suchpfad für Programme erweitern:
PATH="${PGROOT}/bin:${PATH}"
# Suchpfad für Shared libraries setzen
# (bei Bedarf erweitern):
LD_LIBRARY_PATH="${PGROOT}/lib"
# Suchpfad für Manualseiten erweitern:
MANPATH="${PGROOT}/man:${MANPATH}"
Web−Anwendungen mit Java
383
PostgreSQL auf den Übungsrechnern
# Suchpfad für Java−Klassen erweitern:
CLASSPATH="${CLASSPATH}:${PGROOT}/lib/postgresql.jar"
# Port des PostgreSQL−Servers:
PGPORT="5432"
# Umgebungsvariablen exportieren:
export PATH
export LD_LIBRARY_PATH
export CLASSPATH
export PGPORT
Shells csh und tcsh:
set PGROOT="/home/pkjf/pkjf000/postgresql"
setenv PATH "${PGROOT}/bin:${PATH}"
# usw.
Zum automatischen Ausführen beim Einloggen in
Datei ~/.cshrc aufnehmen!
Web−Anwendungen mit Java
384
PostgreSQL auf den Übungsrechnern
Datenbank−Server läuft auf carne01.
Start des Datenbank−Servers erfolgt manuell unter der
Benutzerkennung pkjf000:
postmaster −D /home/pkjf/pkjf000/postgresql/data \
−i −p 5703 \
>/tmp/pgsql.log 2>&1 &
Voreinstellung: maximal 32 gleichzeitige Verbindungen
Benutzer pjkf000 bis pkjf099 sind eingerichtet.
Web−Anwendungen mit Java
385
Eigene PostgreSQL−Konfiguration
PostgreSQL erlaubt den Betrieb eigener Datenbank−
Cluster
Wichtig, falls Postmaster auf carne01 einmal nicht laufen
sollte
Verzeichnis für Datenbank−Cluster einrichten und mit
initdb initialisieren
mkdir /tmp/mycluster
initdb −D /tmp/mycluster
Leerer Cluster belegt ca. 20 MB Plattenplatz.
Sicherheit des Clusters in Datei pg_hba.conf
konfigurieren
Details siehe Kommentare in dieser Datei
Web−Anwendungen mit Java
386
Eigene PostgreSQL−Konfiguration
Postmaster starten
postmaster −i −D /tmp/mycluster −p 5555
TCP/IP−Zugriff mit −i erlauben
Eigenes Cluster−Verzeichnis mit −D angeben
Eigenen Port mit −p angeben
Weitere Informationen:
PostgreSQL−Dokumentation
»man postmaster«
»man psql«
Web−Anwendungen mit Java
387
Sicherheit auf den Übungsrechnern
Die PostgreSQL−Konfiguration auf den
Übungsrechnern bietet keine hohe Sicherheit.
Kein Paßwortschutz
Jeder Benutzer kann sich mit jeder Datenbank verbinden.
Paßwort bei JDBC−Verbindungen wird ignoriert.
Tabellen gehören dem Benutzer, der sie angelegt hat.
Zugriffsrechte mit GRANT weitergeben
GRANT select ON mytable TO pkjf123;
Zugriffsrechte mit REVOKE entziehen
REVOKE ALL ON mytable FROM pkjf123;
Web−Anwendungen mit Java
388
Sicherheit auf den Übungsrechnern
Netzzugriff nur für Übungsrechner carne01 bis
carne12 erlaubt
Das heißt: kein Zugriff auf die Datenbanken von außen
Entspricht dem üblichen Einsatzszenario der
Dreischichtenarchitektur
Browser → Applikationsserver → DBMS
Web−Anwendungen mit Java
389
Dreischichtenarchitektur
»Three tier architecture«
Browser
Firewall (erlaubt nur HTTP und
HTTPS)
Web−Anwendungen mit Java
Applikation
s−Server
DBMS
390
Wichtige PostgreSQL−Besonderheiten
VACUUM [FULL]
VACUUM ANALYZE
Aktualisiert Datenbankstatistiken für Optimizer
EXPLAIN SELECT ...
Gewinnt Platz gelöschter Datensätze zurück
Ausführungsplan einer Anfrage zeigen
Programme
initdb initialisiert Datenbank−Cluster
pg_dump extrahiert eine komplette Datenbank als SQL−
Skript oder in weiteren Formaten.
pg_restore restauriert eine Datenbank oder Teile davon.
Web−Anwendungen mit Java
392
JDBC−Beispiel: Daten abfragen
package de.rainer_klute.jdbc;
import java.io.*;
import java.sql.*;
/**
* <p>E−Shop−Bestellungen als HTML−Tabelle.</p>
*/
public class Bestellungen
{
public static void main(String argv[])
throws ClassNotFoundException, SQLException
{
/* JDBC−Treiber laden */
Class.forName("org.postgresql.Driver");
/* JDBC−URL der Datenbank spezifizieren */
String url = "jdbc:postgresql://mark:5712/eshop";
Web−Anwendungen mit Java
393
JDBC−Beispiel: Daten abfragen
/* Datenbankverbindung aufbauen */
Connection con = DriverManager.getConnection
(url, argv[0], argv[1]);
/* Statement erzeugen */
Statement stmt = con.createStatement();
/* SQL−Abfrage ausführen −
* Ergebnis ist ein ResultSet */
String query =
"SELECT name AS \"Name\"," +
"
bezeichnung AS \"Artikel\"," +
"
anzahl AS \"Stückzahl\"," +
"
preis AS \"Einzelpreis\"," +
"
(anzahl * preis) AS" +
"
\"Gesamtpreis\"" +
" FROM bestellungen, artikel, kunden" +
" WHERE artikel.id = bestellungen.artikel" +
"
AND kunden.id = bestellungen.kunde";
ResultSet rs = stmt.executeQuery(query);
Web−Anwendungen mit Java
394
JDBC−Beispiel: Daten abfragen
/* Ergebnisrelation als HTML−Tabelle ausgeben */
PrintStream p = System.out;
p.println("<!DOCTYPE HTML PUBLIC " +
"\"−//W3C//DTD HTML 4.0//EN//\">");
p.println("<TITLE>SQL−Abfrage mit JDBC</TITLE>");
p.println("<H1>SQL−Abfrage mit JDBC</H1>");
p.println("<H2>Abfrage:</H2>");
p.println("<P>" + query + "</P>");
p.println("<H2>Ergebnistabelle:</H2>");
p.println("<TABLE BORDER=’1’>");
/* Anzahl der Spalten ermitteln */
ResultSetMetaData rsmd = rs.getMetaData();
int columns = rsmd.getColumnCount();
Web−Anwendungen mit Java
395
JDBC−Beispiel: Daten abfragen
/* Spaltennamen aus Metadaten ermitteln und in
* erste Tabellenzeile ausgeben */
p.println("<TR>");
for (int i = 1; i <= columns; i++)
p.println("<TH><P>" + rsmd.getColumnName(i) +
"</P></TH>");
p.println("</TR>");
/* Ergebniszeilen ausgeben */
while (rs.next())
{
p.println("<TR>");
for (int i = 1; i <= columns; i++)
{
/* Zelleninhalt ausgeben */
Object o = rs.getObject(i);
p.print("<TD><P>" + o + "</P></TD>");
}
p.println("</TR>");
}
Web−Anwendungen mit Java
396
JDBC−Beispiel: Daten abfragen
p.println("</TABLE>");
/* ResultSet schließen */
rs.close();
/* Statement−Objekt schließen */
stmt.close();
}
/* Datenbankverbindung schließen */
con.close();
}
Web−Anwendungen mit Java
397
JDBC−Konzepte
Pakete
java.sql enthält JDBC−Basisfunktionalität.
javax.sql enthält zusätzliche Funktionalität für Row sets
und Connection pooling.
Wird hier behandelt.
In J2EE (Java 2 Enterprise Edition) enthalten
JDBC−Treiber kapseln die DBMS−spezifischen
Mechanismen.
Aufbau der Verbindung zur Datenbank
Datenaustausch
Unterschiede in SQL−Dialekten
Web−Anwendungen mit Java
398
JDBC−Treiber laden
Class.forName("org.postgresql.Driver");
Lädt die Klasse org.postgresql.Driver.
JDBC−Treiber registriert sich beim DriverManager.
Alternative: JDBC−Treiber beim Programmstart als
Property jdbc.drivers spezifizieren
java \
−Djdbc.drivers=sun.jdbc.odbc.JdbcOdbcDriver:org.postgresql.Driver \
de.rainer_klute.jdbc.Bestellungen
Vorteile beim Verwenden von jdbc.drivers:
JDBC−Treiber nicht fest vorgeben
Nutzung eines anderen JDBC−Treibers erfordert im
Idealfall keine Änderung des Quellcodes.
Web−Anwendungen mit Java
399
JDBC−Treiber
JDBC selbst besteht im wesentlichen aus Interfaces.
Connection, Statement, ResultSet usw.
Implementierung der Interfaces durch den JDBC−
Treiber
org.postgresql.jdbc2.Connection,
org.postgresql.jdbc2.Statement,
org.postgresql.jdbc2.ResultSet usw.
JDBC−Treiber stammen in der Regel vom DBMS−
Anbieter.
Der Entwickler programmiert nur mit den Interfaces,
nicht mit den Treiberklassen.
Web−Anwendungen mit Java
400