javabog.dk  |  << forrige  |  indhold  |  næste >>  |  programeksempler  |  om bogen

6 JSTL - JSP Standard Tag Library


6.1 Kernefunktionalitet (<c: >) 117

6.1.1 Regneudtryk med EL - Expression Language 118

6.1.2 Variabler 118

6.1.3 Virkefelter 119

6.1.4 Sikkerhed og behandling af formularer 119

6.1.5 Løkker 120

6.1.6 Oversigt 121

6.2 Internationalisering og formatering (<fmt: >) 122

6.2.1 Oversigt 122

6.2.2 Eksempel på brug 123

6.3 JSTL og databaser (<sql: >) 124

6.3.1 Oversigt 125

6.4 XML-behandling (<x: >) 125

6.4.1 Syndikering med XML-funktionerne i JSTL 125

6.4.2 Caching af nyhedskilder 127

6.4.3 WebRowSet og XML-transformering med JSTL 127

6.4.4 Oversigt 129

6.5 Forskellige funktioner (<fn: >) 129

6.5.1 Oversigt 130

6.6 Installation af JSTL og EL 130

6.6.1 Versionsproblemer med JSTL og EL 131

6.7 JSTL versus almindelig javakode i JSP 132

6.8 Kommunikation mellem JSTL og Java 132

6.8.1 Javabønner 133

6.8.2 Implicit definerede objekter i EL 133

6.9 Mere læsning 133

Dette kapitel er frivillig læsning; det forudsættes ikke i resten af bogen.

Det forudsætter kapitel 4, Videre med JSP, men inddrager eksempler fra mange kapitler både før og efter dette kapitel. Det anbefales derfor at du springer let hen over det du ikke forstår og vender tilbage senere.

Med JSP 2.0, der udkom primo 2004, blev det for alvor muligt, at programmere JSP-sider i programmeringssproget JSTL (JSP Standard Tag Library) og bruge regneudtryk i disse sider (EL - Expression Language).

JSTL er et HTML-lignende sprog, som man kan skrive koden, der udføres på serveren i, i stedet for Java. For ikke-Java-kyndige HTML-designere skulle JSTL være betydeligt simplere at bruge end Java, da syntaksen ligner den, de i forvejen kender fra HTML1.

Selvom denne bogs 'hovedsprog' er Java og ikke JSTL, kan du vælge at lære JSTL. Dette kan du gøre ved at læse de andre kapitler og i stedet for at udføre Java-eksemplerne, kigge på og lege med JSTL-eksemplerne i dette kapitel.

Et tag library (forkortet taglib) er, som navnet siger, et bibliotek af HTML-lignende koder. Ligesom JSP-koderne udføres taglib-koderne på serveren.

6.1 Kernefunktionalitet (<c: >)

Kernefunktioner (de mest basale funktioner) i JSTL ligger i core-taglibbet under navnet 'c'. Her er understøttelse for variabler, betingelser, URL-styring og andre ting.

Her er eksemplet Alder fra afsnit 2.2 skrevet i JSTL-syntaks:

<!-- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> -->
<html>
<head><title>Alder med JSTL</title></head>
<body>
<p>
<c:set var="alder" value="31" />
Søren er ${alder} år gammel.
Det svarer til ${12*alder} måneder.<br>

<c:set var="alder" value="3" />
Julie er ${alder} år gammel. 

<c:set var="alder" value="${alder*365}" />
Det svarer cirka til ${12*alder} dage.<br>
</p>
</body>
</html>

Vi starter med at importere core-taglibbet:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

I eksemplet ovenfor har vi sat det ind i en HTML-kommentar <!-- -->. Det er strengt taget ikke nødvendigt, men sørger for, at de fleste HTML-redigeringsværktøjer (som f.eks. Netscape/Mozilla Composer) lader koden stå urørt, selvom de ikke står i JSP-kode. Almindelig javakode mellem <% og %> går ellers ofte går tabt.

Nu kan vi bruge core-biblioteket under præfikset "c" i JSP-siden, f.eks. til at sætte en variabel til en værdi:

<c:set var="alder" value="31" />

I modsætning til Java behøver man ikke definere typen af en variabel, før man bruger den.

6.1.1 Regneudtryk med EL - Expression Language

