Beispiel: JSP-Grundlagen


Inhalt:

Allgemeiner Code
Beispiel 1: JSP-Grundlagen
Beispiel 2: Controller-Servlet
Beispiel 3: Tag Libraries
Beispiel 4: Custom Tag Libraries
Beispiel 5: Tag Files

Diverse JSP-Beispiele. Alle diese Beispiele arbeiten völlig ohne EJB-Zugriff.
Sie führe die gleiche Logik aus wie das Beispiel der Stateful Session Bean: Sie errechnen Oberfläche und Volumen eines Quaders.

Beim Anlegen des Projekts wird als Projekttyp hier immer ein "Dynamic Web Project" verwendet. Es ist wichtig, dass wir jeweils die Checkbox "Add project to an EAR" zurücksetzen.
Dynamic Web Project
In Schritt 2 können wir alle Einstellungen bei den Default-Werten belassen.

Der Export und Re-Import des Projekts erfolgt diesmal nicht als "EAR file" sondern als "WAR file", ansonsten ist das Vorgehen identisch. Beim Import ist zu beachten dass das Projekt wiederum nicht zu einer Enterprise Application zugefügt wird.
In Beispiel 3 verwenden wir TagLibraries, deren JAR-Dateien stecken im Unterverzeichnis "WebContent/WEB-INF/lib". Beim Re-Import müssen wir beachten dass die JARs nicht als Utility-Projekte importiert werden sondern als JARs in Verzeichnis "WEB-INF/lib" gepackt werden (d.h. in Schritt 2 des Importers keine Haken setzen).
Import von JARs

Wichtige Info: Die im folgenden verwendeten Fehlerseiten scheinen bei einem standard-konfigurierten Internet Exploder nicht zu funktionieren. Wenn man z.B. im Beispiel "JSP1" eine negative Zahl eingibt dann kommt eventuell diese Anzeige:
Internet Explorer: Fehler 500
Problem hierbei: der JBoss-Server liefert den HTTP-Fehlercode 500 (Server-Fehler) sowie eine Seite mit der Fehlermeldung zurück. Der Internet Explorer ignoriert diese jedoch und zeigt seine eigene Seite an. Lösung des ganzen: In den Internetoptionen unter "Erweitert" in der Kategorie "Browsing" den Haken vor der Option "Kurze HTTP-Fehlermeldungen anzeigen" entfernen.
Internet Explorer: Fehler 500

Allgemeiner Code


Alle folgenden Beispiele verwenden zwei Hilfsklassen (die jeweils in einem an das Beispiel angepaßten Package stecken). Die Klasse Seitenlaengen enthält die drei Seitenlängen A, B und C:
package de.fhw.komponentenarchitekturen.knauf.jsp1;

public class Seitenlaengen
{
  private double dblA;
  private double dblB;
  private double dblC;

  public double getA()
  {
    return dblA;
  }

  public void setA(double dblA)
  {
    this.dblA = dblA;
  }

  public double getB()
  {
    return dblB;
  }

  public void setB(double dblB)
  {
    this.dblB = dblB;
  }

  public double getC()
  {
    return dblC;
  }

  public void setC(double dblC)
  {
    this.dblC = dblC;
  }
}
Die Klasse Historie enthält eine Liste von Seitenlaengen:
package de.fhw.komponentenarchitekturen.knauf.jsp1;

import java.util.Iterator;
import java.util.Vector;

public class Historie
{
  private Vector<Seitenlaengen> vectorBerechnungen = new Vector<Seitenlaengen>();
  
  public void addSeitenlaenge (Seitenlaengen seitenlaengeAktuell)
  {
    this.vectorBerechnungen.add( seitenlaengeAktuell);
  }
  
  public Iterator<Seitenlaengen> iterator()
  {
    Iterator<Seitenlaengen> iterator = this.vectorBerechnungen.iterator();
    return iterator;
  }
}

Beispiel 1: JSP-Grundlagen

Dieses Beispiel enthält drei JSP-seiten ("index.jsp", "input.jsp" und "errorpage.jsp") und die Klassen de.fhw.komponentenarchitekturen.knauf.jsp1.Historie und de.fhw.komponentenarchitekturen.knauf.jsp1.Seitenlaengen.

Hier gibt es das Projekt als WAR-Export-Datei:
JSP1.war.

Das Beispiel soll folgende Grundelemente einer JSP zeigen:

Die Anwendung findet sich unter dieser URL: http://localhost:8080/JSP1/index.jsp.

Beispiel 2: Controller-Servlet

