<jsptutorial />

Die Syntax von JSPs


Einführung

Die reine Syntax der JavaServer Pages selbst ist vergleichsweise einfach. Es gibt nur wenige spezielle Tags, Direktiven und Bereiche, die JSP-typisch sind. Die Mächtigkeit der Technologie liegt weniger in der JSP-eigenen Syntax als vielmehr in dem gesamten Entwicklungsmodell und natürlich in der Mächtigkeit der Sprache Java, die in JSPs als Code eingebettet werden kann bzw. von Java-Komponenten, die aus JSPs heraus genutzt werden können.
Die einfache Möglichkeit, beliebigen Java-Code in den JSPs zu verwenden, verleitet gerade am Anfang dazu, dies intensiv zu nutzen. In der Tat kommt man so sehr schnell zu ersten Erfolgserlebnissen. Aber man erzeugt damit leider auch Code, der zum einen schwer lesbar ist und zum anderen die gewünschte Trennung von Präsentation und Logik aufhebt. Beides führt schon bei kleineren Projekten schnell zu Problemen. Doch JSPs und J2EE wäre nicht zu dem Entwicklungsmodell gerade auch für große Projekte geworden, hätten SUN und andere an den Spezifikationen beteiligten Firmen nicht Lösungen gefunden, die gerade dies verhindern und die letztlich den Erfolg von JSP begründen. Darauf wird in den späteren Beiträgen ausführlich eingegangen.
Zunächst sollen i.F. die Grundlagen von JSP 1.2 dargelegt werden.Und dies sind zunächst einmal (auch historisch) das Skripting innerhalb der JSPs, bevor wir daran anschließend Kommentare in JSPs, die JSP-Direktiven und die Maskierung besonderer Zeichen behandeln.1

Zum SeitenanfangZum Seitenanfang

Skripting

Expressions


Die einfachste und vermutlich auch verbreiteste Form des Skriptings sind die Ausdrücke (Expressions). Will man bspw. einen String an einer bestimmten Stelle im HTML-Code ausgeben, so verwendet man einen entsprechenden Ausdruck. Ein Beispiel haben wir schon in der Einleitung kennen gelernt, als der User-Agent mit folgendem Code ausgegeben wurde:

<%= request.getHeader("User-Agent") %>

Wichtig ist das Gleichheitszeichen, das den folgenden Code als Ausdruck auszeichnet. Zwischen dem öffnenden "<%=" und dem schliessenden "%>" darf genau ein Ausdruck stehen. Dabei ist zu beachten, dass das sonst bei Java übliche Semikolon am Ende eines Statements entfällt. Als Ausdruck wird hier alles das verstanden, was einen primitiven Wert oder ein Objekt zurück gibt.
Gültige Ausdrücke wären somit bspw.

<%= someBean.getIntValue() %>
<%= request.getParameter("username") %>

Dieser Tag wird häufig verwendet, um bspw. Formular-Werte vorzubesetzen und ähnliches, auch wenn es meist elegantere Lösungen gibt (dazu im weiteren Verlauf des Tutorials mehr). In allen JSP-Versionen vor der Version 2.0 ist man mitunter sogar gezwungen Expressions zu benutzen. Will man bspw. dynamische Werte an Taglib-Tags übergeben, so muss man dafür innerhalb des Tags Expressions verwenden. Dies wird sich mit der Einführung der klareren Expression Language in JSP 2.0 ändern und die derzeit noch recht hohe Bedeutung der heutigen Expressions dürfte dann deutlich zurückgehen (s. dazu das Kapitel Expression Language).

Skriptlets


