JSP Custom Tags sind spezielle JavaBeans, die gut in JSP-Seiten integriert werden können.
JSP Tag Libraries (Taglibs) sind Zusammenfassungen von JSP Custom Tags.
Vorteile von JSP Custom Tags:
+ | Vermeidung von Java-Sriptlets im JSP-Code |
+ | Erhöhung der Lesbarkeit des JSP-Codes |
+ | Leichtere Wiederverwendbarkeit |
+ | Trennung von Präsentations- und Logik-Code |
+ | Getrennte Entwicklung des Designs und der Logik (von verschiedenen Personen/Fachbereichen) |
+ | Erleichterung für den Webseitendesigner, da er keinen Java-Code mehr sieht, und Custom Tags von HTML-Design-Tools unterstützt werden (z.B. von Macromedia Dreamweaver) |
+ | Erleichterung für den Softwareentwickler, da die Entwicklung reinen Java-Codes besser von IDE unterstützt wird |
Custom Tags bestehen aus drei Teilen:
- Der JavaBean (compilierter Java-Code, entweder als '.class'- oder als '.jar'-Datei)
- Der TLD-Beschreibungsdatei (im Texteditor lesbare XML-Datei mit Endung '.tld')
- Den Codefragmenten zur Einbettung in der JSP-Datei
Die JavaBean ist von 'javax.servlet.jsp.tagext.TagSupport' oder '...BodyTagSupport' abgeleitet.
Sie muss für ihre Attribute die üblichen Getter- und Setter-Methoden anbieten.
In der Regel werden die Methoden 'doStartTag()', 'doAfterBody()' und 'doEndTag()' überschrieben.
Wichtig sind dabei die korrekten Rückgabewerte.
Die TLD-Datei (Tag Library Descriptor) definiert per XML den Tag-Namen, die Referenz auf die JavaBean, die möglichen Parameter und zusätzliche Eigenschaften des Tags und der Parameter.
Die JSP-Codefragmente müssen zuerst eine Referenz auf die TLD-Datei und einen Taglib-Präfix definieren
(<%@ taglib uri="..." prefix="..." %>).
Die Verwendung erfolgt dann über HTML-Tags mit dem Taglib-Präfix und dem Tag-Namen
(<meinetaglib:MeinCustomTag ... >).
In den Kapiteln 'Erstes eigenes Custom Tag' und 'Eigenes Custom Tag mit BodyTagSupport' erfahren Sie, wie Sie eigene Custom Tags programmieren können.
In den Kapiteln 'Erste Testanwendung für Apache Jakarta Taglibs (FTP, SMTP, SOAP)' und 'XML-Transformation mit XSL-Stylesheet per Apache Jakarta XTags' werden recht leistungsfähige Anwendungen einiger fertiger Apache Jakarta Taglibs gezeigt.
Der Einsatz von Struts-Taglib-Bibliotheken wird in jsp-struts.htm und jsp-struts-dynaval.htm demonstriert.
<taglib> <taglib-uri>http://jakarta.apache.org/taglibs/taglibs-io</taglib-uri> <taglib-location>/WEB-INF/taglibs-io.tld</taglib-location> </taglib> |
<%@ taglib uri="/WEB-INF/taglibs-io.tld" prefix="io" %> |
<%@ taglib uri="http://jakarta.apache.org/taglibs/taglibs-io" prefix="io" %> |
<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <%@ taglib uri="/WEB-INF/taglibs-benchmark.tld" prefix="benchmark" %> <%@ taglib uri="/WEB-INF/taglibs-datetime.tld" prefix="datetime" %> <%@ taglib uri="/WEB-INF/taglibs-io.tld" prefix="io" %> <%@ taglib uri="/WEB-INF/taglibs-mailer.tld" prefix="mailer" %> <html> <head> <title>Test einiger Jakarta Taglibs</title> </head> <body> <h2>Test einiger Jakarta Taglibs</h2> <h3>datetime:currentTime</h3> <datetime:format pattern="yyyy-MM-dd HH:mm"> <datetime:currentTime /> </datetime:format> h <h3>benchmark:duration</h3> <% out.flush(); %> <benchmark:duration> <% Thread.sleep( 500 ); %> </benchmark:duration> ms <h3>io:soap</h3> BabelFish-Übersetzung von "Hallo Welt, Guten Tag" --> <% out.flush(); %> <io:soap url="http://services.xmethods.net:80/perl/soaplite.cgi" SOAPAction="urn:xmethodsBabelFish#BabelFish"> <io:body> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <m:BabelFish xmlns:m="urn:xmethodsBabelFish"> <translationmode>de_en</translationmode> <sourcedata>Hallo Welt, Guten Tag</sourcedata> </m:BabelFish> </SOAP-ENV:Body> </SOAP-ENV:Envelope> </io:body> </io:soap> <h3>mailer:mail</h3> E-Mail senden (vorher gültige SMTP- und E-Mail-Adressen im Sourcecode einsetzen) <% out.flush(); %> <mailer:mail server="mail.gmx.net" from="MeinVorname.MeinNachname@gmx.de" to="ZielName@ZielDomain.de" subject="Test-E-Mail ueber taglibs-mailer"> <mailer:message>Mein E-Mail-Text</mailer:message> <mailer:send /> </mailer:mail> <h3>io:request ftp</h3> Text von FTP-Server einbinden (gültige FTP-Adresse im Sourcecode einsetzen): <% out.flush(); %> <pre> <io:request url="ftp://ftp.gnu.org/README" /> </pre> </body> </html>
In diesem Beispiel werden Daten aus einer XML-Datei ausgelesen, mit Hilfe eines XSL-Stylesheets in HTML-Code transformiert und als HTML-Tabelle in die JSP-Seite eingebettet.
Die Apache Jakarta XTags basieren auf XPath und sind wesentlich leistungsfähiger als dieses kurze Beispiel demonstrieren kann. Bitte lesen Sie die XTags-Doku unter http://jakarta.apache.org/taglibs/doc/xtags-doc.
<?xml version="1.0" encoding="ISO-8859-1"?> <Pizzen> <Pizza id="0007"> <Name>Pizza Diabolo</Name> <Zutaten>Teufelsohren, Krähenfüße</Zutaten> <Preis>17,89</Preis> </Pizza> <Pizza id="0815"> <Name>Pizza Feuro Vulkano</Name> <Zutaten>Peperoni, Vesuvtomaten</Zutaten> <Preis>9,87</Preis> </Pizza> <Pizza id="4711"> <Name>Pizza Eskimo</Name> <Zutaten>Käse, Eiswürfel</Zutaten> <Preis>4,77</Preis> </Pizza> </Pizzen>
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="Pizzen"> <table border="0" cellspacing="2" cellpadding="2"> <tr bgcolor="#E7EAEA"> <th>Nr.</th> <th>Name</th> <th>Zutaten</th> <th>Preis</th> </tr> <xsl:for-each select="Pizza"> <tr bgcolor="#F7FAFA"> <td> <xsl:value-of select="@id"/> </td> <td> <xsl:value-of select="Name"/> </td> <td> <xsl:value-of select="Zutaten"/> </td> <td align="right"> <xsl:value-of select="Preis"/> Euro </td> </tr> </xsl:for-each> </table> </xsl:template> </xsl:stylesheet>
<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <%@ taglib uri="/WEB-INF/taglibs-xtags.tld" prefix="xtags" %> <html> <head> <title>taglibs-xtags</title> </head> <body> <h3>taglibs-xtags</h3> <xtags:style xml="/xml/Pizzen.xml" xsl="/xml/Pizzen.xsl"/> </body> </html>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"> <taglib> <tlibversion>1.0</tlibversion> <jspversion>1.1</jspversion> <shortname>meine-test-taglib</shortname> <tag> <name>MeinCustomTag</name> <tagclass>mytaglibspackage.MeineCustomTagKlasse</tagclass> <bodycontent>jsp</bodycontent> <attribute> <name>numIterat</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib>
.tld | Tag Library Descriptor |
<taglib> | Umschließt alle zu dieser Taglib gehörenden Custom Tags |
<tag> | Die einzelnen Custom Tags (im Beispiel gibt es nur eins) |
<bodycontent> | 'JSP' bedeutet, dass das Tag sowohl JSP- als auch HTML-Code umschließen kann (Alternativen: 'tagdependent' (kein JSP-Code) / 'empty' (leerer Tag-Body)) |
<attribute> | Die dem Custom Tag übergebbaren Parameter |
<required> | 'true' / 'false' für Parameter ist notwendig / optional |
<rtexprvalue> | Runtime Expression Value, 'true' falls Attribut dynamisch z.B. durch JSP-Scriptlet gesetzt werden darf |
package mytaglibspackage; import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.tagext.TagSupport; public class MeineCustomTagKlasse extends TagSupport { private String numIterat; private int i; public String getNumIterat() { return numIterat; } public void setNumIterat( String numIterat ) { this.numIterat = numIterat; } public int doStartTag() throws JspTagException { try { i = Integer.parseInt( numIterat ); } catch( Exception ex ) { i = 0; } return ( 0 < i ) ? EVAL_BODY_INCLUDE : SKIP_BODY; } public int doAfterBody() throws JspTagException { return ( 0 < --i ) ? EVAL_BODY_AGAIN : SKIP_BODY; } public int doEndTag() throws JspTagException { return EVAL_PAGE; } }
cls set CLASSPATH=.;..\..\classes;..\..\..\..\..\common\lib\servlet-api.jar javac -d ..\..\classes *.java
<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <%@ taglib uri="/WEB-INF/meine-test-taglib.tld" prefix="meinetaglib" %> <html> <head> <title>Test meines ersten Custom Tags</title> </head> <body> <h3>Test meines ersten Custom Tags</h3> <meinetaglib:MeinCustomTag numIterat="bla"> Dieser Text im Tag-Body wird nicht angezeigt.<br> </meinetaglib:MeinCustomTag> <br> <meinetaglib:MeinCustomTag numIterat="3"> Dieser Text im Tag-Body wird 3 x angezeigt.<br> </meinetaglib:MeinCustomTag> <br> <meinetaglib:MeinCustomTag numIterat="5"> Dieser Text im Tag-Body wird 5 x angezeigt.<br> </meinetaglib:MeinCustomTag> </body> </html>
Im letzten Beispiel war kein Zugriff auf den durch das Custom Tag eingeschlossenen Text möglich. Es konnte lediglich über den Returnwert gesteuert werden, ob der Body-Teil ausgeführt werden soll.
Im folgenden Beispiel wird die JavaBean statt von 'TagSupport' von 'BodyTagSupport' abgeleitet. Dann kann über 'getBodyContent()' der Body-Text gelesen werden und über 'getEnclosingWriter().write()' verändert ausgegeben werden.
package mytaglibspackage; import java.io.IOException; import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.tagext.BodyContent; import javax.servlet.jsp.tagext.BodyTagSupport; public class MeineCustomTagKlasse extends BodyTagSupport { private String numIterat; private int i, j; public String getNumIterat() { return numIterat; } public void setNumIterat( String numIterat ) { this.numIterat = numIterat; } public int doStartTag() throws JspTagException { i = j = 0; try { i = Integer.parseInt( numIterat ); } catch( Exception ex ) { } return ( 0 < i ) ? EVAL_BODY_BUFFERED : SKIP_BODY; } public int doAfterBody() throws JspTagException { try { BodyContent bc = getBodyContent(); if( null != bc ) { String s = "" + ++j + ". Iteration: " + bc.getString(); bc.clearBody(); bc.getEnclosingWriter().write( s ); } return ( 0 < --i ) ? EVAL_BODY_AGAIN : SKIP_BODY; } catch( IOException ex ) { return SKIP_BODY; } } public int doEndTag() throws JspTagException { return EVAL_PAGE; } }
Zum Taglib-Einsatz unter Struts siehe jsp-struts.htm und jsp-struts-dynaval.htm.