In diesem Beispiel wird ein großer Teil der Anwendungslogik in ein Servlet ausgelagert. Beim Absenden des Formulars ist nicht die JSP-Seite das Ziel, sondern ein Servlet. Dieses wertet die Request-Parameter aus, erzeugt die Bean mit den aktuellen Request-Werten, berechnet Volumen und Oberfläche.
Anschließend wird der Request an "index.jsp" weitergeleitet, diese Seite gibt die errechneten Werte aus.
Hier gibt es das Projekt als WAR-Export-Datei:
JSP2.war.

Das Beispiel zeigt dieses:
Die Anwendung findet sich unter dieser URL: http://localhost:8080/JSP2/index.jsp.


Beispiel 3: Tag Libraries

In diesem Beispiel wird Beispiel 2 weitergeführt: auf der JSP-Seite "index.jsp" soll kein Stück Javacode mehr zu sehen sein. Stattdessen soll alle dynamische Formatierung von TagLibs erledigt werden.
Das Beispiel verwendet folgende Taglibraries:
-jakarta-taglibs-request-1.0.1 (Arbeiten mit dem Request, z.B. Ausgabe von Attributen im Request)
-Sun-Implementation des Java-Standard-Taglib-Standards Version 1.2.

Hier gibt es das Projekt als WAR-Export-Datei:
JSP3.war.

Nach dem Anlegen des Dynamic Web Projects müssen die zu verwendenden Tag-Libraries importiert werden.
Dazu müssen die Dateien "taglibs-request.jar" aus dem Paket "jakarta-taglibs-request-1.0.1" (siehe Link auf meiner Startseite) und "jstl.jar" aus der Sun-Referenzimplementation (findet man im JBoss-Verzeichnis unter "server\default\deploy\jbossweb.sar") in das Verzeichnis "WebContent\WEB-INF\lib" des Projekts eingefügt werden. Anschließend "Refresh" im Projekt wählen. Die beiden Libraries sollten jetzt im Project Explorer unter "Web App Libraries" auftauchen.
Wir müssen außerdem die Deklarationen der Taglibraries (Dateien mit der Endung ".tld") ins Projekt packen. Dazu aus "taglibs-request.jar" die Datei "taglib.tld" extrahieren, und aus "jstl.jar" die Datei "c.tld". Beide in das Verzeichnis "WebContent\WEB-INF\tags" (das Ziel ist frei wählbar, die Dateien könnten auch direkt in WEB-INF gelegt werden) packen.
Tag Libraries
Jetzt müssen wir die Tag Libraries in "web.xml" eintragen:
	<jsp-config>
		<taglib>
			<taglib-uri>http://jakarta.apache.org/taglibs/request-1.0</taglib-uri>
			<taglib-location>/WEB-INF/tags/taglib.tld</taglib-location>
		</taglib>
 		<taglib>
			<taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
			<taglib-location>/WEB-INF/tags/c.tld</taglib-location>
		</taglib>
	</jsp-config> 
Hier werden symbolische Namen für die Taglibs in "WEB-INF\lib" deklariert, unter diesen URI (Unified Resource Identifier) werden sie später auf den JSP-Seiten angesprochen.

Anmerkung:
Sofern die "taglib-uri" dem Default entspricht, der in der .tld-Datei deklariert ist, kann man sich diese Einträge in web.xml sparen, JBoss und Eclipse finden die Taglib auch so, sofern sie (auch in JAR-Dateien versteckt) im WEB-INF-Verzeichnis liegen. Wenn man so vorgeht, dann muss man die .tld-Dateien nicht aus den JAR-Dateien extrahieren.

In "index.jsp" werden die Taglibs so eingebunden:
	<%@ taglib uri="http://jakarta.apache.org/taglibs/request-1.0" prefix="req" %>
	<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 
Jetzt können die Tags aus den TagLibraries unter den Alias-Namen "req" bzw. "c" verwendet werden.

Der Rest von "index.jsp" sieht so aus:
<req:existsAttribute name="Volumen">
  Volumen = <req:attribute name="Volumen" />, Oberfläche = <req:attribute name="Oberflaeche" />
  <br/> <br/> <br/>
</req:existsAttribute>

<jsp:include page="input.jsp" />

<h2>Ihre letzten Berechnungen waren:</h2> <br/>
<c:forEach var="item" items="${sessionScope.historie.iterator}">
  a=<c:out value="${item.a}"/>, b=<c:out value="${item.b}"/>, c=<c:out value="${item.c}"/> <br/>
</c:forEach>
Das Tag "req:existsAttribute" prüft, ob ein bestimmtes Attribut im Request existiert. Im Beispiel prüfe ich auf "Volumen" und erkenne daran, ob das Servlet zur Berechnung aufgerufen wurde, oder ob dies der erste Aufruf der JSP ist.

Das Tag "req:attribute" gibt ein bestimmes Request-Attribut aus.

