Java Enterprise: APIs Servlet

Aus Wikibooks

Als Servlet bezeichnet man im Rahmen der Java Enterprise: Plattform (J2EE) ein Java-Objekt , an das ein Webserver Anfragen seiner Clients delegiert, um die Antwort an den Client zu erzeugen. Der Inhalt dieser Antwort wird dabei erst im Moment der Anfrage generiert, und ist nicht bereits statisch (etwa in Form einer HTML-Seite) für den Webserver verfügbar.

Servlets stellen damit im Rahmen der J2EE-Spezifikation das Pendant zu einem Common Gateway Interface (CGI-Skript) oder anderen Konzepten, mit denen dynamisch Web-Inhalte erstellt werden können (PHP etc.) dar. Sie sind Instanzen von Java-Klassen, die von der durch die Spezifikation definierten Klasse javax.servlet.HttpServlet abgeleitet wurden. Diese Instanzen werden bei Bedarf von einer Laufzeitumgebung, dem sogenannten Web-Container erzeugt und von ihm aus angesprochen. Der Webcontainer seinerseits kommuniziert mit dem Webserver.

Servlets werden oft nach dem Model-View-Controller (Muster:MVC)-Pattern zusammen mit JSP verwendet, wobei das Servlet den Controller und die JSP-Seite einen View repräsentiert.

Bei Verwendung der Servlet-Spezifikation und einer entsprechenden Webcontainer-Umgebung besteht die Implementierung einer dynamischen Webseite in folgendem: Es wird eine von javax.servlet.HttpServlet abgeleitete Klasse erstellt. Zwei Methoden der Superklasse werden überschrieben, die für die Verarbeitung der beiden Kernmethoden der HTTP-Spezifikation zuständig sind (GET und POST). In einer XML-Datei werden Metainformationen über das Servlet hinterlegt. Diese XML-Datei wird zusammen mit der kompilierten Klasse (sowie ggf. weiteren benötigten Klassen) in eine einzige Archiv-Datei zusammengeführt (sogenanntes Web-Archiv), dieses wiederum wird dem Webcontainer über eine von ihm bereitgestellte Funktionalität zur Verfügung gestellt (sog. Deployment).


Servlet Programmierung[Bearbeiten]

Ein Servlet ist einfach betrachtet eine Javaklasse. Mit dem Unterschied, dass die Klasse zu keinem Programm gehört, das auf dem lokalem Rechner läuft, sondern zu einer Webanwendung, die auf einem Webserver läuft. Während gewöhnliche Javaprogramme mit Hilfe des Ausgabestroms Textnachrichten in eine Konsole schreiben können, kann ein Servlet eine Webseite mit dem Ausgabestrom dynamisch generieren. Die Grundstruktur eines Servlets ist recht einfach. Die Klasse ist von HttpServlet abgeleitet und implementiert das Interface Servlet. Beide aus dem Paket javax.servlet.[http]

public class ServletName 
       extends javax.servlet.http.HttpServlet 
       implements javax.servlet.Servlet {}

Damit ist die Servletklasse aber noch unvollständig. Der Webserver (Servletcontainer oder Application Server) benötigt eine Art Einsprungpunkt für die Servletklasse so ähnlich wie es bei einem J2SE Javaprogramm es eine public static void main(String[] argv) geben muss. Ein Servlet hat genau betrachtet zwei solcher Startmethoden plus dem normalen Konstruktor, den ja jede Javaklasse hat. Für gewöhnlich nimmt man beim Konstruktor einige Initialisierungen auf. Dafür gibt es bei Servlet aber die Methode init.

public void init() throws ServletException {
     //Initialisierungen
      String p = getInitParameter("initpara1");
} 

Dies ist jedoch erst seit Version 2.1 der Servlet-API möglich. Zuvor musste man, um z.B. auf den ServletContext zuzugreifen oder Initialisierungswerte aus der web.xml aufzurufen, die init Methode mit der ServletConfig benutzen. Man beachte den Aufruf von super.init(conf).

public void init(ServletConfig conf) throws ServletException {
     super.init(conf);
     //Initialisierungen
     /* Nutzung der Config...
      String p = conf.getInitParameter("initpara1");
      String i = conf.getServletContext().getServerInfo();
      */
} 

Wird ein Servlet direkt auf dem Server ausgeführt und nicht etwa von einem Webformular aufgerufen, wird nach der init, die doGet Methode des Servlets ausgeführt.

protected void doGet(
               HttpServletRequest request, 
               HttpServletResponse response) 
                    throws ServletException, IOException {
       out = response.getWriter();
       out.println("Hallo Welt");
}

Des Weiteren stehen eine Reihe weitere Methoden zur Verfügung:


Methode Beschreibung
destroy Wird automatisch aufgerufen, wenn der Server das Servlet aus dem Speicher entfernt. Hier können Initialisierungen aus der init rückgängig gemacht werden oder sonstige finale Operationen ausgeführt werden.
doGet wenn ein GET Request bearbeitet wird
doPost wenn ein POST Request bearbeitet wird
doDelete wenn ein DELETE Request bearbeitet wird
doPut wenn ein PUT Request bearbeitet wird
getServletInfo Kann überschrieben werden um individuelle Informationen über das Servlet "von aussen" abzufragen.

Hier noch ein Beispiel wie ein Servlet benutzt werden kann um dynamische HTML Seiten zu erzeugen:

protected void doGet(
     HttpServletRequest request,
     HttpServletResponse response)
        throws ServletException, IOException {
PrintWriter out = response.getWriter(); out.println("<table border=\"1\">"); out.println("<tr><td><b>x<b></td><td>f(x)=sin(x)+cos(x)+x^2</td></tr>"); //out.println("<colgroup> <col width=\"30px\"> <col width=\"*\"></colgroup>"); double y; for(int x=0;x<10;x++){ if((x % 2)==0) out.println("<tr bgcolor=#ffff00>"); else out.println("<tr bgcolor=#00ffff>"); y=Math.sin(x)+Math.cos(x)+Math.pow(x,2); out.println("<td>"+x+"</td><td>"+y+"</td></tr>"); } out.println("</table>"); }

Die doGet Methode erzeugt eine Wertetabelle für eine mathematische Funktion, wobei jede Tabellenzeile abwechselnd eine andere Farbe bekommt. Das Ergebnis nach der Ausführung auf dem Server sollte so aussehen:

xf(x)=sin(x)+cos(x)+x^2
01.0
12.381773290676036
24.493150590278539
38.151127511459421
414.58955388382846
524.32473791080009
636.68075478845144
750.41088885306209
864.84385821281477
980.50098822335708

Verarbeitung von Webformularen[Bearbeiten]

Häufig werden Servlets eingesetzt um die Daten aus Eingabeformularen in Webseiten zu verarbeiten. Beispielsweise für ein Login:

<form method="post" action="/ServletName" name="formular">
  <table border="0">
    <tbody>
      <tr>
        <td>Name</td>
        <td><input name="txtName"></td>
      </tr>
      <tr>
        <td>Passwort</td>
        <td><input name="txtPass" type="password"></td>
      </tr>
    </tbody>
  </table>
  <input name="btnSenden" value="Weiter" type="submit"><br>
 </form>
 

Wichtig für das spätere Servlet sind folgende Komponenten:

  • method="post"

Das ist die Art mit der die Daten an das Servlet geschickt werden. Am gebräuchlichsten sind POST und GET.

  • action="/ServletName"

Bei action steht der Name des Skriptes/Servlets an das die Formulardaten geschickt werden und welches auf dem Server ausgeführt wird.

  • input name="txtName"

Das Eingabefeld für den Benutzernamen.

  • input name="txtPass"

Das Eingabefeld für das Password.

Für das Servlet sind die Namen txtName und txtPass relevant.

Das LoginServlet[Bearbeiten]

Man legt nun also eine neue Servletklasse an. Diese muss den Namen haben, der in dem Webformular bei action angegeben ist.


import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ServletName extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } }

Im HTML-Formular wurde die Methode POST ausgewählt, daher reicht es die Methode doPost zu implementieren, aber häufig werden die Servlets nicht von der selben Person erstellt, wie die HTML Seiten, die sie benutzen. Daher kann man als Servletprogrammierer auch nie genau wissen, ob nun POST oder GET benutzt wurde. Aus diesem Grund hat es sich durchgsetzt, beide Methoden zu implementieren, wobei eine die andere nur aufruft. Das sieht dann so aus:

       protected void doGet(HttpServletRequest request, HttpServletResponse response) 
          throws ServletException, IOException {
          
doPost(request,response); }

In der doPost Methode findet nun die Datenverarbeitung statt. Man kann z.B. den Nutzer samt Passwort aus einer gespeicherten Datei oder Datenbank lesen und überprüfen. In diesem Beispiel sollen Name und Passwort im Programmtext hinterlegt sein. Dafür reichen also zwei einfache Arrtibute:

private String Benutzername = "root";
private String Benutzerpasswort = "foobar";

Im Servlet greifen wir nun über die getParameter(String pName) Methode des HttpServletRequest - Objektes auf die Daten vom Formular zu.

String loginName = request.getParameter("txtName");
String loginPass = request.getParameter("txtPass");

Man beachte, dass hier die Namen der Formularelemente als Parameternamen eingesetzt werden. Für gewöhnlich überprüft man jetzt noch, ob die Parameter auch tatsächlich verfügbar waren. Denn ein Aufruf von getParamter() mit unbekanntem Parameternamen wirft keine Exception.

if ((loginName==null) || (loginPass==null)){
   response.sendError(HttpServletResponse.SC_BAD_REQUEST);
   return;
}

Hier werden die beiden Stringobjekte geprüft, ob sie null sind. Wenn dem so ist, wird eine Fehlermeldung ausgegeben und die doPost Methode (und damit das ganze Servlet) beendet.

Wenn das lesen der Parameter geglückt ist, können diese jetzt auf Gültigkeit geprüft werden. In diesem einfachen Beispiel also nur ob sie mit den intern gespeicherten Zeichenketten identisch sind.

if ((loginName.equals(Benutzername) && (loginPass.equals(Benutzerpasswort))))
    response.getWriter().println("Anmeldung erfolgreich");
else
    response.getWriter().println("Benutzername oder Passwort falsch.");

Mit hilfe von response.getWriter() bekommt man eine Instanz auf einen Ausgabestrom für die zu generierende HTML Seite, dessen wichtigster Zweck ein Servlet ja ist. Die Benutzung ist nahezu identisch mit der Standardkonsolenausgabe System.out.

Das komplette Servlet sieht nun wie folgend aus:

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ServletName extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
private String Benutzername = "root"; private String Benutzerpasswort = "foobar";
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request,response); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String loginName = request.getParameter("txtName"); String loginPass = request.getParameter("txtPass");
if ((loginName==null) || (loginPass==null)){ response.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } if ((loginName.equals(Benutzername) && (loginPass.equals(Benutzerpasswort)))) response.getWriter().println("Anmeldung erfolgreich"); else response.getWriter().println("Benutzername oder Passwort falsch."); } }

Weblinks[Bearbeiten]