Skriplets können jedweden beliebigen Java-Code enthalten, vorausgesetzt die verwendeten Bibliotheken liegen im Classpath der Web-Anwendung und die benötigten Packages wurden importiert (s. dazu den Abschnitt zu den Direktiven in diesem Kapitel).
Diese Tatsache, dass man hier Zugriff auf die ganze Welt der Java-Programmierung hat, hat einerseits dazu geführt, dass sich JSPs schnell verbreiten konnten. Mehr noch hat dies jedoch dazu beigetragen, dass vor allem in der Anfangszeit der JSPs Skriptlets übermässig genutzt wurden und so Seiten entstanden, deren Source-Code nur schwer lesbar war, da er aus einem beständigen Mix von HTML- und Java-Code bestand. Entsprechend waren diese JSPs und die dort verwendeten Java-Code-Schnipsel schwer wartbar und nahezu gar nicht wiederverwendbar. Deswegen möchten wir, noch bevor wir die Syntax erklären, ausdrücklich davor warnen, Skriplets zu verwenden. Es gibt weitaus bessere Alternativen, auf die in diesem Tutorial noch eingegangen werden wird. Lediglich bei kleinen Projekten kann man Skriptlets verwenden, doch dürfte Java bei derartigen Projekten (derzeit) ohnehin eher eine untergeordnete Rolle spielen - und zudem haben selbst diese Projekte die Angewohnheit, im Laufe der Zeit dann doch zu wachsen...
Kommen wir nun zur Syntax. Diese ähnelt den Expressions, nur dass das Gleichheitszeichen entfällt. Ein kleines Beispiel:
<html>
<head><title>Why, doesn't this look ugly?</title></head>
<body style="font-family:sans-serif;padding-top:15px;">
<h3>
<%
   String[] valueArray = {"This", "is", "a", "rather", "dull", "example"};
   int i;
   for (i = 0; i < valueArray.length; i++) {
%>
      <%= valueArray[i] %> 
<%
   }
%>   
   </h3>
   
   <p style="padding-top:10px;">Or put another way: 
<%
   for (i = 0; i < valueArray.length; i++) {
%>
      <p>valueArray[<%=i%>]: "<%= valueArray[i] %>"<br>
<%
   }
%>
</body>
</html>

Dieses simple Beispiel2 deutet einerseits an, wie mächtig Skriplets werden können. Aber schon hier, in diesem kleinen Beispiel, wird deutlich, wie schnell JSP-Seiten durch den Einsatz von Skriptlets unlesbar werden können. Die Lösung lautet hier, auf Beans und auf Taglibs zurückzugreifen. Dies wird in den späteren Kapiteln ausführlich dargelegt werden (in den Kapiteln Tag-Libraries und Beans in JSPs).
Dennoch ist das Verständnis der Skriptlets wichtig, da man vor allem bei der Wartung älterer Projekte diese häufig vorfindet. Und wer einmal so ein Alt-Projekt gewartet hat, wird verstehen, warum wir unsere Warnungen hier so wiederholt und vehement vortragen ;-)

Deklarationen


Das letzte Skripting-Element dient zur Deklaration von Instanz-Variablen3 und zur Definition von Methoden und nimmt die Form <%! ... %> an.
So kann man bspw. einen Counter wie folgt definieren:

<%! int objectCounter = 0; %>

Das abschliessende Semikolon ist hierbei wichtig.
Der Unterschied zwischen Variablen-Deklarationen mittels des Deklarations-Tags und solcher, die in Scriplets vorgenommen werden, ist der, dass in Scriplets die Variablen nur lokal definiert werden, also innerhalb der Methode "_jspservice" des aus den JSPs generierten Servlets (s. das Kapitel zum Lebenszyklus einer JSP). Hingegen sind in Deklarations-Tags deklarierte Variablen Attribute des Objekts und stehen somit in allen Methoden zur Verfügung. Dies hat insbesondere auch Auswirkungen auf die Thread-Sicherheit der Variablen. Es existiert in aller Regel genau ein Objekt eines Servlets pro Container (zu den Feinheiten kommen wir in anderen Kapiteln des Tutorials) auf das aus mehreren Threads heraus zugegriffen wird. Somit sind die Instanz-Variablen durchweg nicht threadsicher!
Neben Variablen können zudem auch ganze Methoden mit dem Deklarations-Tag definiert werden:
<%!
public boolean isInRange(int var) {
   if (var < 0 || var > 65535) {
      return false;
   }
   return true;
}
%>