Das Tag "c:forEach" der JSTL läuft über eine Liste und schreibt das jeweils aktuelle Item als Attribut in den PageContext. Die zu durchlaufende Liste wird hier als Expression Language (EL) - Ausdruck deklariert. ${sessionScope.historie.iterator} bedeutet: "Im SessionContext gibt es ein Attribut namens 'historie', und dieses hat eine Property 'iterator' (also eine Methode "getIterator"), über die Rückgabe der Property laufen.".
Das aktuelle Item wird in ein PageContext-Attribut namens "item" gepackt (der Name dieses Attributs wird durch das Attribut "var" deklariert).

Anmerkung:
Bei der EL ist zu beachten, dass ihre Elemente sich auf Attribute in Session-, Request- und PageContext sowie auf Properties von darin gefundenen Objekten beziehen. Dies alles sucht sich der Server zur Laufzeit zusammen, es gibt keinerlei Möglichkeit, sie durch Compilierung oder Validierungen der Entwicklungsumgebung zu prüfen.
Für weitere Informationen sei auf folgendes verwiesen:


Das Tag "c:out" gibt den Wert einer Variablen als String aus. Im Beispiel wird ein EL-Ausdruck verwendet: ${item.a} sucht ein Attribut "item" im PageContext (ich hätte es auch sauberer als ${pageScope.item.a} schreiben können), und gibt von diesem eine Property "a" (also die Rückgabe der Methode "getA") aus.


Wie im vorherigen Beispiel muss außerdem die Errorpage als Handler für den Error Code 500 eingetragen werden.

Die Anwendung findet sich unter dieser URL: http://localhost:8080/JSP3/index.jsp.


Beispiel 4: Custom Tag Libraries

In diesem Beispiel werden die TagLibraries aus Beispiel 3 ersetzt durch handgeschriebene Taglibraries.

Hier gibt es das Projekt als WAR-Export-Datei:
JSP4.war.

Die TagLibraries landen im Package de.fhw.komponentenarchitekturen.knauf.jsp4.tags. Die Definition der Tags erfolgt in der Datei "WebContent\WEB-INF\tags\jsp4.tld".
Der Rahmen dieser TagLibrary-Deklaration sieht so aus (gemäß JSP-2.1-Spezifikation, die TLDs aus dem letzten Beispiel wurden erstellt gemäß JSP-Spezifikation 1.1, dort wurde eine DTD verwendet und einige Tags hießen leicht anders):
<taglib xmlns="http://java.sun.com/xml/ns/javaee" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" 
  version="2.1> 
  <tlib-version>1.0</tlib-version>
  <short-name>jsp4</short-name> 
  <uri>http://www.informatik.fh-wiesbaden.de/~knauf/jsp4</uri> 
  ...
</taglib> 
Hier vergebe ich einen Kurznamen der TagLib und eine URI, wobei beide Werte frei vergebbar sind und nur als Vorschläge dienen, auf der JSP-Seite können sie beliebig überschrieben werden.

Folgende Tags werden verwendet:
In "web.xml" muss dieses zugefügt werden:
<jsp-config>
 	<taglib>
		<taglib-uri>http://www.informatik.fh-wiesbaden.de/~knauf/jsp4</taglib-uri>
		<taglib-location>/WEB-INF/tags/jsp4.tld</taglib-location>
	</taglib>
</jsp-config> 
Die Taglib-URI unter der wir die TagLib später in den JSPs ansprechen ist hier identisch mit der in der TLD-Datei vorgegebenen, dies ist aber nicht verpflichtend.

In "index.jsp" wird die TagLib so eingebunden:
<%@ taglib uri="http://www.informatik.fh-wiesbaden.de/~knauf/jsp4" prefix="jsp4" %>
Jetzt zeigt uns Eclipse auch brav die verfügbaren Tags an:
TagLib in Eclipse


Die Anwendung findet sich unter dieser URL: http://localhost:8080/JSP4/index.jsp.


Beispiel 5: Tag Files

Wir nutzen hier ein im JSP-Standard 2.0 eingeführtes neues Feature: Tag-Libraries können auch in sogenannten Tag Files implementiert werden. In diesem Beispiel werden die in Java codierten Tags aus Beispiel 4 ersetzt durch JSP-Fragmente.
Weitere Informationen finden sich in Kapitel 8.5 der JSP-2.1-Spezifikation.
Nützliche Links zu diesem Thema:
http://www.oracle.com/technology/sample_code/tutorials/jsp20/tagfiles.html
http://www.oracle.com/technology/sample_code/tech/java/codesnippet/jsps/customtag/How-to-TagFile.html
http://today.java.net/pub/a/today/2003/11/14/tagfiles.html (Teil 1 und 2)
http://www.oracle.com/technology/pub/articles/cioroianu_tagfiles.html