Værdier fra variabler og regneudtryk skal i JSTL puttes ind i et ${}-udtryk, som er en måde at gøre brug af EL - Expression Language. Med JSP 2.0 kan evaluering af ${}-udtryk ske uden for JSTL, sådan at de bliver evalueret, når de står direkte i HTML-koden:

Det svarer til ${12*alder} måneder.<br>

I tidligere udgaver kunne EL-udtryk kun stå inde i JSTL-koder, så man måtte skrive dem ind i f.eks. en <c:out />:

Det svarer til <c:out value="${12*alder}" /> måneder.<br>

Der kan stadig nogle enkelte steder være grund til at bruge <c:out />, nemlig hvis man ønsker at undgå, at værdien kan fortolkes som HTML-kode (se afsnit 8.5.1, HTML-injektion og afsnit 6.1.4, Sikkerhed og behandling af formularer).

EL er et elegant sprog, der gør det muligt, at skrive ret lange Java-udtryk på kort form.

Således kan knudrede Java-udtryk, som f.eks.:

Velkommen <%= ((Bruger)session.getAttribute("bruger")).getNavn() %> !

med EL skrives som blot:

Velkommen ${session.bruger.navn} !

Det skyldes, at EL har en meget fleksibel punktum-notation, der automatisk undersøger egenskaber på javabønner og gennemsøger attributter på implicitte objekter og andre nøgleindekserede objekter (hashtabeller).

6.1.2 Variabler

Variabler kan sættes med:

<c:set var="fornavn" value="Jacob"/>

der sætter variablen 'fornavn' til "Jacob". Findes variablen ikke, oprettes den.

En anden mulighed er, at sætte værdien ind i :

<c:set var="fornavn">
  Jacob
</c:set>

6.1.3 Virkefelter

Som udgangspunkt har variabler kun siden som virkefelt (scope="page"), så de smides væk, når forespørgslen er færdigbehandlet. Man kan specificere et andet virkefelt med f.eks.:

<c:set var="fornavn" value="Jacob" scope="session"/>

hvorefter variablen vil blive husket, så længe brugerens session eksisterer.

De mulige virkefelter er: page, request, session og application. Et (realistisk) eksempel på brug af virkefelter kan ses i slutningen af afsnit 6.4.2.

Vil man fjerne en variabel, kan det gøres med f.eks.:

<c:remove var="navn" scope="session"/>

6.1.4 Sikkerhed og behandling af formularer

JSTL har med EL nogle ganske kraftige mekanismer til at arbejde med formulardata.

Her eksemplet fra afsnit 3.2.5 (der udskriver alle parametrene, der er overført fra formularen i afsnit 3.2.4), skrevet i JSTL:

<!-- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> -->
<html>
<head><title>Parametre3 med JSTL</title></head>
<body>

<p>
Her er parameteren "navn": <c:out value="${param['navn']}"/><br>
Parameteren på en anden måde: <c:out value="${param.navn}"/><br>
</p>

<p>
Andre parametre:<br>
<c:forEach var="parametren" items="${param}">
  <c:out value="${parametren.key}"/>
  med værdi: '<c:out value="${parametren.value}"/>'.
 <br>
</c:forEach>
</p>

<p>
Parameteren 'kan_spise' har flere værdier.<br>
De er:
<c:forEach var="vaerdi" items="${paramValues['kan_spise']}">
  <c:out value="${vaerdi}"/>
</c:forEach>
</p>

</body>
</html>

Læg mærke til, at vi her bruger af <c:out /> for at skrive ud:

Parameteren på en anden måde: <c:out value="${param.navn}"/><br>

Ved at bruge <c:out /> bliver specielle tegn som <, >, &, ' og " erstattet af deres HTML-entiteter (d.v.s. &lt;, &gt;, &amp; o.s.v.).

Vi kunne godt bruge et EL-udtryk direkte i HTML-koden, som vi plejer:

Parameteren på en anden måde: ${param.navn}<br>

men da ville indholdet af navn-parameteren kunne fortolkes som HTML-kode med de problemer, det medfører (se afsnit 8.5.1, HTML-injektion).

Det er derfor en rigtig god idé, at udnytte JSTLs indbyggede sikkerhedsfunktioner og altid bruge <c:out />, hver gang man udskriver data, der kommer fra brugeren.