Der Deklarations-Tag ist sicherlich der am wenigstens verwendete JSP-Tag. Methoden sollten z.B. möglichst gar nicht in JSPs deklariert werden, da die aus den JSPs generierten Servlets keinen Namen haben, der unabhängig vom Servlet-Container wäre. Somit ist ein Zugriff aus anderen JSPs oder Java-Klassen unmöglich, das obige Beispiel somit nur syntaktisch "public", in Wirklichkeit jedoch de facto "private". Zudem ist es sehr unwahrscheinlich, dass eine Methode wirklich nur in einer einzigen JSP verwendet wird. Wird sie aber mehrfach benötigt, so macht ihre Auslagerung in eine spezielle Hilfsklasse mehr Sinn.
Es gibt eine Ausnahme von dieser Regel und das sind die Lifecycle-Methoden der JSPs. Will man diese überschreiben, so muss man dies innerhalb von Deklarations-Tags machen.

Zum SeitenanfangZum Seitenanfang

Kommentare

Will man in JSPs einen Kommentar einfügen, so macht man dies wie folgt:

<%-- myComment --%>

In dem Beispiel zu den Deklarationen haben wir diese Kommentare schon verwendet.
JSP-Kommentare können auch mehrzeilig sein und sie kommentieren alles aus, solange kein passendes JSP-Kommentar-Ende kommt. Also auch Skriptlets können so auskommentiert werden. JSP-Kommentare sind natürlich im generierten HTML-Code nicht mehr sichtbar.
Will man Kommentare sichtbar machen, so können die üblichen HTML-Kommentare verwandt werden:

<!-- mein Kommentar -->

Diese sind ganz gewöhnliches HTML und als solches natürlich auch ggf. dynamisch erstellbar, falls dies angebracht erscheint.
Innerhalb der Skriptlets sind selbstverständlich auch die üblichen Java-Kommentare möglich.
Wie überall in der Programmierwelt gilt auch bei JSPs, dass es sinnvoll ist, diese ausgiebig mit Kommentaren zu dokumentieren.

Zum SeitenanfangZum Seitenanfang

Direktiven

Wie schon im Kapitel "Lebenszyklus von JSPs" beschrieben, werden JSPs in einem ersten Schritt hin zu Servlets transformiert. Wünschenswert ist, dazu dem JSP-Compiler Hilfsmittel an die Hand geben zu können, wie er mit der Seite und den auf dieser verwendeten Inhalten umgehen soll. Genau dazu dienen die JSP-Direktiven.
Syntaktisch sehen alle Direktiven wie folgt aus:

<%@ direktive param1="value1" param2="value2" %>

Bis zur Version 2.0 gab es lediglich die drei Direktiven "include", "page" und "taglib", die auch im Folgenden vorgestellt werden. Hinzu gekommen sind mit der JSP-Version 2.0 zudem die Direktiven "attribute" und "tag", auf die wir im Kapitel Tag-Libraries eingehen werden.

Die Direktive "include"

Da die "include"-Direktive die einfachste Direktive ist, wollen wir auch mit ihr beginnen. Mit dieser Direktive wird es möglich, den kompletten Inhalt anderer Dateien in die JSP einzubinden. Nutzen kann man diese Einbindung vielfach. Beispielsweise könnten stets wieder kehrende Footer, Header und unveränderliche Teile so eingebunden werden, oder ggf. Code ausgelagert werden, wenn sonst die Seite zu unübersichtlich wird4. Die Einbindung der externen Datei geschieht, bevor die JSP in ein Servlet transformiert wird. Die Datei, die eingebunden wird, wird dabei durch das Attribut "file" angegeben.

AttributDefaultwertKurzbeschreibung
filerelativer oder Context-absoluter Pfad auf eine zu inkludierende Textdatei


Die eingebundene Datei kann dabei selbst wiederum JSP-Code enthalten oder auch auf Variablen der einbindenden JSP zugreifen (dabei müssen die Variablen natürlich an der eingebundenen Stelle sichtbar sein). Schließlich wird hier einfach Code in eine andere Datei ausgelagert.
Abschließend noch kurz die volle Syntax:

<%@ include file="fileToInclude" %>

