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 für WildFly 24 und JakartaEE 8.

Eine aktuelle Version für JakartaEE10 und WildFly 33 findet sich hier.


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. Die Checkbox "Add project to an EAR" darf dabei nicht gesetzt sein (das ist der Default).
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

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 die Apache-Implementation des Java-Standard-Taglib-Standards (JSTL) Version 1.2:
https://tomcat.apache.org/taglibs/standard/

Eine offizielle Doku der TagLib habe ich nicht gefunden, das ist wohl zu alt. Auf obiger Download-Seite gibt es nur eine Readme, die das Einrichten erklärt.
Aber zum Beispiel gibt es diese Seite: https://www.w3schools.in/jsp/standard-tag-library/.

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

Nach dem Anlegen des Dynamic Web Projects muss die zu verwendende Tag-Library zugefügt werden.
Dazu muss die Datei "taglibs-standard-spec-1.2.5.jar" und "taglibs-standard-impl-1.2.5.jar" aus der Apache-Referenzimplementation (siehe oben) 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.

WildFly enthält diese Dateien ebenfalls, und sogar in etwas neueren Versionen: sie liegen im WildFly-Verzeichnis unter "modules\system\layers\base\javax\servlet\jstl\api\main\taglibs-standard-impl-1.2.6-RC1.jar") Da eine mittels der JBoss Tools erzeugte Server Runtime diese Jar-Dateien einbindet, ist oben beschriebenes Platzieren der Dateien in "WEB-INF\lib" nicht nötig:
JSTL in WildFly


Deklaration der Taglib in web.xml:
Sofern die "taglib uri", die in der JSP deklariert ist, dem Default entspricht, der in der .tld-Datei deklariert ist, kann man sich die im Folgenden beschriebenen Einträge in web.xml sparen, WildFly und Eclipse finden die Taglib auch so, sofern sie (auch in JAR-Dateien versteckt) im WEB-INF-Verzeichnis liegen. Hier ist aber trotzdem der Vollständigkeit halber beschrieben, wie man die TagLibrary explizit deklarieren könnte:

Die Deklarationen der Taglibraries (Dateien mit der Endung ".tld") werden ins Projekt gelegt. Dazu aus "jstl.jar" die Datei "c.tld". Diese in das Verzeichnis "WebContent\WEB-INF\tags" (das Ziel ist frei wählbar, die Datei könnte auch direkt in WEB-INF gelegt werden) packen.
Tag Libraries

Jetzt wird die Tag Library in "web.xml" eintragen:
	<jsp-config>
 		<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.


In "index.jsp" wird die Taglib so eingebunden:
	<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 
Jetzt können die Tags aus der Tag Library unter dem Alias-Namen "c" verwendet werden.

Der Rest von "index.jsp" sieht so aus:
<c:if test="${requestScope.Volumen != null}">
  Volumen = <c:out value="${requestScope.Volumen}" />, Oberfläche = <c:out value="${requestScope.Oberflaeche}"/>
  <br/> <br/> <br/>
</c:if>

<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 "c:if" prüft, ob ein bestimmtes Attribut im Request ("requestScope") existiert. Im Beispiel prüfe ich ob "Volumen" ungleich null ist und erkenne daran, ob das Servlet zur Berechnung aufgerufen wurde, oder ob dies der erste Aufruf der JSP ist.

Das Tag "c:out" 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.
Die Links, die es 2009 beim Erstellen dieser Seite noch gab, funktionieren leider alle nicht mehr.

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.komponentenarchitekturen.knauf.jsp4.*"%>


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 02.03.2022
Historie:
02.03.2022: Erstellt aus Beispiel von 2009. Aktualisiert auf WildFly 24, JakartaEE 8. Beispiel "JSP3": "taglibs-request.jar" entfernt, da schon lange deprecated, Quellen für JSTL aktualisiert, Einbindung der TagLib überarbeitet.