Praktikum aus Softwareentwicklung 2, Stunde 13 Lehrziele/Inhalt 1. JSP Custom Tags 2. Applets JSP Custom Tags EL und die JSTL ersetzen Scriptlets in weiten Teilen von Web-Anwendungen, manchmal braucht man aber Funktionen die in der JSTL fehlen. Da wir auf Scriptlets verzichten wollen, um die JSP-Seiten sauber zu halten brauchen wir eine Lösung eigenen Code in Tags zu packen. In JSP können wir dazu Custom Tags implementieren. Seit JSP 2.0 (zeitgleich mit Servlet API 2.4 und J2EE 1.4) gibt es mit Simple Tags und Tag Files bequeme Möglichkeiten eigene Tags zu erzeugen. Vor JSP 2.0 war es komplexer eigene Tags zu implementieren. Sollte es notwendig sein die alte API zu verwenden findet man dazu Dokumentation wenn man nach JSP classic Tags sucht. Tag Files Tag Files sind die einfachste Art eigene Tags zu erstellen. Mit Tag Files kann man Teile einer JSP-Seite auslagern, zB: Header oder Footer die auf allen Seiten einer Webanwendung gleich sind. Tag Files können Parametriert werden, zB: der Titel der Web-Seite im Header. Größere Text-/Html-Blöcke können als Tag-Body übergeben werden. Installiert werden Tag Files indem man sie im Verzeichnis WEB-INF/tags/ (oder einem Unterverzeichnis davon) ablegt, um sie zu nutzen muss man eine taglib-Direktive in die JSP-Seite einfügen. Über die taglib-Direktive muss angegeben werden welcher Präfix verwendet werden soll und wo die Tags abgelegt sind. In Abbildung 31 ist eine JSP-Seite zu sehen die Tag Files nutzt. In der taglib-Direktive ist angegeben, dass die Tags mit dem Präfix psw2tf angesprochen werden, und dass die Tags direkt im Verzeichnis WEB-INF/tags liegen. Das Beispiel nutzt die Tags header, footer und disclaimer. Mit dem Tag header wird der HTML-Seiten-Header eingebunden, er benötigt den Parameter title, dieser wird als Titel der Webseite ausgegeben. Parameter in einem Tag File werden mit der Direktive attribute bekannt gemacht. Die Implementierung ist in Abbildung 32 gegeben. Weiter nutzt die Seite den Tag footer der die Webseite abschließt (siehe Abbildung 33), er ist parameterlos. Und den Tag disclaimer (siehe Abbildung 34) der den übergebenen Body als Parameter verwendet und als Disclaimer-Text ausgibt. Will man Tag Files in mehreren Anwendungen verwenden lohnt es sich diese in eine JAR-Datei zu verpacken. Tag Files in JAR-Dateien müssen im Verzeichnis META-INF/tags/ (oder einem Unterverzeichnis davon) liegen und eine Beschreibung der Tags muss als Tag Library Descriptor vorliegen. Der Aufbau dieser Beschreibungen ist im Abschnitt Simple Tags beschrieben. © Markus Löberbauer 2010 Seite 57 <%@page contentType="text/html" pageEncoding="UTF-8"%> <%@taglib prefix="psw2tf" tagdir="/WEB-INF/tags/" %> <psw2tf:header title="Hello Page"/> <h1>Hello PSW2 Students!</h1> <p> Welcome to the shiny world of JSP programming. In this course you will learn everything you&#39;ll ever need! Hello PSW2 Students! </p> <psw2tf:disclaimer> to the shiny world of JSP programming. In Everything written on this page may be Welcome this course you will learn everything you'll ever exaggerated, or just plain wrong. need! </psw2tf:disclaimer> <psw2tf:footer /> Disclaimer Abbildung 31) JSP Seite mit Custom Tags aus Tag Files Everything written on this page may be exaggerated, or just plain wrong. <%@tag description="standard header tag for our web application" pageEncoding="UTF-8"%> <%@attribute name="title" required="true" description="title of the page" rtexprvalue="true"%> <!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>${title}</title> </head> <body> Abbildung 32) Beispiel Tag mit Parameter (Seiten-Header) <%@tag description="standard footer for our web application" pageEncoding="UTF-8"%> </body> </html> Abbildung 33) Beispiel Tag File ohne Parameter (Seiten-Footer) <%@tag description="web site disclaimer" pageEncoding="UTF-8"%> <p> Disclaimer<br> <em> <jsp:doBody /> </em> </p> Abbildung 34) Beispiel Tag File das den Body des Tags nutzt (Disclaimer). Simple Tags Tag Files vermeiden Code-Verdopplung in JSP-Seiten, aber wenn man Programmlogik braucht sind Tag Files zu wenig. Dann kommen Custom Tags ins Spiel. Die einfachste Möglichkeit Custom Tags zu programmieren sind Simple Tags. Jeder Simple Tag muss das Interface SimpleTag implementieren, in der Praxis leitet man dafür von der Klasse SimpleTagSupport ab. Die Klassen um Tags zu implementieren liegen im Paket javax.servlet.jsp.tagext. Damit der Web-Container die Tags findet muss man eine Tag Library Description (TLD) schreiben. © Markus Löberbauer 2010 Seite 58 Abbildung 35 zeigt eine JSP-Seite die Studenten, mit Hilfe des Custom Tags StudentFilter, anzeigt. Mit der Direktive taglib wird die Tag-Library in die Seite eingebunden. Abbildung 36 zeigt den Tag StudentFilterTag. <%@page contentType="text/html" pageEncoding="UTF-8"%> <%@taglib prefix="psw2tag" uri="http://ssw.jku.at/Teaching/Lectures/PSW2/2010/" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title>Students</title></head> <body> <h1>Active Students</h1> <ol> <psw2tag:StudentFilter activeOnly="true" students="${students}" var="student"> <li>${student.name}</li> </psw2tag:StudentFilter> </ol> <h1>All Students</h1> <ol> <psw2tag:StudentFilter students="${students}"> <li>${var.name}</li> </psw2tag:StudentFilter> </ol> </body> </html> Active Students 1. 2. Susi Brain Max Power All Students 1. 2. 3. 4. Susi Brain Jack Smart Max Power Anna Cool Abbildung 35) Beispiel-JSP-Seite mit Simple Tags public class StudentFilterTag extends SimpleTagSupport { private String controlVariable = "var"; private boolean activeOnly; private Iterable<Student> students; @Override public void doTag() throws JspException, IOException { JspFragment body = getJspBody(); if (body == null) { return; } JspContext context = getJspContext(); for (final Student student : students) { if (activeOnly && !student.isActive()) { continue; } context.setAttribute(controlVariable, student); body.invoke(null); } } public void setStudents(Iterable<Student> students) { this.students = students; } public void setActiveOnly(boolean activeOnly) { this.activeOnly = activeOnly; } public void setVar(String controlVariable) { this.controlVariable = controlVariable; } } Abbildung 36) Beispiel Simple Tag; Liefert die Studenten der Reihe nach, gefiltert nach Aktivität © Markus Löberbauer 2010 Seite 59 Simple Tags erben von SimpleTagSupport und überschreiben die Methode doTag, diese wird zum Rendern des Tags aufgerufen. Der Lebenszyklus eines Tags ist wie folgt: Der Web-Container lädt bei der ersten Verwendung eines Tags die Tag-Klasse und dann … 1. 2. 3. 4. 5. 6. 7. erzeugt ein Objekt des gewünschten Tags über den Default-Konstruktor setzt den Jsp-Context über setJSPContext setzt den Eltern-Tag, falls der Tag in einem anderen Tag geschachtelt ist setzt alle Attribute über die Setter-Methoden setzt den Body über setJSPBody, falls der Tag einen Body hat ruft die Methode doTag auf verwirft das Tag-Objekt Aus dem Lebenszyklus sehen wir, eine Tag-Klasse benötigt einen parameterlosen Default-Konstruktor und ein Tag-Objekt wird nur einmal benutzt, d.h. man kann sich darauf verlassen, dass die Attribute die richtigen Werte haben; und manuelle Bereinigung des inneren Zustands unnötig ist. <?xml version="1.0" encoding="UTF-8"?> <taglib version="2.1" 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"> <short-name>psw2tag</short-name> <tlib-version>1.0</tlib-version> <uri>http://ssw.jku.at/Teaching/Lectures/PSW2/2010/</uri> <tag> <name>StudentFilter</name> <tag-class> at.jku.ssw.psw2.jsptutorial.tag.StudentFilterTag </tag-class> <body-content>scriptless</body-content> <attribute> <name>students</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>java.util.Iterable</type> </attribute> <attribute> <name>activeOnly</name> <required>false</required> <rtexprvalue>true</rtexprvalue> <type>boolean</type> </attribute> <attribute> <name>var</name> <required>false</required> <rtexprvalue>true</rtexprvalue> <type>java.lang.String</type> <description>control variable</description> </attribute> </tag> </taglib> Abbildung 37) Tag Library Descriptor für den Beispiel-Tag StudentFilterTag © Markus Löberbauer 2010 Seite 60 Abbildung 37 zeigt den TLD für unseren StudentFilter, darin ist festgelegt welche Klasse für den Tag verwendet werden soll und welche Attribute der Tag hat. Ein TLD hat einen eindeutigen Namen (uri), eine Kurzbezeichnung (short-name), eine Version (tlib-version) und optionale Daten wie zB: eine Beschreibung (description) und ein Icon (icon). In einer TLD können beliebig viele Tags (tag) und Tag Files (tag-file) beschrieben werden. Abbildung 38 zeigt die Datenklasse Student für das Beispiel. Ein Student hat einen Namen und einen Status ob er aktiv ist. Abbildung 39 zeigt das Servlet mit der Anbindung an die Geschäftslogik und dem Aufruf der Seite showStudents.jsp. package at.jku.ssw.psw2.jsptutorial.model; public class Student { private final String name; private final boolean active; public Student (final String name, final boolean active) { this.name = name; this.active = active; } public String getName() { return name; } public boolean isActive() { return active; } } Abbildung 38) Beispiel-Datenklasse: Student public class ShowStudentsServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setAttribute("students", getStudents()); RequestDispatcher rd = request.getRequestDispatcher( "/WEB-INF/jsp/showStudents.jsp"); rd.forward(request, response); } private Iterable<Student> getStudents() { // read students, e.g. from a database // ... return students; } } Abbildung 39) Beispiel-Servlet: Liest Studenten und leitet an die Beispiel-JSP-Seite weiter © Markus Löberbauer 2010 Seite 61 Applets Mit Applets hat Sun die Möglichkeit geschaffen Java Programme in Webseiten einzubetten. Applets können mit AWT oder mit Swing entwickelt werden, dazu muss man eine Klasse von java.applet.Applet bzw. javax.swing.JApplet ableiten. Damit Applets auf dem lokalen Rechner keinen Schaden anrichten können werden sie in einer sicheren Umgebung (Sandbox) ausgeführt. Dadurch wird verhindert, dass: Applets auf das lokale Dateisystem zugreifen, Netzwerkverbindungen aufbauen, gefährliche System-Aufrufe ausführen (zB: System.exit), die Zwischenablage auslesen oder sicherheitskritische System-Properties abfragen. Benötigt man Zugriff auf diese sicherheitskritischen Dinge muss man sein Applet signieren, dann fragt Java den Benutzer ob er dem Applet die Zugriffe erlaubt. Der Lebenszyklus von Applets besteht aus vier Methodenaufrufen: 1. init, wird aufgerufen sobald das Applet geladen wird, hier kann zB: die GUI aufgebaut, Threads gestartet oder Ressourcen geladen werden 2. start, wird jedes Mal aufgerufen wenn das Applet angezeigt wird, zeigt ein Applet eine Animation, kann diese hier gestartet werden 3. stop, der Browser ruft diese Methode wenn das Applet nicht mehr angezeigt wird, hier kann die Animation wieder gestoppt werden 4. destroy, hier können Ressourcen freigegeben werden Wir beschäftigen uns hier mit der Swing-Version von Applets, und wie Swing allgemein sind auch JApplets nicht threadsicher. Das heißt, Änderungen an der GUI müssen im GUI-Thread erfolgen. Abbildung 40 zeigt eine JSP-Seite mit einem Applet, im Tag applet wird festgelegt wie groß das Applet sein soll, wo die Jar-Datei liegt und wie die Applet-Klasse heißt. Im Body des Applet-Tags können Parameter angegeben werden, in unserem Fall wird der Parameter name auf Alex gesetzt. Außerdem ist im Body ein Text hinterlegt der angezeigt werden soll falls der Browser nicht mit Applets umgehen kann. Die Zugehörige Applet-Klasse ist in Abbildung 41 gegeben. <%@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"> <html> <head> <title>Applet Test</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <applet width="200" height="150" code="at.jku.ssw.psw2.applet.TestApplet" codebase="<c:url value="/"/>" archive="TestApplet.jar"> <param name="name" value="Alex"/> Please enable Applets in your browser. </applet> </body> </html> Abbildung 40) Beispiel JSP-Seite mit Applet © Markus Löberbauer 2010 Seite 62 package at.jku.ssw.psw2.applet; public class TestApplet extends JApplet { private String name; private JLabel label; @Override public void init() { name = getParameter("name"); try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { label = new JLabel("Name: " + name); getContentPane().add(label, BorderLayout.CENTER); } }); } catch (Exception ex) { Logger.getLogger(TestApplet.class.getName()) .log(Level.SEVERE, null, ex); } // allocate resources here } @Override public void start() { // start animations here } @Override public void stop() { // stop animations here } @Override public void destroy() { // cleanup resources here } } Abbildung 41) Beispiel Applet, zeigt den Wert des Parameters "name" in einem Label an © Markus Löberbauer 2010 Seite 63