Dabei kann der Wert des Attributs "file" auf jede beliebige Textdatei verweisen. Sie muss relativ zum Pfad der JSP selbst sein. Liegt diese im Filesystem auf einer höheren Ebene, so wird wie bei HTML mittels "../" auf übergeordnete Verzeichnisse zugegriffen.
Es soll noch kurz darauf hingewiesen werden, dass mit der "include"-Standardaktion eine Möglichkeit zum Einbinden externer Inhalte zur Laufzeit besteht. S. dazu das Kapitel JSP-Standardaktionen. Ausserdem stellt das "tiles"-Framework eine weitere Alternative dar, die insbesondere bei stets gleichem Seitenaufbau sinnvoll ist. Wir verwenden bspw. das "tiles"-Framework zur Aufteilung der Seiten des Tutorials. Wie wir dies machen, welche Möglichkeiten das tiles-Framework bietet und warum es zumeist eine bessere Alternativ zu der Verwendung von include-Anweisungen ist, beschreiben wir im Kapitel Tiles-Framework.

Die Direktive "page"

Im Gegensatz zur "include"-Direktive gibt es bei der "page"-Direktive zahlreiche Attribute, wie die folgende Tabelle zeigt.

AttributDefaultwertKurzbeschreibung
Attribute bis JSP-Version 1.2
languagejavaDefiniert die Skripting-Language (derzeit immer Java, zukünftig evtl. auch Python o.a. Skriptsprachen)
extendsMögliche Oberklasse der JSP (diese muss das Interface javax.servlet.jsp.JspPage implementieren)
importImportiert benötigte Klassen und Pakete
sessiontrueBei "true" nimmt die JSp an einer HttpSession teil und enthält das implizite Objekt "session"
buffer8kbDer Puffer für den Content. Der Default-Mindestwert ist lt. JSP-Spezifikation 8kb. Im Falle eines Überlaufs wird der Pufferinhalt an den Client gesendet.
autoFlushtrueBei "true" wird nach Absenden eines vollen Puffers dieser geleert. Bei "false" wird im Falle eines Pufferüberlaufs eine Exception geworfen.
isThreadSafetrueBei "true" kann der Container davon ausgehen, dass eine JSP-Seite von meherer Threads synchron genutzt werden kann. Bei "false" werden Anfragen serialisiert. "false" sollte möglichst niemals genutzt werden, da das dadurch verlangte Verhalten erhebliche Performance-Probleme bereiten kann!
infoEine Kurzbeschreibung der Seite.
errorPageEine relative URL zu einer Seite, die im Fehlerfalle aufgerufen werden soll. Es gibt über Einträge in der web.xml m.E. bessere Wege, das gleiche Ergebnis zu erreichen.
isErrorPagefalseGibt an, ob die seite eine Seite zur darstellung von Fehlern sein soll. Nur bei "true" ist das implizite "exception"-Objekt vorhanden.
contentTypetext/htmlLegt den Mime-Typ der Antwort an. Neben "text/html" dürfte v.a. "text/xml" in der Praxis vorkommen.
pageEncodingBei internationalisierten Seiten geradezu ein Pflicht-Attribut!
Attribute ab JSP-Version 2.0
isELIgnoredLegt fest, ob Expression Language-Ausdrücke in dieser Seite ausgewertet werden sollen. Unter Umständen wichtig für alte Projekte, die möglicherweise Konstrukte enthalten, die syntaktisch der EL entsprechen.