Hvis man ønsker at bruge <c:out /> uden denne sikkerhedsfunktion (specielle tegn bliver erstattet med deres HTML-entiteter) kan det slås fra med attributten escapeXml="false":

Parameteren på en anden måde: <c:out value="${param.navn}" escapeXml="false"/><br>

6.1.5 Løkker

Her er eksemplet Syvtabellen fra afsnit 2.2.1 skrevet i JSTL-syntaks:

<!-- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> -->
<html>
<head><title>Syvtabellen med JSTL</title></head>
<body>
<p>Her er syv-tabellen:<br>

<c:forEach var="i" begin="1" end="10">
  Syv gange ${i} er: ${7*i}.<br>
</c:forEach>

</p>
</body>
</html>


Man kan også gennemløbe andet end tal. I afsnit 6.1.4 findes et eksempel hvor alle parametrene gennemløbes.

Herunder løber vi gennem nogle strenge med navne på frugter:

<!-- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> -->
<html>
<head><title>Løkker med JSTL</title></head>
<body>
<p>Her er nogle frugter:<br>

  <c:forEach var="f" items="æble,pære,banan,blomme">
    En frugt: ${f}<br>
  </c:forEach>

</p>
</body>
</html>

6.1.6 Oversigt

Her er en oversigt over alle koderne i dette core-tagbiblioteket.

<c:set

Sætter/opretter en variabel til et udtryk. Virkefelt kan angives med scope=... der kan være page, request, session eller application.

<c:remove

Fjerner en variabel (fra et bestemt virkefelt hvis scope=... er angivet).

<c:out

Udskriver et udtryk/en variabel. Det svarer altså til <%= ... >, blot erstattes alle specielle tegn med HTML-entiteter (kan slås fra med escapeXml="false")

<c:import url=...

Henter indholdet af en absolut eller relativ URL og putter ind i siden eller i en variabel hvis var=... og scope=... er angivet.

<c:param name=...

(inde i <c:import>)

Tilføjer parameter til en <c:import>-forespørgsel.

<c:redirect url=...

Omdirigerer til en anden URL.

<c:url

Definerer en URL.

<c:if test=...

Betingelse. Kroppen udføres, hvis betingelsen er opfyldt.

<c:choose

Vælger mellem et antal alternativer, mærket med <when> og <otherwise>

<c:when test=...

(inde i <c:choose>)

Kroppen udføres, hvis betingelsen er opfyldt.

<c:otherwise

(inde i <c:choose>)

Kroppen udføres, hvis ingen af betingelserne i <c:when var opfyldt.

<c:forEach

Gennemløber noget.

<c:forTokens items=... delims=...

Opdeler en streng (items=) i bidder efter nogle skilletegn (delims=) og gennemløber bidderne.

<c:catch

Fanger alle undtagelser, der sker mellem <c:catch> og </c:catch>.
Med <c:catch var=...> kan undtagelsen gemmes i en variabel.

6.2 Internationalisering og formatering (<fmt: >)

JSTL har en lang række funktioner til at parse og formatere tal og datoer. De ligger i taglib-bet fmt, som importeres med:

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>

6.2.1 Oversigt

Her er en oversigt over alle koderne i dette tagbibliotek.

<fmt:requestEncoding value=...

Sætter tegnsætter for anmodningen.

<fmt:setLocale value=...

Sætter sproget sådan, at formateringer sker efter dette sprog (f.eks.: value="da_DK")

<fmt:timeZone value=...

Sætter tidszonen for alle operationen i kroppen

<fmt:setTimeZone value=...

Sætter tidszonen globalt

<fmt:bundle basename=...

Indlæser et resursebundt, der kan bruges i kroppen.

<fmt:setBundle basename=...

Indlæser et resursebundt globalt.

<fmt:message key=...

Slår op i resursebundt og formaterer og udskriver resultatet

<fmt:param>

(inde i <fmt:message>)

Supplerer et opslag med <fmt:message> med et argument

<fmt:formatNumber

Formaterer et tal

<fmt:parseNumber

Fortolker en streng som et tal

<fmt:formatDate value=...

Formaterer en dato/tid

<fmt:parseDate

Fortolker en streng som en dato/tid

6.2.2 Eksempel på brug

