Servlets und Java Server Pages (JSP)

Werbung
FH Fulda
FB AI
Prof. Dr. U. Schröter
Servlets und Java Server Pages (JSP)
(Quelle: java Magazin 5/2000)
Servlets
Servlets sind zum Java Servlet-API konforme Java-Objekte, d. h. spezielle, serverseitig
ausführbare Java-Klassen. Grundsätzlich lassen sich Servlets für Aufgaben der dynamischen
Generierung von HTML-Seiten einsetzen. Servlets haben kein grafisches Benutzerinterface.
Die Java Servlet-API definiert mit Schnittstellen Eigenschaften und Methoden, die ein
Servlet zur Verfügung stellen muss. Servlets können vom Server dynamisch über ein
Netzwerk geladen werden.
Pakete:
 javax.servlet  allgemeine Klassen und Schnittstellen zur Unterstützung protokollunabhängiger Servlets,
 javax.servlet.http  von javax.servlet abgeleitete Klassen und Interfaccs mit spezieller
http-Funktionalität.
Die Klasse javax.servlet.http.HttpServlet stellt die Ausgangsbasis für eigene, http-spezifische
Servlets zur Verfügung.
Anders als bei CGI-Anwendungen läuft ein Servlet nicht in einem separaten Prozess, sondern
in einem Thread innerhalb der Java Virtual Machine des Serverprozesses ab.
Initialisierung von Servlets
Nach dem Starten wartet der Server auf Anfragen der Clients. Zielt ein Request auf ein noch
nicht geladenes Servlet, wird das Servlet geladen und genau eine Instanz erzeugt.
Anschließend ruft die Servlet-Engine die init()-Metbode des Servlets auf, wobei laut APISpezifikation garantiert wird, dass diese Methode, vor der Weitergabe einer Abfrage, genau
einmal vollständig ausgeführt wird. Beim Aufruf der Initialisierungsmethode wird dem
Servlet als Argument eine Objekt-Referenz des Typs javax.servlet.ServletConfig übergeben.
Diese Schnittstelle ServletConfig ermöglicht dem Servlet einen Zugriff auf seine
Ausführungsumgebung, d. h. den Zugriff auf die Initialisierungsparameter sowie die
Bereitstellung eines ServletContext-Objektes.
Verarbeitung
Jeder Request führt zu einem Aufruf der Methode service (ServletRequest, ServletResponse).
Dabei wird dem Servlet jeweils ein Objekt vom Typ javax.servlet.ServletRequest und
javax.servlet.ServletResponse übergeben. Die in diesen Schnittstellen definierten Methoden
entsprechen im Wesentlichen den CGI-Umgebungsvariablen.
Am wichtigsten für das Arbeiten mit Servlets sind die im Interface ServletResponse definierten Methoden getOutputStream() und getWriter(), zum Übertragen von binären Daten
bzw. zur Übertragung von Zeichenketten an den aufrufenden Client.
Freigabe
1
Eine Servlet-Engine kann durch den Aufruf der Methode destroy() das Servlet wieder aus
dem Speicher entfernen, wodurch nicht mehr benötigte Ressourcen wieder freigeben werden.
Sessions
Das HTTP-Protokoll ist zustandslos. Dies ist problematisch, wenn aber eine Anwendung
realisiert werden soll, für die es notwendig ist, benutzerspezifische Informationen über eine
zusammenhängende Folge von Anfragen und Antworten aufzuheben. Ein Beispiel ist ein
Online-Shop-System, in dem Einkaufs- und Zahlungsinformationen eines Benutzers in einem
geschlossenen Ablauf hinweg im System gehalten werden müssen. Zur Unterstützung dieser
Benutzerverwaltung stellt die Servlet-API das Interface HttpSession aus dem Paket
java.servlet.http zur Verfügung. Sie realisiert das Konzept des Session Tracking.
HttpSession stellt alle notwendigen Methoden bereit, um eine Session zu erzeugen, ihre
Gültigkeit festzustellen oder wieder zu löschen. Einer Session können Objekte zugeordnet
werden. Zu diesem Zweck verfügt HttpSession über die Methoden putvalue(String name,
Objectvalue) zum Hinzufügen, Object getValue(String
name) zum Lesen und
removeValue(String name) zum Löschen eines Session-Objektes. Zudem kann mit String[]
getvalueNames() festgestellt werden, welche Objektnamen verwendet werden.
Intern arbeiten Webserver zur Realisierung des Session-Trackings meist mit Cookies oder
URLRewriting. Beide Verfahren werden von der Servlet-API unterstützt. Beim URL
Rewriting werden die in einer HTML-Seite enthaltenen URLs so verändert, dass sie eine für
den Server eindeutige Identifikationsnummer, die Session-ID, enthalten. Der Vorteil dieses
Verfahrens ist die Unterstützung von Browsern die keine Cookies kennen, bzw. keine
Cookies akzeptieren.
Parallele Client-Anforderungen
Mehrere gleichzeitig eintreffende Anfragen an ein Servlet führen zu einer parallelen
Ausführung der service()-Methode desselben Servlets, so kann es bei gemeinsamen
Ressourcen zu Konflikten kommen. Java stellt verschiedene Möglichkeiten zur
Gewährleistung der Thread-Sicherheit zur Verfügung, die hier genutzt werden müssen.
Zur Synchronisation paralleler Prozesse ist in Java das Konzept des Monitors
implementiert. Ein Monitor ist die Kapselung eines kritischen Bereichs, mit Hilfe einer
automatisch verwalteten Sperre. Diese Sperre wird beim Betreten des Monitors gesetzt und
beim Verlassen wieder zurückgenommen. Ist beim Eintritt bereits eine Sperre gesetzt, so
muss gewartet werden, bis der Konkurrent die Sperre freigegeben und den Monitor verlassen
hat. Das Monitor-Konzept wird durch das Voranstellen des Schlüsselworts synchronized
realisiert. So besteht die Möglichkeit, entweder die komplette Methode oder einen Block
innerhalb einer Methode zu schützen. Schreibende Zugriffe auf gemeinsame Ressourcen
müssen synchronisiert werden.
Alternativen
Microsoft stellt mit den Active Server Pages (ASP) eine Kombination von HTML-Seiten
mit integriertem Source-Code zur Verfügung. Der Zugriff auf Objekte außerhalb der ASP
erfolgt dann mit den proprietären Techniken von Microsoft wie ODBC, COM, DCOM, OLE
etc.. Damit lassen sich das Layout in den ASP-Vorlagen und der Sourcecode in den externen
Objekten voneinander trennen.
2
Ähnlich geht es mit PHP, einem Hypertext-Preprozessor. Dabei werden Vorlagendateien
*.php durch eine Webserver-Erweiterung interpretiert und dann ,,reines" HTML an den
Client gesandt.
Etwas standardisierter im Rahmen von HTML sind Server Side Indudes (SSI). Auch diese
können direkt innerhalb von HTML-Dateien dynamische Information, z.B. Datum und
Uhrzeit, einbinden. Sie können auch CGI-Programme starten und deren Ausgaben in die
HTML-Datei einbetten. Server Side Includes werden auch serverseitig ausgewertet und
natürlich nur dann, wenn der Webserver diese SSIs auch unterstützt. Damit ein Web-Server
auch erkennt, dass eine HTML-Datei Server-Side-Include-Anweisungen enthält, bekommen
die dazugehörigen Vorlagendateien meist die spezielle Dateinamenendung .shtml, .shtm oder
.sht.
Java Server Pages
Während ASP integraler Bestandteil der Microsoft Plattform ist und somit als konkrete
Implementierung für Webserver als Erweiterungskomponente zur Verfügung steht, hat Sun
mit der Spezifikation der JavaServerPages primär eine plattform-übergreifende Lösung zur
dynamischen Erzeugung von Websites definiert. Das Paket javax.servlet.jsp enthält die
Basisfunktionalität zur Trennung des Content-Managements von der Präsentation, der
Grundidee der Java Server Pages.
Innerhalb einer JavaServerPage werden dynamische Inhalte mittels spezieller JSP-Elemente
hinzugefügt, während die Formatierung der Seite durch HTML beschrieben wird. Durch
Nutzung der Java Komponenten-Technologie (JavaBeans bzw. Enterprise JavaBeans) können
große Teile bereits bestehender Java Komponenten mit JSP-Tags eingebunden werden. Das
erlaubt eine weitestgehende Trennung der Entwicklung des Designs von der Entwicklung der
Applikationslogik.
Generell können Java Server Pages alle Features von Java nutzen, sie haben den vollen
Zugriff auf alle Java-APIs. Damit aber eine Trennung von Layout und Code tatsächlich
stattfindet, sollten JSP-Seiten auf Java nur über definierte Schnittstellen oder Beans
zugreifen. Der Designer kann die JSP-Seite schreiben und der Java-Programmierer stellt die
Beans und anderen Java Sourcecode zur Verfügung. Vorteil dieser Vorgehensweise ist eine
bessere Wartbarkeit sowie mehr Transparenz.
Komponenten von JSP´s
Mit Hilfe von Direktiven übergibt eine JSP-Seite Informationen an die ausführende JSPEngine. Aktionen dienen der Manipulation des Ausgabestroms, d.h. sie geben dynamische
Inhalte aus, wie z.B. den Inhalt einer Variablen oder den Wert eines beliebigen Ausdrucks.
Weiterhin sind sie in der Lage, auf beliebige Objekte zuzugreifen, demzufolge kann durch
Aktionen die Funktionalität einer Java Server Page erweitert werden. Dabei gibt es eine
Reihe von Standardaktionen, die von allen Engines, die der JSP-Spezifikation entsprechen,
unterstützt werden müssen.
Während mit Deklarationen die Definition von Variablen und Methoden erfolgt, kann an
beliebiger Stelle mit der % % - Markierung ein Script eingebunden werden. Diese beinhalten
3
Java Code. Durch das Hinzufügen entsprechender Import - Statements kann das gesamte Java
- API innerhalb dieser Segmente genutzt werden. Wichtige Objekte, wie z.B. out für die
Ausgabe oder response bzw. request für die Anfrage bzw. Antwort, werden jeder Java Server
Page beim Aufruf zur Verfügung gestellt.
Ausführung einer JSP
Die Verarbeitung einer JSP-Seite wird von einem JSP-fähigen Webserver durch eine JSPEngine übernommen. Eine JSP Engine ist meist als Servlet implementiert. Mit Hilfe eines
Aliases innerhalb des Webservers wird jede Client-Anfrage, die sich auf eine JSP-Seite
bezieht, auf die JSP-Engine umgeleitet.
Die als Servlet implementierte JSP-Engine öffnet die angeforderte Java Server Page und
überprüft deren Syntax. Ist alles in Ordnung, erfolgt die Generierung einer ,,.java" Quelldatei, die dann mit Hilfe eines vorab konfigurierten Compilers in eine ,,.class"-Datei
übersetzt wird. Das so entstandene Servlet wird dann von der Servlet-Engine geladen, um die
ursprüngliche Client-Anfrage zu bearbeiten.
Das Ergebnis ist somit ein aus der JSP - Seite zur Laufzeit erzeugtes Servlet, das dynamisch
von der Servlet - Engine geladen wird. Die Erstellung des Servlets erfolgt nur beim ersten
Aufruf der JSP - Seite. Es tritt daher eine Verzögerung bei der ersten Bearbeitung einer
Anfrage, aufgrund des zur Erzeugung des Servlets benötigten Aufwands, ein. Jeder weitere
Aufruf wendet sich dann über die JSP - Engine an das bereits geladene Servlet.
Vor- und Nachteile
Bei den Servlets sind die Möglichkeiten für Programmierer wesentlich besser, da hier ein
richtiges Java-Programm geschrieben wird, mit der gewohnten Unterstützung durch
Entwicklungsumgebungen. Auch die Performance ist in den meisten Fällen besser als bei
JSP. Der einzige Nachteil ist die Tatsache, dass alles von Hand zusammengebastelt werden
muss, was die zu generierende HTML-Seite betrifft.
JSP ist bei komplexeren HTML-Seiten mit wenigen dynamischen Inhalten im Vorteil, da hier
die Seiten zuerst mit einem ganz normalen Designtool für Webseiten erstellt werden können
und hinterher die Java-Fragmente einfach von Hand eingetragen werden. Nachteile sind die
schon erwähnte längere Dauer beim ersten Aufruf einer JSP und, bei verstärktem Einsatz von
JSP, die zusätzliche Parsearbeit des Webservers.
***
Beispiel Servlet
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
4
public final class Hello extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println("<html>");
writer.println("<head>");
writer.println("<title>Sample Application Servlet Page</title>");
writer.println("</head>");
writer.println("<body bgcolor=white>");
writer.println("<table border=\"0\">");
writer.println("<tr>");
writer.println("<td>");
writer.println("<img src=\"images/tomcat.gif\">");
writer.println("</td>");
writer.println("<td>");
writer.println("<h1>Sample Application Servlet</h1>");
writer.println("This is the output of a servlet that is part of");
writer.println("the Hello, World application. It displays the");
writer.println("request headers from the request we are currently");
writer.println("processing.");
writer.println("</td>");
writer.println("</tr>");
writer.println("</table>");
writer.println("<table border=\"0\" width=\"100%\">");
Enumeration names = request.getHeaderNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
writer.println("<tr>");
writer.println(" <th align=\"right\">" + name + ":</th>");
writer.println(" <td>" + request.getHeader(name) + "</td>");
writer.println("</tr>");
}
writer.println("</table>");
writer.println("</body>");
writer.println("</html>");
}
}
Beispiel JSP
<html>
<head>
<title>Sample Application JSP Page</title>
</head>
<body bgcolor=white>
<table border="0">
5
<tr>
<td align=center>
<img src="images/tomcat.gif">
</td>
<td>
<h1>Sample Application JSP Page</h1>
Beispiel - Applikation aus Tomcat
</td>
</tr>
</table>
<table border="0" border="100%">
<tr>
<th align="right">Context Path:</th>
<td align="left"><%= request.getContextPath() %></td>
</tr>
<tr>
<th align="right">Path Information:</th>
<td align="left"><%= request.getPathInfo() %></td>
</tr>
<tr>
<th align="right">Query String:</th>
<td align="left"><%= request.getQueryString() %></td>
</tr>
<tr>
<th align="right">Request Method:</th>
<td align="left"><%= request.getMethod() %></td>
</tr>
<tr>
<th align="right">Servlet Path:</th>
<td align="left"><%= request.getServletPath() %></td>
</tr>
</table>
</body>
</html>
Datenbankzugriff mit JSP (gesamte DB)
<HTML>
<HEAD>
<%@ page language="java" import="java.sql.*" %>
<%
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = DriverManager.getConnection("jdbc:odbc:PARASERV");
Statement stm = con.createStatement();
ResultSet rs = stm.executeQuery("select * from adress");
%>
<TITLE>
AListe
</TITLE>
</HEAD>
<BODY BGCOLOR="#99FFCC">
<H3><U>Adressliste als JSP</U></H3>
<TABLE BORDER="1" WIDTH="80%" BGCOLOR="silver">
<TR>
6
<TD WIDTH="16%"><P ALIGN="CENTER"><B>Name</B></TD>
<TD WIDTH="16%"><P ALIGN="CENTER"><B>Vorname</B></TD>
<TD WIDTH="16%"><P ALIGN="CENTER"><B>Strasse</B></TD>
<TD WIDTH="16%"><P ALIGN="CENTER"><B>Postleitzahl</B></TD>
<TD WIDTH="16%"><P ALIGN="CENTER"><B>Ort</B></TD>
<TD WIDTH="20%"><P ALIGN="CENTER"><B>Telefon</B></TD>
</TR>
<% rs.next(); %>
<TR>
<TD WIDTH="16%"> <%= rs.getString("Name")%></TD>
<TD WIDTH="16%"> <%= rs.getString("VName")%></TD>
<TD WIDTH="16%"> <%= rs.getString("Strasse")%></TD>
<TD WIDTH="16%"> <%= rs.getString("PLZ")%></TD>
<TD WIDTH="16%"> <%= rs.getString("Ort")%></TD>
<TD WIDTH="20%"> <%= rs.getString("Telefon")%></TD>
</TR>
<% while(rs.next()){ %>
<TR>
<TD WIDTH="16%"> <%= rs.getString("Name")%></TD>
<TD WIDTH="16%"> <%= rs.getString("VName")%></TD>
<TD WIDTH="16%"> <%= rs.getString("Strasse")%></TD>
<TD WIDTH="16%"> <%= rs.getString("PLZ")%></TD>
<TD WIDTH="16%"> <%= rs.getString("Ort")%></TD>
<TD WIDTH="20%"> <%= rs.getString("Telefon")%></TD>
</TR>
<% }
con.close();
}
catch(Exception ex){
ex.printStackTrace();
} %>
</TABLE>
<FORM><br><input type=button onClick="history.back()" value="zurück"></FORM>
</BODY>
</HTML>
Datenbankzugriff mit JSP (einzelne Sätze)
<HTML>
<HEAD>
<%@ page language="java" import="java.sql.*" %>
<%
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = DriverManager.getConnection("jdbc:odbc:PARASERV");
Statement stm = con.createStatement();
ResultSet rs = stm.executeQuery("select NAME, VNAME from adress");
rs.next();
%>
<TITLE>
AListe
</TITLE>
</HEAD>
<BODY BGCOLOR="#99FFCC">
<FORM action=http://localhost:8080/servlet/adrserv.AUpdel method=POST>
<H3><U>Einzel-Adresse als JSP</U></H3>
<P>Name :<SELECT NAME="Selection">
<OPTION><%= rs.getString("Name") %>,<%= rs.getString("VName") %></OPTION>
7
<%
while(rs.next()){
%>
<OPTION><%= rs.getString("Name") %>,<%= rs.getString("VName") %></OPTION>
<%
}
con.close();
}
catch(Exception ex){
ex.printStackTrace();
}
%>
</SELECT></P><BR>
<INPUT TYPE=CHECKBOX NAME="Delete" VALUE="Entfernen">Entfernen
<P><INPUT TYPE="SUBMIT" NAME="Submit" VALUE="Submit"><INPUT TYPE="RESET"
NAME="Reset" VALUE="Reset">
</FORM>
</BODY>
</HTML>
Datenbankzugriff mit Servlet (ganze Tabelle)
package adrserv;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import java.sql.*;
public class AListe extends HttpServlet {
//Globale Variablen initialisieren
HtmlTable htab = null;
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
//Die HTTP-Anforderung Get bearbeiten
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = new PrintWriter (response.getOutputStream());
out.println("<html>");
out.println("<head><title>Adressliste</title></head>");
out.println("<body BGCOLOR=\"#99FFCC\">");
out.println("<H3><U>Adressliste</U></H3>");
Connection con = null;
Statement stm = null;
ResultSet rs = null;
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
con = DriverManager.getConnection("jdbc:odbc:PARASERV");
stm = con.createStatement();
rs = stm.executeQuery("select * from adress");
htab = new HtmlTable(out,rs); //html-Tabelle generieren lassen
htab.doTable(true);
8
rs.close();
stm.close();
con.close();
}
catch(Exception ex){}
out.println("<FORM><br><input type=button onClick=\"history.back()\" value=
\"zurück\"></FORM>");
out.println("</body></html>");
out.close();
}
//Servlet-Information holen
public String getServletInfo() {
return "adrserv.AListe Information";
}
}
HTMLTable
package adrserv;
import java.io.*;
import java.sql.*;
public class HtmlTable {
PrintWriter pout = null;
ResultSet rset = null;
ResultSetMetaData rsmd = null;
public HtmlTable() {
}
public HtmlTable(PrintWriter out,ResultSet rs){
pout = out;
rset = rs;
}
public void startTable(boolean mitRand){
if(mitRand)
pout.println("<table border>");
else
pout.println("<table>");
}
public void endTable(){
pout.println("</table>");
}
public void startRow(){
pout.print("<tr>");
}
public void endRow(){
pout.println("</tr>");
}
public void doTitelCell(String data){
9
pout.print("<th>" + data + "</th>");
}
public void doCell(String data){
pout.print("<td>" + data + "</td>");
}
public void doRow(String[] data, boolean titel){
startRow();
for(int i = 0;i < data.length;i++){
if(titel)
doTitelCell(data[i]);
else
doCell(data[i]);
}
endRow();
}
public void doTable(boolean mitRand){
//datenbanktabelle als html-tabelle
int feldZahl=0;
try{
rsmd = rset.getMetaData();
feldZahl = rsmd.getColumnCount();
}
catch(Exception ex){ex.printStackTrace();}
String[] colBuff = new String[feldZahl];
startTable(mitRand);
try{
rset.next();
//feldnamen -> titelzeile
for(int i = 1;i<=feldZahl;i++)
colBuff[i-1] = rsmd.getColumnName(i);
doRow(colBuff,true);
//tabellendaten holen -> html-tabelle
do{
for(int col = 0;col < feldZahl;col++){
colBuff[col] = rset.getString(col+1);
}
doRow(colBuff,false);
}while(rset.next());
}
catch(Exception ex){ex.printStackTrace();}
endTable();
}
}
10
Herunterladen