Natürlich sind nicht alle Attribute gleich wichtig - einige haben (zumindest derzeit) kaum praktische Bedeutung.
Die Attribute "info", "language" und "extends" werden, wenn überhaupt, nur vereinzelt genutzt. Zumindest das "language"-Attribut könnte aber in der Zukunft eine größere Rolle spielen, wenn einzelne Container oder gar die JSP-Spezifikation weitere Sprachen unterstützen bzw. zulassen. Das Attribut Session wird im Kapitel Session-Handling, Cookies und URL-Rewriting erläutert. Im Allgemeinen kann man es aber auf dem Standardwert belassen.
Ebenfalls mit sinnvollen Standardwerten ausgestattet sind die "buffer", "autoFlush" und "isThreadSafe"-Attribute. Hier wird man allenfalls mal in Ausnahmefällen Änderungen vornehmen müssen.
Ganz anders die "import", "contentType" und "pageEncoding"-Attribute. Diese sind geläufige Attribute. Das erste wird genutzt um sämtliche benötigten Klassen einzubinden - entsprechend den import-Statements in Java-Klassen. Dabei kann das Attribut alle benötigten Importe durch Kommata getrennt angeben, oder es können jeweils getrennte "page"-Direktiven verwandt werden. Beide Möglichkeiten finden sich in dem Beispiel etwas weiter unten. Die "import"Attribute werden überall dort benötigt, wo Skriptlets eingesetzt werden. Insofern gilt hier das, was wir immer zu Skriptlets sagen: Sie sollten besser vermieden werden. Kommt man ohne Skriptlets aus, braucht man auch keine page-Direktiven mit "import"-Attributen. Wir stellen sie hier dennoch im Beispiel unten ausführlich dar, da wir aus Erfahrung nur zu gut wissen, wie oft Skriptlets trotz aller Warnungen eingesetzt werden.
Der Content-Type muss jedes mal gesetzt werden, wenn keine HTML-Datei erzeugt wird. Dies dürften in der Praxis v.a. XML-Dateien sein, oder auch WML bzw. cHTML-Seiten für Mobiltelefone. In diesem Fall, muss das Attribut "contentType" entsprechend gesetzt werden.
In internationalisierten Anwendungen kommt man zudem um das "pageEncoding"-Attribut nicht herum. Wirklich globalisierte Seiten benötigen hier das Character-Encoding UTF-8. Ganz gute Informationen zu verschiedenen Zeichensätzen findet man auf den SELFHTML-Seiten zur Internationalisierung. Auch in diesem Tutorial widmen wir uns ausgiebig diesem in der Praxis sehr wichtigen Thema. S. dazu das Kapitel Internationalisierung.
Mit den Neuerungen der JSP-Version 2.0 kam auch ein weiteres Attribut zur "page"-Direktive hinzu. In aller Regel sollte der Standardwert, der Expression Language erlaubt, wohl bevorzugt werden. Aber bei der Nutzung alter JSP-Seiten in neuen JSP-Containern kann es dann zu Problemen kommen, wenn im normalen Text der Seite EL-Ausdrücke wie bspw. ${bean.value} vorkommen. Dann muss man in diesen Seiten u.U. das Attribut "isELIgnored" auf "true" setzen.
Im folgenden Code-Fragment finden sich ein paar Beispiele für mögliche Nutzungen der "page"-Direktive:

<%@ page isELIgnored="false" %>
<%@ page pageEncoding="UTF-8" %>
<%@ page contentType="text/html" %>
<%@ page import="java.util.List,java.util.Iterator" %>
<%@ page import="java.math.BigInteger" %>
<%@ page import="org.jsptutorial.util.*" %>

Die Direktive "taglib"

Tags und deren Zusammenfassung in Bibliotheken werden ausführlich im Kapitel Tag-Libraries vorgestellt. Um diese Bibliotheken einzubinden und in einer JSP zu nutzen, muss man mittels der "taglib"-Direktive angeben, wo diese zu finden ist und wie auf sie in der JSP-Seite bezug genommen werden soll.
Die Attribute dieser Direktive sind in der folgenden Tabelle zusammengefasst.

AttributKurzbeschreibung
uriAbsoluter oder relativer Pfad zur Taglib-Deskriptor-Datei. Kann auch eine in der web.xml definierte fiktive URL sein.
prefixDas Pflicht-Präfix, das innerhalb der JSP verwendet wird zur Unterscheidung verschiedener Tag-Libraries.
mit JSP 2.0 hinzugekommen:
tagdirGibt an, dass das Präfix Tag-Erweiterungen in diesem Unterverzeichnis von "/WEB-INF/tags" bezeichnet.


Im folgenden Beispiel greifen wir bspw. auf die Core-Bibliothek der Java-Standard Tag Library zu. Weitere Beispiele befinden sich im Kapitel zu den Tag-Libraries.

<%-- the following line declares where to find the core-taglib 
      (actually a symbolic URI) and which prefix is used 
      to access its tags --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%-- now we can access any of the core JSTL-Tags by using 
      <c:tagname attribute1=""> 
      where "c" is the prefix defined in the taglib directive above
      and tagname is the name of one of the tags defined by the library--%>
