Servlets Marc Monecke [email protected] Praktische Informatik Fachbereich Elektrotechnik und Informatik Universität Siegen, D-57068 Siegen 16. Juni 2003 Zusammenfassung Neben statischem HTML-Text werden in Web-Seiten oft auch dynamische Inhalte angezeigt. Solche Inhalte werden von Programmen erzeugt, die an den HTTP-Server angebunden sind. Das Servlet-API ist eine Programmierschnittstelle, mit der Java-Programme (Servlets) auf diese Weise verwendet werden können. Die Servlets werden in einem Servlet Container verwaltet, der für die Weiterleitung der Anfragen und die Rückgabe des Ergebnisses zuständig ist. Inhaltsverzeichnis 1 Einleitung und Motivation 1.1 CGI-Programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 2 Servlets 2.1 Aufgaben eines Servlets . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Vorteile gegenüber CGI . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 3 3 3 Klassenhierarchie 3.1 Servlet-Container . . . . 3.2 Einfaches HTTP-Servlet 3.3 Web-Anwendungen . . . 3.4 Aufruf eines Servlets . . 3.5 Servlet Context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 4 5 5 6 6 4 Servlet-Lebenszyklus 4.1 Initialisierung . . . . . . . . . . . 4.1.1 Initialisierungsparameter . 4.2 Ausführung . . . . . . . . . . . . 4.3 Zerstörung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 6 7 7 8 . . . . . . . . . . . . . . . . . . . . i 5 Parameter 5.1 Parameter an Links . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1.1 Verarbeitung im Servlet . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Verarbeitung von Formularen . . . . . . . . . . . . . . . . . . . . . . . . . 8 8 8 9 6 Sitzungen 6.1 Sitzungen mit Servlets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 10 7 Zusammenfassung 10 ii 1 Einleitung und Motivation – in Web-Anwendungen wird die Benutzungsschnittstelle durch Web Browser realisiert – Darstellung, Layout – Interaktion – ein HTTP-Server liefert die Daten (HTML-Seiten) auf Anfrage – oft werden neben statischem HTML-Text auch dynamische Inhalte benötigt: – Inhalt basiert auf Daten, die der Benutzer eingegeben hat – etwa einer Suchanfrage – Inhalt wird von Daten abgeleitet, die sich häufig ändern – etwa der Wetterbericht – Inhalt enthält Daten, die von Datenbanken oder Fremdsystemen geliefert werden – allgemein sind serverseitige Programme nötig, die die Daten ermitteln, erzeugen oder aufbereiten – Programme müssen an den HTTP-Server angebunden werden – weil der die Schnittstelle zum Klienten (dem Browser) bereitstellt 1.1 CGI-Programme – Lösung: Common Gateway Interface (CGI) – Abbildung 1 CGI Web Browser HTTP−Server CGI bin HTTP DB−Schnittstelle DB Abbildung 1: Anbindung von Programmen an den HTTP-Server über CGI – Der Aufruf eines angebundenen CGI-Programms (CGI binary, CGI bin) läuft wie folgt ab: 1. Der Browser nutzt das HTTP-Protokoll, um Anfragen an den HTTP-Server zu schicken. Eine Anfrage besteht aus der Adresse des ausführbaren CGI-Programms (eine URL) und optionalen Parametern. 2. Der HTTP-Server startet für jede Anfragen einen neuen (schwergewichtigen) Prozeß, der das CGI-Programm ausführt und übergibt die Parameter. 3. Das CGI-Programm erzeugt das Ergebnis, etwa indem es Daten aus einer Datenbank ausliest, und liefert es in Form einer HTML-Ausgabe an den HTTP-Server zurück. 4. Der HTTP-Server schickt das Ergebnis an den Browser weiter. 1 – Beispiel: http://pi.informatik.uni-siegen.de/cw-bin/dbs-I.cgi Hier wird eine SQL-Anfrage im Browser eingegeben und an ein Perl-Skript weitergeleitet, das die Anfrage auf einer Datenbank ausführt und das Ergebnis als Tabelle zurückliefert. Vorteile von CGI – HTTP-Server und Anwendungsprogramm klar getrennt – einfache, standardisierte Schnittstelle – dadurch ist das CGI-Programm weitgehend unabhängig vom verwendeten HTTP-Server – CGI-Programm kann in beliebiger Sprache geschrieben werden – häufig werden C und Perl verwendet. Hier stehen auch zahlreiche Bibliotheken mit Hilfsfunktionen zur Verfügung, die z.B. das Auslesen der Parameter und das Aufbereiten des Ergebnisses erleichtern. Nachteile von CGI – für jede Anfrage wird ein neuer Prozeß erzeugt → hoher initialer Aufwand bei jedem Zugriff – bei vielen parallelen Anfragen entsteht eine große Zahl von Prozessen → hoher Verwaltungsaufwand – Ressourcen (z.B. Datenbankverbindung) können nicht gemeinsam genutzt werden, da das CGI-Programm nach Bearbeitung der Anfrage nicht weiter existiert → besser ein Serverprozeß, der Anfragen entgegennimmt und Ressourcen verwaltet 2 Servlets – in Java geschriebene Programme – werden auf dem Server innerhalb eines Servlet-Containers ausgeführt (Abbildung 2) – Servlet-Container mit Verbindung zum HTTP-Server oder als Teil davon – das hängt vom verwendeten HTTP-Server, dem verwendeten Servlet-Container und der Konfiguration ab. Servlet-Container können auch allein (stand-alone) verwendet werden und übernehmen dann auch die Aufgaben eines einfachen HTTP-Servers. Ein solcher Betrieb ist besonders während der Entwicklung von Servlets sinnvoll. Servlet Container Web Browser HTTP−Server Servlet HTTP Abbildung 2: Servlets 2 2.1 Aufgaben eines Servlets Servlets übernehmen die gleichen Aufgaben wie traditionelle CGI-Programme. Allerdings können sie aufgrund der umfangreichen Servlet-Schnittstelle und den vom ServletContainer angebotenen Diensten meist komfortabler und schneller entwickelt werden. 1. Daten vom Klienten (Browser) einlesen (Anfrage, Request) 2. weitere Informationen über Anfrage ermitteln – z.B. Hostname, Browser, Cookies 3. auf Basis der empfangenen Daten und der ermittelten Informationen Ausgabedaten erzeugen – das Ergebnis kann direkt berechnet werden oder es können Informationen aus einer Datenbank oder von einem Fremdsystem angefordert werden 4. Ausgabedaten in Antwort (Response) gemäß HTTP verpacken – z.B. Angabe des Typs der übertragenen Daten (MIME header) 5. Senden des Ergebnisdokuments an den Klienten 2.2 Vorteile gegenüber CGI – Effizienz: alle Servlets werden in einer Java VM ausgeführt, diese wird zusammen mit dem HTTP-Server nur einmal gestartet. Jedes Servlet wird in einem thread ausgeführt – also unabhängig von den anderen Servlets, aber trotzdem mit nur geringem Verwaltungsaufwand. Die zugehörige Java-Klasse eines Servlets muß nur einmal in den Hauptspeicher geladen werden, auch wenn mehrere Instanzen davon existieren. Auch können mehrere Servlets oder mehrere Instanzen eines Servlets gemeinsame Ressourcen wie Datenbank-Verbindungen nutzen. – Einfache Benutzung: Entwickler müssen keine weitere Sprache neben Java beherrschen, um mit Servlets arbeiten zu können. Im Servlet-API sind Dienste vorgeschrieben, die die Verwendung des HTTP-Protokolls unterstützen. Die nötigen Funktionen sind also in den jeweiligen Implementierungen des API enthalten und müssen nicht in Zusatzbibliotheken bereitgestellt werden. – Portabilität: Java-Programme laufen auf jeder Plattform; Servlets können mit jedem Web-Server genutzt werden, der die standardisierte Servlet-Schnittstelle unterstützt – Sicherheit: Servlet-Container enthält Sicherheitsmechanismen während CGI-Programme direkt in der Betriebssystem-Umgebung ausgeführt werden – CGI-Entwickler müssen diese Mechanismen also selbst bereitstellen, etwa um den Zugriff auf Dateien einzuschränken oder den Aufruf eines CGI-Programms nur bestimmten Benutzern zu erlauben. 3 Klassenhierarchie Abbildung 3 zeigt einige Klassen und Schnittstellen, die bei der Arbeit mit Servlets relevant sind. – Schnittstelle Servlet: Die Operationen dieser Schnittstelle müssen alle Servlets implementieren: – init führt die Initialisierung des Servlets durch den Servlet-Container – in der service-Operation werden die Anfragen von Klienten bearbeitet 3 <<interface>> ServletConfig <<interface>> Servlet init() getServletName() getInitParameter() getServletContext() service() destroy() GenericServlet service() getServletConfig() HttpServlet init() init() destroy() doGet() doPost() doPut() Abbildung 3: Ausschnitt aus der Klassenhierarchie – destroy wird aufgerufen, wenn das Servlet nicht mehr gebraucht wird – sie kann also dazu genutzt werden, belegte Ressourcen freizugeben und temporäre Daten zu löschen. Die destroy-Operation sollte allerdings nicht dazu genutzt werden, Daten wie den Sitzungszustand oder statistische Daten zu sichern, da sie nicht in allen Fällen aufgerufen werden muß – etwa, wenn ein Systemfehler auftritt. – Schnittstelle ServletConfig: Objekte mit dieser Schnittstelle werden vom ServletContainer bei der Initialisierung erzeugt. Die Schnittstelle enthält z.B. die Operationen: – getServletName liefert den Namen des Servlets zurück – getInitParameter erlaubt den Zugriff auf Initialisierungsparameter, die bei der Installation des Servlets im Container definiert werden können. Sie erlauben es, das Servlet für die gegebene Aufgabe zu konfigurieren. – getServletContext liefert ein ServletContext-Objekt zurück, das zur Kommunikation zwischen Servlet-Container und Servlet dient (genauer: ein Objekt, dessen Klasse die Schnittstelle ServletContext implementiert). Es kann auch verwendet werden, um globale Informationen zu speichern (s. Abschnitt 3.5). – GenericServlet: Basisklasse für Servlets. Anfragen eines Klienten werden an die Operation service weitergeleitet. – HttpServlet: Basisklasse für Servlets, die das HTTP-Protokoll unterstützen, und meist Ausgangspunkt für die Entwicklung eigener Servlets. Anfragen des Klienten werden hier gleich auf die passenden Operationen doGet, doPost, doPut usw. abgebildet. 3.1 Servlet-Container – verwaltet Servlets – bietet Schnittstelle zur Kommunikation zwischen Servlet und Container – kann Dienste für Verteilung, Sicherheit anbieten – Beispiel: Tomcat aus dem Apache Jakarta-Projekt – implementiert Servlet- und Java ServerPages-API 4 – kann allein genutzt werden oder integriert in Apache Web-Server 3.2 Einfaches HTTP-Servlet import javax.servlet.*; import javax.servlet.http.*; public class Hello extends HttpServlet { String title = "STII Demo Servlet"; public void doGet ( HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html><head>"); out.println("<title>" + title + "</title>"); out.println("</head><body>"); out.println("<h1>" + title + "</h1>"); out.println("<b>sehr einfaches Servlet</b>"); out.println("</body></html>"); } } – Antwort auf get-Anfragen: doGet – Informationen über die Anfrage in HttpServletRequest enthalten – Ergebnis in HttpServletResponse zurückliefern – Typ des Ergebnisses mit setContentType() angegeben – dabei wird der MIMETyp (Multipurpose Internet Mail Extensions) angegeben, im Beispiel text/html für HTML; bei Bildern z.B. image/gif und bei PDF-Dateien application/pdf. – Ausgaben mit println in Ausgabestrom schreiben → response.getWriter() 3.3 Web-Anwendungen – Servlets sind Teil einer Web-Anwendung, enthält – Servlets – JSP-Seiten – JavaBeans und ’einfache’ Java-Klassen – weitere Ressourcen wie HTML-Texte, Bilder – Web-Anwendung wird im HTTP-Server/Servlet-Container installiert – eine installierte Web-Anwendung wird automatisch mit dem Servlet-Container gestartet und kann über eine URL aufgerufen werden. Bei der Installation kann die Anwendung auch konfiguriert werden, indem Initialisierungsparameter für die Servlets angegeben oder Benutzer und Zugriffsrechte eingerichtet werden. 5 – Servlet-Container enthält Administrations-/Management-Werkzeuge zum Starten, Stoppen, Neuladen von Web-Anwendungen – Auslieferung in Web-Archivdatei (.war): zip-Archiv mit Manifest-Datei – zur Laufzeit: Web-Anwendung definiert Servlet Context 3.4 Aufruf eines Servlets – URL zum Aufruf von Servlets: http://hostname/servlet/servlet-name in diesem Fall liegen alle Servlets in einem gemeinsamen ’Namensraum’. Dies ist möglich, weil der Servlet-Container einen Bereich zu Verfügung stellt, der keiner WebAnwendung zugeordnet ist (root context). Als Teil einer Web-Anwendung werden Servlets über den Namen der Anwendung identifiziert. – Web-Anwendung hat einen Namen, über den sie identifiziert wird: Beispiel: Web-Anwendung demo → http://localhost:8080/demo/servlet/Hello – abhängig vom Servlet-Container können weitere Namen zugeordnet werden → ist Servlet Hello weiterer Name hi zugeordnet: http://localhost:8080/demo/hi – ggf. mit Paketname: http://localhost/servlet/pi.vorlesung.Hello wenn Servlet-Klasse im Paket pi.vorlesung – direkter Zugriff auf den Servlet-Container → Port-Nummer angeben Beispiel: http://pi55.informatik.uni-siegen.de:8080/servlet/Hello (also Port 8080, vorgegeben bei Tomcat) 3.5 Servlet Context – Objekt mit Schnittstelle ServletContext repräsentiert Web-Anwendung – ein Objekt pro Anwendung und pro Java-VM – üblicherweise also genau ein Objekt pro Anwendung. Unterstützt der Servlet-Container aber verteilte Anwendungen, wird auf jedem Rechner, auf dem die Anwendung läuft, jeweils eine Java-VM gestartet mit jeweils einem ServletContext pro Anwendung. – ermöglicht die Kommunikation mit dem Servlet-Container – Abbildung von relativen auf absolute Pfade – Verwaltung globaler Variablen der Anwendung Operationen: setAttribute(), getAttribute() 4 4.1 Servlet-Lebenszyklus Initialisierung – Operation init führt Initialisierungen durch – z.B. Datenbankverbindung aufbauen, komplexe Berechnungen durchführen – wird nur einmal pro Servlet aufgerufen; nicht für jede Anfrage! – Erzeugen/Initialisieren des Servlets 6 – beim Start des Servlet-Containers oder – beim ersten Aufruf des Servlets Das Servlet wird beim Start des Servlet-Containers erzeugt und initialisiert, wenn es explizit beim Servlet-Container angemeldet ist (wie das geht, hängt vom Container ab). Andernfalls wird es beim ersten Aufruf erzeugt. 4.1.1 Initialisierungsparameter – werden dem Servlet bei der Initialisierung mitgegeben – erlauben die Konfiguration von Servlets – Definition serverabhängig – Tomcat: Angabe in der web.xml <servlet> <servlet-name> Hello2 </servlet-name> <servlet-class> Hello2 </servlet-class> <init-param> <param-name>message</param-name> <param-value>Nachricht im Initialisierungsp...</param-value> </init-param> </servlet> Servlet-Code – Zugriff auf die Initialisierungsparameter über ServletConfig.getInitParameter() /* Hello2.java */ ... public void init ( ServletConfig config ) { super.init ( config ); message = config.getInitParameter ( "message" ); if ( message == null ) message = "keine Nachricht!"; } ... 4.2 Ausführung – Beim Aufruf eines Servlets wird ein neuer thread gestartet und die Operation service ausgeführt – HttpServlet: Anfrage an Operationen doGet(), doPost() usw. weiterleiten – diese Operationen enthalten die eigentliche Funktionen des Servlets 7 – normalerweise existiert nur eine Instanz des Servlets, dessen Operationen in verschiedenen threads ausgeführt werden → Zugriffe auf gemeinsame Daten synchronisieren! – Ausnahme: Servlet implementiert SingleThreadModel → eine Instanz pro Anfrage 4.3 Zerstörung – Servlets können zerstört werden (ausgelöst durch Administrator oder weil lange nicht benutzt) → Ressourcen sparen – dazu wird Operation destroy aufgerufen → aufräumen, Datenbank-Verbindung schließen, Daten sichern o.ä. – Vorsicht: man kann sich nicht darauf verlassen, daß destroy wirklich aufgerufen wird – etwa, wenn der Servlet-Container abstürzt. Wichtige Daten sollten daher regelmäßig gesichert werden und nicht erst, wenn die destroy-Operation aufgerufen wird. 5 Parameter – Servlets können beim Aufruf Parameter übergeben werden – Paar aus Name und Wert – Wert ist immer eine Zeichenkette – Übergabe auf zwei Arten: 1. Anhängen an Link 2. Erfassen im Formular 5.1 Parameter an Links – werden hinter ? an URL angehängt – mehrere Parameter durch & getrennt – Beispiel: http://localhost:8080/servlet/demo/Param?nachname=Meier&ort=... – Übertragung mit HTTP-get-Befehl 5.1.1 Verarbeitung im Servlet – in doGet-Operation; Parameter im HttpServletRequest enthalten – Zugriffsoperationen: String Enumeration Map String[] getParameter ( String name ) getParameterNames () getParameterMap () getParameterValues ( String name ) 8 public class Param extends HttpServlet { public void doGet ( HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException { ... nachname = request.getParameter ( "nachname" ); ... } ... 5.2 Verarbeitung von Formularen – HTML-Formulare bestehen aus – Eingabefeldern für Texte, Listen, Ankreuzfelder – Buttons zum Absenden (submit) und Löschen (reset) des Formularinhalts – beim Absenden wird eine Aktion ausgeführt → URL verweist auf Servlet – allgemein können als Aktion eines Formulars auch CGI-Programme und HTML-Seiten angegeben werden, in denen die Formular-Daten z.B. von Javascript-Code verarbeitet wird. – beim submit werden die Daten als Parameter an die URL übergeben – zwei HTTP-Übertragungsmethoden: 1. get: Daten werden als Parameter an die URL angehängt → eher für einfache Daten 2. post: Daten werden vom HTTP-Server im Standard-Eingabekanal zur Verfügung gestellt → eher für umfangreiche Daten, die weiterverarbeitet werden sollen (z.B. Speichern in Datenbank) In CGI-Programmen muß dieser Unterschied berücksichtigt werden: Parameter, die per get übertragen wurden, werden in der in Abschnitt 5.1 beschriebenen Form in einer Umgebungsvariable gespeichert. Das CGI-Programm muß diese Variable auslesen und die Namen und Werte der Parameter extrahieren. Dies wird z.B. in Perl durch spezielle Funktionsbibliotheken erleichtert. Bei post-Parametern muß dagegen stdin abgefragt und die einzelnen Parameter extrahiert werden. Das CGI-Programm muß also die verwendete Übertragungsmethode kennen oder so programmiert sein, daß es die verwendete Methode ermittelt. Bei Servlets ist eine solche Unterscheidung nicht nötig: Der Servlet-Container übernimmt automatisch die Konvertierung und stellt dem Servlet die Parameter immer im HttpServletRequest zur Verfügung. 6 Sitzungen – HTTP zustandslos → zwei aufeinanderfolgende Aufrufe können nicht dem gleichen Benutzer zugeordnet werden! – oft müssen Daten/Zustand der bisherigen Interaktionen bewahrt bleiben (Benutzername, selektierte Einträge, Einkaufskorb. . . ) → Sitzungen (Sessions) nötig 9 – also zusammenhängende Folge von Anforderungen und Antworten – bei CGI: Sitzungen mit Cookies, zusätzlichen Parametern in URL (URL rewriting), versteckten Werte in Formularen realisierbar 6.1 Sitzungen mit Servlets – Session durch Objekt mit Schnittstelle HttpSession repräsentiert – Zugriff auf Informationen über Session (Erzeugungs-, Zugriffszeit. . . ) – Speichern von Daten in der Session → setAttribute(), getAttribute() – wird im HttpServletRequest mitgeliefert: HttpSession session = request.getSession () – Session wird automatisch vom Servlet-Container zerstört, wenn für eine einstellbare Zeit nicht aktiv → setMaxInactiveInterval() 7 Zusammenfassung – Servlets sind in Java geschrieben Programme zum Erzeugen dynamischer WebInhalte – haben Vorteile gegenüber CGI-Programme – laufen in Servlet Containern – z.B. Apache Tomcat – können Daten per HTTP-get und post verarbeiten – automatische Verwaltung von Sessions 10