Her er et eksempel på, hvordan man arbejder med datoer:

<!-- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 
     <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> -->
<html>
<head><title>Dato med JSTL</title></head>
<body>
<p>
  Det er lige nu: 
  <jsp:useBean id="tid" class="java.util.Date" />
  <c:set var="t" value="${tid.hours}" />
  <c:choose>
    <c:when test="${t <= 9}">morgen</c:when>
    <c:when test="${t <= 12}">formiddag</c:when>
    <c:when test="${t <= 17}">eftermiddag</c:when>
    <c:when test="${t <= 21}">aften</c:when>
    <c:otherwise>nat</c:otherwise>
  </c:choose>
</p>

<p>
  Datoen formateret: <fmt:formatDate value="${tid}" /><br>
  Datoen uformateret: ${tid}<br>
</p>
</body>
</html>

Sammenlign med eksemplet i afsnit 2.3.

Først opretter vi et Date-objekt og knytter det til variablen 'tid':

  <jsp:useBean id="tid" class="java.util.Date" />

I almindelig JSP ville man skrive 'new Date()'. Den specielle måde med <jsp:useBean /> diskuteres i afsnit 6.8, Kommunikation mellem JSTL og Java):

Så aflæser vi, hvad klokken er med ${tid.hours} (svarer til 'tid.getHours()' i almindelig JSP) og sætter resultatet ind i variablen 't':

  <c:set var="t" value="${tid.hours}" />

Derefter vælges mellem et sæt alternativer (svarer til en switch-sætning eller en række kædede if-sætninger i almindelig JSP):

  <c:choose>
    <c:when test="${t <= 9}">morgen</c:when>

Til sidst udskriver vi tiden formateret med

<fmt:formatDate value="${tid}" />

6.3 JSTL og databaser (<sql: >)

JSTL har nogle meget effektive kommandoer til databasekommunikation. De importeres med:

<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql"%>

For at få adgang til en database fra JSTL, kan databasedriveren og -URLen angives i siden sammen med JSP-koden:

<sql:setDataSource url="jdbc:mysql:///test" driver="com.mysql.jdbc.Driver" />

Det er dog langt bedre, at angive det i web.xml under intialiseringsparameteren med navn 'javax.servlet.jsp.jstl.sql.dataSource':

  <context-param>
    <param-name>javax.servlet.jsp.jstl.sql.dataSource</param-name>
    <param-value>jdbc:mysql:///test,com.mysql.jdbc.Driver</param-value>
  </context-param>

Herunder har vi angivet "jdbc:mysql:///test" og "com.mysql.jdbc.Driver". Hvis man ville angive brugernavn og adgangskode, f.eks. 'j' og 'hemli' skulle parameteren have været:

    <param-value>jdbc:mysql:///test,com.mysql.jdbc.Driver,j,hemli</param-value>      

Her ses et eksempel på brug:

<%-- Anvend JSTLs core- og database-tagbibliotek --%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql"%>

<html>
<head><title>Databasearbejde med JSTL</title></head>
<body>

<%-- datakilde angives i web.xml, men kan også direkte på siden (kun til test):
<sql:setDataSource url="jdbc:mysql:///test" driver="com.mysql.jdbc.Driver" /> --%>

<%-- lav en forespørgsel --%>
<sql:query var="kunder" sql="SELECT * FROM kunder" />

<table border="1" cellpadding="2" cellspacing="0">
  <tr>
    <th>Navn</th>
    <th>Kredit</th>
  </tr>

  <%-- Gå gennem alle kunderne --%>
  <c:forEach var="kunde" begin="0" items="${kunder.rows}">
    <tr>
      <td>${kunde.navn}</td>
      <td>${kunde.kredit}</td>
    </tr>
  </c:forEach>
</table>

</body>
</html>

6.3.1 Oversigt

Her er en oversigt over alle koderne i sql-tagbiblioteket.

<sql:transaction

Udfører alt kode i kroppen som én databasetransaktion

<sql:query

Udfører SQL-forespørgslen i kroppen eller i attributten sql=...

<sql:update

Udfører SQL-sætningen i kroppen eller i attributten sql=...

<sql:param

Sætter en parameter i en SQL-sætning.

<sql:dateParam

Sætter en parameter i en SQL-sætning (for Date-objekter).