Hier gibt es das Projekt als WAR-Export-Datei: JSP5.war.

Erstellen der Tags:
Das Erstellen eines Tags ist einfach: wir legen ein Unterverzeichnis "tags" in "WEB-INF" an (das Verzeichnis darf auch anders heißen). Alle Dateien in diesem Verzeichnis, die die Endung ".tag" haben werden als Tag erkannt. Der Dateiname ist dabei gleichzeit der Tagname.

Das Erstellen einer TLD-Datei entfällt. Falls ein Tag Attribute hat, dann werden die so in der .tag-Datei deklariert:
	<%@ attribute name="..."%>

Die Entsprechung zur "page"-Direktive auf einer JSP-Seite ist die "tag"-Direktive, die z.B. zum Importieren von Java-Packages verwendet werden kann:
	<%@ tag import="de.fhw.swtvertiefung.knauf.jsp5.*"%>


Verwendung der Tags:
In web.xml muss nichts eingetragen werden.
In der JSP wird die Taglibrary so eingebunden:
	<%@ taglib prefix="jsp5" tagdir="/WEB-INF/tags" %>
Der relative Pfad zum Verzeichnis der Tags wird angegeben und die Taglibrary erhält einen Alias.
In der JSP selbst erfolgt die Verwendung genauso wie im letzten Beispiel.


"ifExistsRequestAttribute"-Tag:
Die Tags in diesem Beispiel verwenden alle massiv Javacode. Dies ist nicht wirklich schön, aber da die Tags allesamt auch durch Tags der JSTL abbildbar sind würde es nicht viel Sinn ergeben hier die JSTL zu verwenden.
<%@ attribute name="requestAttribute" required="true"%>

<%
  //Prüfen ob das Attribut existiert !
  if (request.getAttribute(requestAttribute) != null)
  {
    //Body ausführen !
    %>
 	<jsp:doBody />
 	<%
  }
%> 
Das Tag hat ein Attribut "requestAttribute", dies ist ein String der ein Attribut angibt auf dessen Existenz im Request geprüft wird. Falls das Attribut vorhanden ist wird der Inhalt des Tags auf der JSP ausgeführt. Dies geschieht durch das JSP-Element "<jsp:doBody />".


"loopOverHistorie"-Tag:
Hier ergab sich das Problem dass ich das aktuelle Item nicht in den JspContext legen konnte, denn es ging in den Childelementen verloren. Deshalb verwende ich hier den Request, um das aktuelle Item abzulegen.
<%@ tag import="java.util.Iterator"%>
<%@ tag import="de.fhw.komponentenarchitekturen.knauf.jsp5.*"%>
<%@ attribute name="item" required="true"%>
<%@ attribute name="sessionContextAttribute" required="true"%>

<%

  if (session.getAttribute(sessionContextAttribute) != null)
  {
    Object objSessionContextAttribute = session.getAttribute(sessionContextAttribute);
    if (!(objSessionContextAttribute instanceof Historie))
      throw new JspException("Attribut " + sessionContextAttribute + " ist nicht vom Typ 'Historie' sondern '" + objSessionContextAttribute.getClass().toString());
    Historie historie = (Historie) objSessionContextAttribute;
    //Iterator initialisieren:
    Iterator<Seitenlaengen> iteratorHistorie = historie.getIterator();
    //Ist überhaupt ein Item vorhanden ?
    while (iteratorHistorie.hasNext() == true)
    {
      Seitenlaengen itemAktuell = iteratorHistorie.next();
      
      //Aktuelles Item in den Request packen (im jspContext kommt das leider nicht im Subtag an):
      request.setAttribute(item, itemAktuell);

      //Tag-Body ausführen.
      %>
      <jsp:doBody />
      <%
    }
  }
%>

Die Anwendung findet sich unter dieser URL: http://localhost:8080/JSP5/index.jsp.



Stand 04.01.2009
Historie:
30.11.2008: Erstellt aus Vorjahresbeispiel, Anpassungen an Eclipse 3.4 und JBoss 5.0, JavaDoc-Warnungen in Beispiel 4 korrigiert.
02.12.2008: Alle JSPs von DOCTYPE XHTML 1.0 auf HTML 4.0 umgestellt, da WTP bei XHTML falsche Validierungswarnungen ausspuckte.
07.12.2008: Doku von Beispiel 1-3 stark erweitert.
09.12.2008: Doku von Beispiel 4+5 stark erweitert.
10.12.2008: @Override-Annotations für Servlet- und Tag-Methoden, required="true" für Attribute in JSP5 zugefügt.
04.01.2009: Noch ein Link auf eine EL-Seite