Protokoll Stunde 12

Werbung
Praktikum aus Softwareentwicklung 2, Stunde 12
Lehrziele/Inhalt
1. JavaServer Pages
Dynamischer Kontext in JavaServer Pages
Mit JavaServer Pages (JSP) kann man dynamischen Inhalt erzeugen. Dazu kann man: Java-Code in die
Seite schreiben, Ausdrücke in der Skriptsprache Expression Language auswerten und programmierte
Tags einfügen.
Skriptelemente
Skriptelemente sind die älteste und unübersichtlichste Art Logik in JSP einzubringen. Skriptelemente
enthalten Java-Code (Scriptlet) der direkt in die Handler-Methode kopiert wird wenn der WebContainer das Servlet aus der JSP erzeugt. Der JSP-Compiler erkennt Scriptlets an dem KlammernPaar: <% und %>.
Abbildung 21 zeigt ein einfaches Beispiel für Scriptlets. Man sieht, dass Scriptlets und HTML beliebig
gemischt werden kann. Das erste Scriptlet beginnt mit einer Schleife, dann kommt HTML-Code und
das zweite Scriptlet schließt die Schleife ab. Der JSP-Compiler kopiert dabei den HTML-Code in
out.write-Anweisungen und den Scriptlet-Code direkt in die generierte Handler-Methode. Vertippt
man sich im Java-Code, kann die Fehlersuche mühsam sein. Je nach verwendetem Web-Container
werden Fehlermeldungen vom Java-Compiler mehr oder weniger auf die eigentliche Fehlerstelle in
der JSP-Seite zurückgeführt.
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<html>
<head><title>JSP Scriptlet Page</title></head>
<body>
<h1>Let's Count!</h1>
<%
for (int i = 0; i < 10; ++i) {
out.println(i);
%>
,
<%
}
%>
...
</body>
Let's Count!
</html>
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , ...
Abbildung 21) Beispiel-JSP mit Scriptlet
In seltenen Fällen muss man in JSP Felder und Methoden deklarieren. Das ist in DeklarationsElementen möglich, sie werden mit <%! eingeleitet und mit %> abgeschlossen.
© Markus Löberbauer 2010
Seite 48
<%@page contentType="text/html" pageEncoding="UTF-8"
import="java.util.Date"%>
<html>
<head><title>JSP Declarations Page</title></head>
<body>
<%
String message = format("Hello World!");
out.println(message);
%>
</body>
<%!
private static final String MESSAGE_FORMAT = "%s : %s";
%>
<%!
private String format(String message) {
return String.format(MESSAGE_FORMAT, new Date(), message);
}
%>
</html>
Fri Jun 04 08:27:27 CEST 2010 : Hello World!
Abbildung 22) Beispiel-JSP mit Feld- und Methoden-Deklaration
Abbildung 22 zeigt wie man in einer JSP ein Feld deklariert, hier die Konstante MESSAGE_FORMAT,
und wie man Methoden deklariert, hier die Methode format. Wie bei programmierten Servlets muss
man auch bei durch JSP generierten Servlets darauf achten, dass durch ein Objekt mehrere
Benutzeranfragen gleichzeitig bearbeitet werden können. Also auch hier gilt, Felder sind potentiell
ein Synchronisations-Problem.
Im Beispiel in Abbildung 22 rufen wir eine Methode auf und geben das Ergebnis in der Web-Seite
aus. Das wird in JSP mit Expression-Elementen unterstützt. Expression-Elemente werden mit <%=
eingeleitet und mit %> abgeschlossen. Innerhalb eines Expression-Elements muss ein Ausdruck
stehen, zB: eine Berechnung oder ein Methodenaufruf mit Rückgabewert. In Abbildung 23 werden
Expression-Elemente verwendet, um das Ergebnis der Methode format und um die Zahlen 0 bis 9 in
einer Schleife auszugeben.
Kommentare in JSP werden in <%-- und --%> eingeschlossen, diese Kommentare kommen nur in der
JSP vor. Will man Kommentare auch im generierten Servlet wiederfinden, dann muss man sie als
normale Java-Kommentare in Scriptlets schreiben.
Weitere Befehle in JSP:





<jsp:include>: Einfügen einer anderen Seite zur Laufzeit.
<jsp:forward>: Weiterleiten an eine andere Seite.
<jsp:param>: Parameter an eine andere Seite weitergeben, die mit <jsp:include> oder
<jsp:forward> verwendet wird.
<jsp:useBean>: Verwenden von JavaBean-Komponenten in JSP. Syntax: <jsp:useBean
id="Instanzname" scope="Geltungsbereich" class="Klassenname"/>
<jsp:getProperty>, <jsp:setProperty>: Abfragen bzw. Setzen eines Bean-Properties.
© Markus Löberbauer 2010
Seite 49
Die JSP-Syntax der Skriptelemente mit dem Prozentzeichen passt nur schlecht zum XML-Stil von
HTML. Deshalb gibt es für die Skriptelemente eine XML-Syntax. Dabei heißen die Tags: <jsp:scriptlet>
für Scriptlets, <jsp:expression> für Ausdrücke und <jsp:declaration> für Deklarationen. Dabei ist zu
beachten, dass innerhalb einer Seite entweder konsequent die JSP-Syntax oder die XML-Syntax
verwendet werden muss. Einen Überblick über die gesamte Syntax von JSP kann man im JSR 152
oder unter http://java.sun.com/products/jsp/docs.html bekommen.
<%@page contentType="text/html" pageEncoding="UTF-8"
import="java.util.Date"%>
<html>
<head><title>JSP Expressions Page</title></head>
<body>
<%= format("Hello World!") %><br>
<%
for (int i = 0; i < 10; ++i) {
%>
<%= i %>
<%
}
%>
</body>
<%!
private static final String MESSAGE_FORMAT = "%s : %s";
%>
<%!
private String format(String message) {
return String.format(MESSAGE_FORMAT, new Date(), message);
}
%>
</html>
Fri Jun 04 08:42:31 CEST 2010 : Hello World!
0123456789
Abbildung 23) Beispiel-JSP mit Expressions
Implizite Objekte in JSP
In den Scriptlet-Beispielen haben wir mit out.println Text in die Web-Seite geschrieben. Aber wo
kommt dieses out her? In JSP werden einige Objekte in der Handler-Methode implizit zur Verfügung
gestellt:







out, Klasse: JspWriter (Schreiben von Text in die Web-Seite)
request, Klasse: HttpServletRequest
response, Klasse: HttpServletResponse
session, Klasse: HttpSession
application, Klasse: ServletContext
config, Klasse: ServletConfig
exception, Klasse: JspException (Nur verfügbar in Error-Pages. Treten Fehler in Servlets oder
JSP auf wird standardmäßig eine technische Fehlerseite erzeugt, die hilft dem Entwickler, für
den Anwender wirkt sie aber unprofessionell. Daher kann man in einer JSP page-Direktive
eine JSP angeben die im Fehlerfall angezeigt werden soll, zB:
<%@ page errorPage="/error.jsp" %>. Auch im Deployment Descriptor (web.xml) können mit
error-page-Abschnitten Fehlerbehandlungsseiten angegeben werden. Mit error-code können
© Markus Löberbauer 2010
Seite 50


http-Fehlercodes abgefangen werden (zB: 404); und mit exception-type können Exceptions
abgefangen werden.
pageContext, Klasse: PageContext (Kapselt die Impliziten Objekte, kann zB benutzt werden,
um diese an eine Methode zu übergeben.
page, Klasse: Object (Verweis auf das Seiten-Objekt = this-Pointer)
Expression Language
Skriptelemente verleiten dazu, zu viel Java-Code in JSP einzubetten, daher möchte man gerne auf
Skriptelemente verzichten. Die Verwendung von Beans ist aber häufig zu aufwändig oder zu
eingeschränkt. Aus diesen Gründen hat Sun mit JSP 2.0 die Expression Language (EL) eingeführt.
Ausdrücke in EL beginnen mit einem Dollar-Zeichen und sind in geschwungene Klammern
eingeschlossen, zB: ${42.0 / 23}, ${person.name} oder ${car.engine.power}.
EL erlaubt den Zugriff auf Properties von Properties, usw. Damit ist es mächtiger als die JSP-BeanSyntax. Und dabei wesentlich kompakter. Für jeden Property-Zugriff kommt ein Punkt gefolgt vom
Namen des Properties. Existiert in einer Klasse eine Methode getName(), dann heißt das Property
name. Der Zugriff erfolgt damit über ${objektname.name}. Der Aufbau von EL-Ausdrücken ist in
Abbildung 24 zu sehen.
${ersterBezeichner.weitereBezeichner}
Implizite Objekte Attribute aus
pageScope
requestScope
sessionScope
applicationScope
pageScope
requestScope
sessionScope
applicationScope
param
paramValues
Objekte werden zuerst
im Page-, dann im
Request-, dann im
Session- und wenn sie
dort auch nicht
gefunden werden im
Application-Scope
gesucht.
header
headerValues
cookie
initParam
Schlüssel einer Map
oder
Property
Muss sich an die Java
Namenskonvention halten!
pageContext
Abbildung 24) Aufbau eines EL-Ausdrucks
Muss man auf Elemente in einer Map oder Liste zugreifen, dann entsprechen die Zugriffsnamen nicht
nicht immer den Java-Namenskonventionen. In diesem Fall gibt es den Klammer-Operator ([]) als
Alternative zum Dot-Operator(„.“). Die Syntax sieht dann wie folgt aus: ${objektname[bezeichner]}
wobei objektname eine Map, ein Bean, eine List oder ein Array sein kann; bezeichner ist ein Schlüssel
© Markus Löberbauer 2010
Seite 51
in der Map, ein Property, ein Listen-Indey bzw. ein Array-Index. Der Zugriff kann auch verschachtelt
sein zB: ${cars[favoiritCars[0]]}.
Achtung, Property-Namen müssen unter Anführungszeichen gestellt werden, sonst wird der Name
selbst als Objekt gesucht, zB: der Ausdruck im Dot-Stil ${person.name} entspricht ${person["name"]}
im Klammer-Stil. Verwendet man nur ${person[name]}, dann wird zuerst name ausgewertet und das
Ergebnis als Property-Name in person gesucht.
Operationen in der Expression Language
Mit EL kann man arithmetische und logische Operationen ausdrücken: Addition (+), Subtraktion (-),
Multiplikation (*), Division (/, div) und Divisionsrest (%, mod) sowie logisches Und (&&, and), Oder
(||, or) und Nicht (!, not). Vergleiche durchführen: Gleichheit (==, eq), Ungleichheit (!=, ne), Kleiner
(<, lt), Grösser (>, gt), Kleiner gleich (<=, le) und Grösser gleich (>=, ge).
Die folgenden Literale sind in EL definiert: true, false, null, und empty (zeigt an ob ein Attribute
gesetzt ist, zB: ${not empty persons}. Das Schlüsselwort instanceof ist reserviert, hat aber noch keine
Bedeutung.
Java Standard Tag Libaray
Mit EL kann man einfach auf einzelne Werte zugreifen. Häufig benötigt man aber auch einfache
Kontrollstrukturen wie Iterationen oder Alternativen. Dazu kann die Java Standard Tab Jibrary (JSTL)
genutzt werden. Seit JSP 2.1 (JavaEE 5) ist die JSTL in Version 1.2 Teil der JavaEE-Spezifikation.
Damit man die JSTL in Tomcat nutzen kann muss man die Dateien jstl.jar und standard.jar entweder
in das lib-Verzeichnis von Tomcat oder seiner Web-Anwendung kopieren. Die Dateien sind in der
Standard-Installation von Tomcat in den Beispielanwendungen zu finden.
Die JSTL ist nach Aufgaben in die Bereiche Core, Formatierung, Funktionen, SQL Datenbank-Zugriff
und XML Verarbeitung geteilt. Wir werden kurzen Einblick auf den Core der JSTL geben; weitere
Informationen können im JSR-52 nachgelesen werden. Wichtige Tags der Core Tag Library sind:
<c:out>, <c:forEach>, <c:if>, <c:choose>, <c:when>, <c:otherwise>, <c:url> und <c:param>.
<c:out>
Mit dem Tag out kann man berechnete Ausgaben in die Webseite machen. Dabei wird null mit einem
gegebenen Default-Wert ersetzt, ist keiner gegeben mit dem leeren String. Interessant ist auch, dass
folgende HTML-Sonderzeichen ersetzt werden:





< gegen <
> gegen >
& gegen &
' gegen '
" gegen "
<c:forEach>
Mit dem forEach-Tag kann man über Sammlungen oder Zahlenbereiche iterieren, Abbildung 25 zeigt
eine Beispielanwendung. In der page-Direktive wird isELIgnored auf false gesetzt, das stellt sicher,
dass die EL-Ausdrücke richtig übersetzt werden. In Tomcat 6 und Glassfish 3 ist das bereits der
© Markus Löberbauer 2010
Seite 52
Standardwert. In der Beispielanwendung wird davon ausgegangen, dass eine Sammlung mit dem
Namen „Cars“ in einem der Scopes verfügbar ist.
<%@ page isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
Print all cars:
<c:forEach var="car" items="${Cars}">
${car}<br />
</c:forEach>
Print the numbers from 0 to 23 with a step of 5:
<c:forEach begin="0" end="23" step="5" varStatus="counter">
${counter.count}<br />
</c:forEach>
</body>
...
</html>
Abbildung 25) JSTL Beispiel mit <c:forEach>
<c:if>
Der Tag if wird eingesetzt wenn optionale Teile in einer JSP vorhanden sind, Abbildung 26 zeigt ein
Beispiel. Anders als in Programmiersprachen fehlt bei dem JSTL if-Tag ein else-Zweig, benötigt man
eine Auswahl aus mehreren Alternativen muss man entweder jede Alternative mit einem if-Tag
eindeutig beschreiben oder einen choose-Tag benutzen.
<%@ page isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"
<html>
<body>
<c:if test="${car eq 'Smart'}">
Be smart drive Smart!
</c:if>
<c:if test="${car eq 'SUV'}">
Real man drive hard!
</c:if>
</body>
...
</html>
%>
Abbildung 26) JSTL Beispiel mit <c:if>
<c:choose>, <c:when>, <c:otherwise>
Der choose-Tag entspricht der switch-Anweisung oder if-else-if-Kaskade in Programmiersprachen,
Abbildung 27 zeigt ein Beispiel.
© Markus Löberbauer 2010
Seite 53
<%@ page isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"
<html>
<body>
<c:choose>
<c:when test="${car eq 'Smart'}">
Be smart drive Smart!
</c:when>
<c:when test="${car eq 'SUV'}">
Real man drive hard!
</c:when>
<c:otherwise>
Porsche, all a lady can expect.
</c:otherwise>
</c:choose>
</body>
...
</html>
%>
Abbildung 27) JSTL Beispiel mit <c:choose>, <c:when> und <c:otherwise>
<c:url>, <c:param>
Mit <c:url> kann man Urls mit Parametern in JSP zusammensetzen, siehe Abbildung 28. Dieser Tag
ermöglicht Webanwendungen ohne Cookies, dazu fügt der url-Tag eine Session-ID als Parameter an
die Url, falls der Client keine Cookies unterstützt.
<%@ page isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
Please visit our
<a href="<c:url value='exhibition.do'>
<c:param name='color' value='${customer.favouritColor}' />
</c:url>"> car exhibition</a>
to see your next vehicle!
<a href="<c:url value='logout.jsp' />" >Logout</a>
</body>
</html>
Abbildung 28) JSTL Beispiel mit <c:url> und <c:param>
JSP aus Servlets Nutzen
In sauber entwickelten Programmen sollte die Businesslogik aus Servlets angesprochen werden und
die Oberfläche in JSP. Diese Vorgangsweise heißt in Java Model 2 Architektur und setzt das ModelView-Controller-Muster bei Webanwendungen um.
Über die Klasse javax.servlet.RequestDispatcher kann man von einem Servlet auf ein anderes Servlet
oder JSP umleiten. Einen RequestDispatcher kann man aus dem ServletContext über die Methode
getRequestDispatcher(String absolutPath) aus einem Absoluten Pfad holen. Hier darf auch ein Pfad in
das Verzeichnis WEB-INF zeigen, obwohl dieses Verzeichnis gegen Zugriffe von außen geschützt ist.
Oder über die Methode getNamedDispatcher(String name) aus einem Namen erzeugen, der Name
entspricht dem aus der web.xml (servlet-name). Relativ zum aktuellen Servlet kann man sich auch
aus dem ServletRequest über die Methode getRequestDispatcher(String path) einen
RequestDispatcher holen.
© Markus Löberbauer 2010
Seite 54
Hat man einen RequestDispatcher kann man den Request über die Methoden include oder forward
weiterleiten. Nutzt man die Methode include behält man die Kontrolle und kann nachdem das
gerufene Servlet fertig ist noch etwas ausgeben/aufräumen. Meistens ist das aber unnötig und man
verwendet forward, dabei gibt man die Kontrolle an das gerufene Servlet ab.
Die aufbereiteten Daten gibt man an das gerufene Servlet als Attribute im HttpServletRequest mit.
Attribute kann man in den Request über die Methode setAttribute(String name, Object o) stellen und
über getAttribute(String name) abfragen. In JSP kann man Attribute über EL abfragen, wobei man
den Namen des Attributes angeben muss, zB: ${name}.
Abbildung 29 zeigt ein Servlet, den Parameter name aus dem Request ausliest, den gelesenen Wert
in Großbuchstaben verwandelt, das Ergebnis als Attribut ablegt und den Request an eine JSP
weiterleitet. Wobei die JSP im Verzeichnis WEB-INF liegt und von außen nicht direkt aufgerufen
werden kann. Die zugehörige JSP ist in Abbildung 30 gezeigt.
@WebServlet(name = "Greeter", urlPatterns = {"/Greeter"})
public class Greeter extends HttpServlet {
public static final String NAME_PARAMETER = "name";
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
String name = request.getParameter(NAME_PARAMETER);
String upperCaseName = name != null ? name.toUpperCase() : "???";
request.setAttribute(NAME_PARAMETER, upperCaseName);
RequestDispatcher rd = getServletContext()
.getRequestDispatcher("/WEB-INF/jsp/namePrinter.jsp");
rd.forward(request, response);
}
}
Abbildung 29) Beispiel: Servlet mit Request-Weiterleitung
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8">
<title>Name Printer Page</title>
</head>
<body>
<h1>Hello <c:out value="${name}"/>!</h1>
</body>
</html>
Abbildung 30) Beispiel: JSP das einen Namen über EL und <c:out> ausgibt.
© Markus Löberbauer 2010
Seite 55
Schemadefinitionen für web.xml
Der Deployment Descriptor (web.xml) ist eine XML-Datei, hier sind die Rahmen für die gängigen
Versionen abgebildet. Version 2.3 wird noch über DTD beschrieben, d.h. die Elemente innerhalb der
web.xml müssen in der richtigen Reihenfolge angegeben werden, zB: servlet vor servlet-mapping.
Version 2.3
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<!-- ... -->
</web-app>
Version 2.4
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- ... -->
</web-app>
Version 2.5
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app version="2.5"
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-app_2_5.xsd">
<!-- ... -->
</web-app>
Version 3.0
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
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-app_3_0.xsd">
<!-- ... -->
</web-app>
© Markus Löberbauer 2010
Seite 56
Herunterladen