<sql:setDataSource

Sætter database-URLen (kun til udvikling, ikke egnet til drift)

6.4 XML-behandling (<x: >)

JSTL har fin understøttelse for behandling af XML-data. De har præfikset 'x' og importeres med:

<%@ taglib uri="http://java.sun.com/jsp/jstl/xml" prefix="x"%>

6.4.1 Syndikering med XML-funktionerne i JSTL

Dette afsnit forudsætter, at du har læst afsnit 11.3, Syndikering (nyhedsfødning).

Indholdssyndikering (fødning af nyheder fra andre websider ind i ens egne) er beskrevet i afsnit 11.3. Man kan udnytte JSTLs XML-funktioner til at flette andres RSS-filer med nyheder ind i ens egne sider.

Herunder et eksempel, hvor vi fletter vi nyheder fra Danmarks Radio ind.

Først importeres core- og XML-taglibbet. Derefter hentes en ekstern webside med nyhederne med <c:import>, der efter parses som XML med <x:parse> og lægges i variablen rss.

Denne variabel bruges derefter til, at navigere rundt i DOM-træet og med passende XPath-udtryk gennemløbe elementer med <x:forEach> og udskrive elementer med <x:out>.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/xml" prefix="x"%>
<html>
<head><title>Syndikering med JSTL og XML</title></head>
<body>

<c:import var="rssKilde" url="http://www.dr.dk/nyheder/html/nyheder/rss/"/>
<x:parse var="rss" doc="${rssKilde}"/>

<h1>
  <x:out select="$rss//*[name()='channel']/*[name()='title'][1]"/>
</h1>
<x:out select="$rss//*[name()='channel']/*[name()='description'][1]"/>
<br>
Læs flere nyheder 
<a href="<x:out select="$rss//*[name()='channel']/*[name()='link'][1]"/>">her</a>