<c:forEach items="${showTutorialForm.map.topicList}" var="topic">

<%-- herein we can make use of the elements provided by this loop;
      this will be dealt with in detail in the JSTL and EL chapters --%>

</c:forEach>

Zum SeitenanfangZum Seitenanfang

Maskierung besonderer Zeichen

Wir haben in diesem Kapitel gezeigt, dass bestimmte Zeichen zur Kennzeichnung unterschiedlicher Bestandteile einer JSP-Page vorgesehen sind. Aber es kann durchaus vorkommen, dass man diese Zeichen auch z.B. im normalen HTML-Code der Seite braucht. Bspw. kann man nicht einfach in einer JSP-Seite mittendrin die Zeichen "<%" verwenden. Schließlich würde der folgende Teil als ein JSP-Skriptlet angesehen und normaler Text würde dort sofort zu einer Fehlermeldung führen. Und auch das - erst in späteren Kapiteln vorgestellte - $-Zeichen zur Kennzeichnung von Expression Language-Ausdrücken muss geschützt werden können.
Interessanterweise gelten diese Probleme nur an bestimmten Stellen. Nach einem öffnenden Skriptlet-Tag könnte bspw. in Kommentaren die Zeichenfolge "<%" ohne Probleme benutzt werden. Oder die Zeichenfolge "%>" kann überall dort verwendet werden, wo normaler HTML-Content vorkommt. Sie bereitet aber bspw. in Kommentaren oder String-Zeichenketten in einem Skriptlet Probleme, da sie dort dieses sofort beenden würde.
Generell ist das Backslash-Zeichen "\" das Mittel der Wahl zur Maskierung. Die folgende Tabelle zeigt genau, wo dieses zu platzieren ist. Sie enthält aber nicht nur die besonderen Zeichen und die alternative Schreibweise, will man die Zeichen an besonderen Stellen nutzen, sondern als dritte Spalte auch kurze Angaben dazu, wo die Maskierung dieser Zeichen überhaupt eine Rolle spielt.

ZeichenketteMaskierte ZeichenketteWo ist dies zu beachten
<%<\%ܜberall dort, wo normaler HTML-Code und Template-Text verwandt wird
%>%\>Innerhalb von Skriptlets und in Attributen von Direktiven
"\"Innerhalb von Attributen, wenn das Attribut mit doppelten Anführungsstrichen als Begrenzer gekennzeichnet wird
'\'Innerhalb von Attributen, wenn das Attribut mit einfachen Anführungsstrichen als Begrenzer gekennzeichnet wird
\\\Wenn innerhalb von Attributen ein Backslash benötigt wird
${$\{(ab JSP 2.0) In allen Attributen und überall dort wo normaler HTML-Code und Template-Text verwandt wird. Allerdings nur, wenn die Evaluierung von Expression Language eingeschaltet ist
#{#\{(ab JSP 2.1) In allen Attributen und überall dort wo normaler HTML-Code und Template-Text verwandt wird. Allerdings nur, wenn die Evaluierung der Unified Expression Language eingeschaltet ist

Zum SeitenanfangZum Seitenanfang

Anmerkungen:

1) Im Folgenden wird nur die Standardsyntax beschrieben. Alternativ existiert auch noch eine XML-konforme Syntax für JSP-Seiten. Diese wird ausführlich im Kapitel JSP-Dokumente besprochen. (zurück)

2) Das Beispiel ist natürlich völlig sinnlos. Es soll ausschliesslich zeigen, wie man Skriptlets einsetzt. Empfehlenswert ist allerdings, sich mal den Quelltext der generierten Seite anzusehen. (zurück)

3) Instanz ist eigentlich eine schlechte Übersetzung des englischen "instance". Instanz hat sich aber inzwischen soweit durchgesetzt, dass ich die Verwendung des Ausdrucks für legitim halte. (zurück)

4) Eine derart grosse Seite, dass man Code auslagern muss, um die JSP noch lesbar zu halten, ist allerdings praktisch immer ein deutliches Warnzeichen für zu viel Logik in einer JSP. (zurück)


www.jsptutorial.org
© 2005, 2006, 2007