<ul>
  <x:forEach select="$rss//*[name()='item']">
    <li>
      <x:out select="./*[name()='title']"/><br>
      <font size="-1">
        <x:out select="./*[name()='description']" escapeXml="false" />
        <a href="<x:out select="./*[name()='link']"/>">læs mere</a><br><br>
      </font>
    </li>
  </x:forEach>
</ul>

</body>
</html>

6.4.2 Caching af nyhedskilder

Kommandoerne

<c:import var="rssKilde" url="http://www.dr.dk/nyheder/html/nyheder/rss/"/>
<x:parse var="rss" doc="${rssKilde}"/>

henter nyhederne fra DR og fortolker XML-koden, hver gang der spørges på siden.

Ved mange forespørgsler kan dette føre til lange svartider og unødig stor belastning af nyhedskilden. Det kunne derfor være en idé, at cache det fortolkede XML-dokument i f.eks. en time.

I JSTL kan det gøres ved at gemme det fortolkede dokument i application-objektet sammen med en tidsstempel. Ved en anmodning, kontrolleres det, om der er gået mere end en time (3600000 millisekunder) og kun da hentes XML-dokumentet fra serveren:

<jsp:useBean id="nu" class="java.util.Date"/>
<c:if test="${nu.time > cachetid-3600000}">
  <c:import var="rssKilde" url="http://www.dr.dk/nyheder/html/nyheder/rss/"/>
  <x:parse var="rss" doc="${rssKilde}" scope="application"/>
  <c:set var="cachetid" value="${nu.time}" scope="application"/>
</c:if>

6.4.3 WebRowSet og XML-transformering med JSTL

Lad os nu se på, hvordan man kunne transformere et XML-dokument om til HTML.

I afsnit 5.9.4 så vi, hvordan et WebRowSet-objekt kunne repræsenterer et sæt rækker fra en database som XML. I det følgende eksempel indlæses og behandles dette XML-dokument, for at producere en HTML-side med kunderne:

Her hentes først data i et WebRowSet, der skrives ned i variablen kundeXml, der er oprettet med <jsp:useBean>, så den både er tilgængelig for almindelig Javakode og for JSTL (j.v.f. afsnit 6.8, Kommunikation mellem JSTL og Java). Derefter parses den med <x:parse> og gennemløbes og alle rækkerne udskrives.

<%@ page language="java" import="java.sql.*, javax.sql.*, com.sun.rowset.*" %>
<%-- Bemærk: rowset.jar fra Sun skal være i CLASSPATH --%>

<%-- Anvend JSTLs core- og XML-tagbibliotek --%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/xml" prefix="x"%>

<html>
<head><title>XML-transformering af WebRowSet med JSTL</title></head>
<body>
<%
  Class.forName("com.mysql.jdbc.Driver");
  Connection con = DriverManager.getConnection("jdbc:mysql:///test");
  Statement stmt = con.createStatement();
  ResultSet rs = stmt.executeQuery("SELECT * FROM kunder");

  // Oprettelse fejler nogen gange første gang (uvist hvorfor)
  try { new WebRowSetImpl(); } catch (Exception e) { } // ignorér fejlen
  WebRowSetImpl wrs = new WebRowSetImpl();

  //anden mulig løsning, se  http://forum.java.sun.com/thread.jspa?threadID=540624&tstart=270 (xxx ikke afprøvet)
  //java.util.Locale loc =  Locale.getDefault();
  //java.util.Locale.setDefault(Locale.US);
  //WebRowSetImpl wrs = new WebRowSetImpl();
  //java.util.Locale.setDefault(loc);

  wrs.populate(rs);
  rs.close();
  // wrs.writeXml(System.out); // Skriv evt XML i webserverens logfil
%>

<%-- Skriv XML-streng til variablen kundeXml --%>
<jsp:useBean id="kundeXml" class="java.io.StringWriter" />
<% wrs.writeXml(kundeXml); %>

<%-- Fortolk XML-streng og put det parsede DOM-træ ind i kunder. 
     Vi får data ud at kundeXml (der er af typen StringWriter) til en streng
     ved at sætte den sammen med streng " " (ét mellemrum): "${kundeXml} " --%>
<x:parse var="kunder" doc="${kundeXml} "/>

<h1>Liste over kunder (XML-transformeret WebRowSet)</h1>

<%-- Løb gennem alle rækkerne i tabellen og udskriv 1. og 2. kolonne --%>
<x:forEach select="$kunder//*[name()='currentRow']">
  Navn: <x:out select="*[1]"/><br>
  Kredit: <x:out select="*[2]"/><br>
  <hr>
</x:forEach>

Her er hele XML-dokumentet:
<pre>
<c:out value="${kundeXml}" />
</pre>

</body>
</html>

6.4.4 Oversigt

Her er en oversigt over alle koderne i XML-tagbiblioteket:

<x:parse

Parser et XML-dokument, der kommer i kroppen eller som attributten 'source'.

<x:set

Sætter en variabel til resultatet af et XPath-udtryk

<x:out

Udskriver noget, ligesom <%= ... >, men evaluerer XPath-udtryk.

<x:forEach

Gennemløber et XPath-udtryk.

<x:if test=...

Betingelse. Kroppen udføres, hvis XPath-udtrykket evaluerer til 'true'

<x:choose

Vælger mellem et antal alternativer, mærket med <when> og <otherwise>

<x:when test=...
(inde i <x:choose>)

Kroppen udføres, hvis betingelsen er opfyldt.

<x:otherwise
(i <x:choose>)

Kroppen udføres, hvis ingen af betingelserne i <c:when> var opfyldt.

<x:transform

Transformerer et XML-dokument med et XSLT stylesheet

<x:param
(i <x:transform>)

Tilføjer parameter til en <x:transform>-operation

6.5 Forskellige funktioner (<fn: >)

En række forskellige funktioner til at arbejde med strenge, kan importeres med:

<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>

Derefter kan man skrive fn:funktionsnavn(...) inde i et EL-udtryk, for at kalde funktionen.

F.eks. kunne man i forrige eksempel skrive kundenavnet med store bogstaver med:

      <td>${fn:toUpperCase(kunde.navn)}</td>

Man kunne i afsnit 6.1.4 udskrive længden af parameteren navn med:

Længden af parameteren navn: ${fn:length(param.navn)}

eller måske kontrollere længden af det indtastede navn:

<c:if test="${fn:length(param.navn) < 2}" >
  Du skal indtaste et navn på mindst to tegn
</c:if>

6.5.1 Oversigt

Her er en oversigt over funktionerne:

length( objekt )

Finder længden af objektet.
Er objektet en streng, giver det antallet af tegn.
Er objektet et array eller en anden datastruktur (collection), giver det antallet af elementer.

contains( streng, delstreng )
containsIgnoreCase( streng, delstreng )
startsWith( streng, delstreng )
endsWith( streng, delstreng )

Undersøger om en streng indeholder en delstreng.

escapeXml( streng )

Erstatter specielle tegn med deres HTML-entitet sådan, at tegn i strengen ikke kan (mis)fortolkes som HTML-kode.

indexOf( streng, delstreng )

Finder indekset (placeringen) i en streng af en delstreng.

join( streng[], mellemstreng )

Sætter et array af strenge sammen til én streng.

replace( streng, førstr, efterstr )

Giver en streng, hvor alle forekomster af delstrengen førstr er erstattet med strengen efterstr.

split( streng, separatorstreng )

Opdeler en streng i et array af delstrenge.

substring( streng, startpos, slutpos )

Giver delstrengen fra startpos til og med slutpos.

substringBefore( streng, delstreng )

substringAfter( streng, delstreng )

Giver den del af strengen der er før (hhv. efter) delstrengen.

toUpperCase( streng )

toLowerCase( streng )

Giver en streng hvor alle tegn er lavet om til store (hhv. små) bogstaver.

trim( streng )

Fjerner blanktegn fra begge ender af strengen.

6.6 Installation af JSTL og EL

For at webserveren kender taglibbet, skal JAR-filerne jstl.jar og standard.jar være tilgængelig for webapplikationen, f.eks. ved at de ligger i WEB-INF/lib/.

Du kan f.eks. kopiere dem fra webapps/jsp-examples/WEB-INF/lib/ i JSP-eksemplerne, der fulgte med i Tomcat.

Hvis du har problemer, så se i afsnit 4.9.6, hvordan du kan lægge JAR-filerne ind.

6.6.1 Versionsproblemer med JSTL og EL

JSTL og EL har udviklet sig lidt knudret: Fra at være bygget sammen til at være adskilte ting, der kan bruges uafhængigt af hinanden. Nu (med JSP 2.0) er EL bygget direkte ind i webserveren, mens JSTL er en JAR-fil, der skal være tilgængelig for webapplikationen. Derfor kan man komme ud for en del bøvl med JSTL og EL i nogle kombinationer.

Man skal her være opmærksom på, at ens web.xml-fil kan være afgørende for, om tingene virker som forventet, idet web.xml i version 2.3 som udgangspunkt ikke understøtter EL, mens version 2.4 gør.

Har man en web.xml i version 2.3, kan det være at man er nødt til at skrive EL-udtryk ud med JSTL-koden <c:out />:

Det svarer til <c:out value="${12*alder}" /> måneder.<br>

Det bedste er at opgradere sin web.xml-fil. Her ses starten af en web.xml-fil i version 2.3 (der får webserveren til kun at fortolke EL-udtryk, der er inde i JSTL-koder):

web.xml i version 2.3

<?xml version = '1.0' encoding = 'ISO-8859-15'?>
<!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>

Disse linjer skal erstattes med det følgende (web.xml i version 2.4 - du kan kopiere det fra den web.xml, der følger med eksemplerne i Tomcat):

web.xml i version 2.4

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app 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"
    version="2.4">

Endelig skal man være opmærksom på, at JSTL-taglib-bibliotekerne nu ligger under 'jsp':

<%-- Anvend JSTL 1.1's core- og XML-tagbibliotek (JSP 2.0) --%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/xml" prefix="x"%>

hvor man før i tiden skrev f.eks.:

<%-- Anvend JSTL 1.0's core- og XML-tagbibliotek (JSP 1.1)  --%>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jstl/xml" prefix="x"%>

6.7 JSTL versus almindelig javakode i JSP

Når nu man kan det samme med almindelig javakode i JSP, hvorfor så lære et nyt sprog og begynde at programmere i JSTL i stedet?

  • JSTL er simplere end Java. Man kan ikke nær så mange ting i JSTL som i almindelig javakode og syntaksen er simplere.

  • For ikke-Java-kyndige har JSTL en betydelig lettere syntaks end hvis de skulle lave almindelig javakode i JSP.

  • JSTL er en anelse langsommere end almindelig javakode.

  • JSTL har mange funktioner til at hente data ud fra java-objekter og er velegnet til at lave en adskillelse af præsentation (HTML-kode) og forretningslogik (der i større projekter nemmest skrives som selvstændige java-klasser uden for JSP-siderne).

  • Hvis man laver et større projekt, der involverer at HTML-designere også skal redigere i dokumenterne, er JSTL velegnet, da JSTL overholder XML-syntaksen. De fleste HTML-editorer lader derfor JSTL-koderne være (og tillader endda at redigere i dem), mens almindelig javakode mellem <% og %> ofte går tabt2.

Det anbefales, at bruge JSTL til præsentation af informationer. Det er næppe en god idé at skrive indviklet forretningslogik i JSTL, der er Java mere velegnet.

6.8 Kommunikation mellem JSTL og Java

Bemærk at JSTL og almindelig javakode i JSP fungerer på forskellige måder og at det sjældent er nogen god idé, at have begge slags kode i samme JSP-sider.

Man kan for eksempel ikke uden videre bruge en variabel fra JSTL i Java eller omvendt.

Således vil JSP-koden

  <%
    Date tid = new Date();
  %>

der opretter et Date-objekt og knytter det til variablen 'tid', ikke gøre den tilgængelig i JSTL.

Det skal man efterfølgende gøre ved, at gemme den som attribut til page, request, session eller application-objektet. Følgende vil således fungere fint:

  <%
    Date tid = new Date();
    page.setAttribute("tid", tid );  // lav variablen 'tid' i JSTL
  %>
  Klokken er ${tid}

6.8.1 Javabønner

Man kan også bruge javabønne-syntaksen (javabønner forklares i kapitel 9):

  <jsp:useBean id="tid" class="java.util.Date" />

Man kan eventuelt give javabønnen et virkefelt, der giver mulighed for at genbruge det samme objekt næste gang siden besøges (virkefelter er beskrevet senere, i afsnit 9.2.5, Oversigt over de mulige virkefelter).

Her gives f.eks. sessionen som virkefelt:

  <jsp:useBean id="tid" class="java.util.Date" scope="session" />

6.8.2 Implicit definerede objekter i EL

Når man skriver et udtryk i EL, kan man vælge præcist, hvad man vil have fat i, ved at benytte de følgende implicitte variabler:

  • pageScope, der giver adgang til attributter gemt i page-objektet

  • requestScope, der giver adgang til attributter gemt i request-objektet

  • sessionScope, der giver adgang til attributter gemt i session-objektet

  • applicationScope, der giver adgang til attributter gemt i application-objektet

  • pageContext, der søger alle ovenstående objekter igennem for attributter

  • param, der giver adgang til parametre i request-objektet

  • paramValues, der giver adgang til parameterværdierne i request-objektet

  • header, der giver adgang til HTTP-headere i anmodningen

  • headerValues, der giver adgang til værdierne af HTTP-headere i anmodningen

  • cookie, der giver adgang til cookier, der fulgte med anmodningen

  • initParam, der giver initialieringsparametre for webapplikationen (i web.xml)

Starter et EL-udtryk ikke med et af ovenstående ord, vil EL søge igennem alle implicitte variabler og derefter søge page-, request-, session- og application-objektets attributter igennem efter et objekt med det pågældende navn.

6.9 Mere læsning

1JSP med JSTL kan minde om sproget Coldfusion fra Macromedia/Allaire

2Desværre med én undtagelse: Importeringen af et taglib foretages med koden <%@ taglib ... %>, der ikke overholder XML-syntaksen og ikke overlever i en HTML-designer. Det kan man dog omgå, ved at lægge den ind i en HTML-kommentar (<!-- ... -->), sådan her:
<!-- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> -->

javabog.dk  |  << forrige  |  indhold  |  næste >>  |  programeksempler  |  om bogen
http://javabog.dk/ - Webprogrammering med Java Server Pages af Jacob Nordfalk.
Licens og kopiering under Åben Dokumentlicens (ÅDL) hvor intet andet er nævnt (72% af værket).

Ønsker du at se de sidste 28% af dette værk (275315 tegn) skal du købe bogen. Så får du pæne figurer og layout, stikordsregister og en trykt bog med i købet.