2.1 JSP-programkode 28
2.1.1 En simpel side med HTML-kode 28
2.1.2 Lægge JSP-serverkode ind i siden 28
2.1.3 Eksempel: Dags dato og tid 29
2.1.4 Hvis du ikke har en server til rådighed 29
2.1.5 JSTL - en ny måde at arbejde på 29
2.2 Variabler 30
2.2.1 Indlejrede java-udtryk 31
2.2.2 Variabler med objekter 31
2.2.3 Importere klassedefinitioner (pakker) 32
2.3 Blanding af HTML og Java - to stilarter 33
2.3.1 Blandet Java og HTML 33
2.4 Data om klienten (request-objektet) 34
2.5 Kommentarer 35
2.6 Test dig selv 36
2.7 Resumé 36
2.8 Avanceret 37
2.8.1 Læse filer fra harddisken 37
2.8.2 Erklæring af metoder og blivende variabler 38
2.8.3 Trådsikkerhed i JSP-sider 39
2.8.4 Producere grafik fra JSP 40
2.8.5 Eksempel: JSP-side der danner et JPG-billede 40
2.8.6 Indlejre og nedskalere billeder fra harddisken 43
2.8.7 Opload af filer til server 44
En grundig forståelse af
emnerne i dette kapitel forudsættes i resten af bogen.
Bemærk:
De avancerede emner i slutningen af kapitlet forudsættes ikke,
de er frivillig læsning, du senere kan vende tilbage til.
I dette kapitel laver vi den allerførste helt simple JSP-fil. Her kan du også teste, om din server er sat rigtigt op og kan køre JSP.
Grundlæggende er en JSP-fil en tekstfil med endelsen .jsp, som består af:
Tekst
HTML-koder
JSP-programkode
Tekst og HTML-koder kender du, så lad os kigge lidt mere på JSP-programkoden.
Når man programmerer JSP så skriver man i virkeligheden i programmeringssproget Java. Derfor kan det være en god ide at lære lidt Java undervejs, f.eks. ved at kigge på de første kapitler af af en lærebog som http://javabog.dk.
Start med at lave et ganske almindeligt HTML-dokument, navngiv filen hej.jsp, og placer den sammen med de andre JSP-filer der fulgte med din webserver (med Tomcat er stien nok jakarta-tomcat-5.0.27/webapps/ROOT/hej.jsp). HTML-koden skal se sådan her ud:
<html> <head><title>Hej</title></head> <body> Her kommer noget JSP-kode: </body> </html>
Prøv så at hente siden gennem webserveren.
Sandsynligvis er adressen http://localhost:8080/hej.jsp.
Husk at JSP er at skrive opgaver til en server, og lad os så prøve at skrive en opgave til serveren. For at fortælle serveren, hvad den skal kigge efter, må vi have nogle koder som fortæller, hvornår serverkoderne starter og slutter. I JSP bruger man <% og %> til at markere start og slut på det, som serveren skal udføre.
Prøv derefter at tilføje følgende helt simple kodestump til din HTML-kode:
<html> <head><title>Hej</title></head> <body> Her kommer noget JSP-kode: <% out.println( "<h1>Hej verden!</h1>" ); out.println( "To plus to er: " ); out.println( 2 + 2 ); %> </body> </html>
Når du nu ser JSP-dokumentet i en netlæser, skulle resultatet gerne være som vist til højre.
Men det interessante viser sig først, når du får vist HTML-koden i netlæseren (ved at vælge "vis kilde" eller "View Source"):
<html> <head><title>Hej</title></head> <body> Her kommer noget JSP-kode: <h1>Hej verden!</h1> To plus to er: 4 </body> </html>
JSP-koderne er væk. Som allerede nævnt er det kun serveren som kan se JSP-koderne - klienten (netlæseren) ser kun resultatet af beregningerne. Serveren har udført Java-koden:
out.println( "<h1>Hej verden!</h1>" ); out.println( "To plus to er: " ); out.println( 2 + 2 );
Lidt teknisk udtrykt ville man sige, at her brugte vi out-objektets metode println() til at skrive strenge til klienten. Bemærk at Java-kommandoer altid afsluttes med semikolon (;).
Lad os prøve at få serveren til at skrive noget andet. Vi kunne f.eks. bede den om at udskrive den aktuelle dato og tidspunkt:
<html> <head><title>Tiden</title></head> <body> <% out.print( new java.util.Date() ); %> </body> </html>
Vi kan altså få serveren til at udskrive dato og tidspunkt, når JSP-siden vises. Bemærk, at hvis man trykker på opdater/genindlæs/reload i sin netlæser, vises et nyt tidspunkt. Serveren beregner og udskriver altså dato og tidspunkt hver gang siden sendes til en klient.
Det er også væsentligt at bemærke, at den HTML-kode klienten ser, ikke indeholder andet end datoen. Det vil sige at JSP ikke stiller krav til, hvilken netlæser, der anvendes. Det er således sådan, at ting, der er lavet med serverside teknologier, virker i alle netlæsere.
Hvis du ikke har en server, der kan køre JSP, til rådighed, kan du prøve alle eksemplerne fra bogen på http://javabog.dk:8080/JSP/kode/. Ovenstående eksempel har således adressen http://javabog.dk:8080/JSP/kode/kapitel_02/hej.jsp .
Er du ikke så erfaren med Java er JSTL (JSP Standard Tag Library), der beskrives i kapitel 6, JSTL - JSP Standard Tag Library, nok lettere for dig end Java. JSTL er et HTML-lignende sprog som man kan skrive koden, der udføres på serveren i, i stedet for Java.
I kapitel 6 er der en række eksempler med JSTL, der gør det samme som eksemplerne i dette og de efterfølgende kapitler. Selvom denne bogs 'hovedsprog' er Java og ikke JSTL kan du derfor vælge at lære JSTL i stedet ved at læse hovedteksten og så ved Java-eksemplerne i stedet kigge på og lege med JSTL-eksemplerne i kapitel 6.
En variabel kan opfattes som en navngiven papirlap, hvor der til enhver tid kan stå netop én ting. Variabler bruges til at huske data.
Variabler i Java skal altid erklæres, dvs. at man skal fortælle serveren, at der skal oprettes en variabel, hvad slags data den skal indeholde og hvad den skal hedde:
int alder = 31;
Her har vi oprettet variablen alder. Den er af typen int, det vil sige at den kan indeholde hele tal. Samtidig har vi givet (eller tildelt) den værdien 31.
Senere kunne vi så hente værdien frem ved at skrive variablens navn. Her er et eksempel:
alder.jsp (JSTL-eksempel i afsnit 6.1)
<html> <head><title>Alder</title></head> <body> <p> <% int alder = 31; out.print( "Søren er " + alder + " år gammel. " ); out.print( "Det svarer til " + 12*alder + " måneder. <br>" ); alder = 3; out.print( "Julie er " + alder + " år gammel. " ); alder = alder*365; out.print( "Det svarer cirka til " + alder + " dage. <br>" ); %> </p> </body> </html>
Resultatet i en netlæser er:
Bemærk, at når en variabel tildeles en ny værdi, bliver den gamle værdi fuldstændig glemt.
Bemærk også, at på højre side af lighedstegnet i en tildeling kan stå et regneudtryk, der i så fald beregnes før variablen tildeles værdien.
Udtrykket alder = alder*365 gør altså det, at det beregner alder*365, der giver 3*365=1095. Denne værdi puttes derefter ind i variablen alder.
I koden <%= %> kan skrives et Java-udtryk, der bliver beregnet på serveren og indsat i HTML-koden hver gang siden hentes.
<%= dato %> er altså bare en kortere måde at skrive <% out.print(dato); %> på.
Her er en side, der udskriver 7-tabellen ved hjælp af <%= %>:
syvtabellen.jsp (JSTL-eksempel i afsnit 6.1.5)
<html>
<head><title>Syvtabellen</title></head>
<body>
<p>Her er syv-tabellen:<br>
<%
for (int i=1; i<=10; i++)
{
%>
Syv gange <%= i %> er: <%= 7*i %>.<br>
<%
}
%>
</p>
</body>
</html>
Bemærk at en klump javakode gerne må slutte, selvom der mangler en }-parentes til at afslutte den blok kode, der skulle udføres i for-løkken, blot der senere kommer endnu en klump javakode, hvori blokken afsluttes (det kommer vi tilbage til i afsnit 2.3.1).
I eksemplet i afsnit 2.1.3 skrev vi new java.util.Date(), hvilket opretter et objekt, som repræsenterer den aktuelle dato og tid på serveren.
Sådan et objekt kan man også gemme i en variabel, sådan her:
java.util.Date tiden = new java.util.Date();
og så bagefter udskrive objektet på skærmen:
out.print( tiden );
Lad os udvide eksemplet og både udskrive en streng og et objekt, som vi samler med +:
<html> <head><title>Tiden 2</title></head> <body> <% java.util.Date tiden = new java.util.Date(); out.print( "Dato og tid er: " + tiden ); %> </body> </html>
Når netlæseren anmoder om siden, udfører serveren JSP-koden og sender til klienten:
<html>
<head><title>Tiden 2</title></head>
<body>
Dato og tid er: Wed Aug 28 16:00:42 CEST 2002
</body>
</html>
I stedet for hele tiden at skrive Date-klassens fulde navn (som er java.util.Date) kan vi også importere java.util.* (alle klasser i pakken java.util) og således undgå at skrive pakkenavnet.
Til det skal vi bruge side-direktivet <%@ page ... %>, der kan bruges til at angive en række ting om hvordan serveren skal udføre siden (side-direktivet bliver grundigere beskrevet senere, i afsnit 4.4):
<%@ page language="java" import="java.util.*" %> <html> <head><title>Tiden 3 - import af pakke</title></head> <body> <% Date tiden = new Date(); out.print( "<p>Dato og tid er: " + tiden + "</p>" ); %> </body> </html>
Vil man importere klasser fra flere pakker skriver man dem adskilt af komma, f.eks. import="java.util.*,java.text.*".
Med det kan vi lave en lidt pænere side, der udskriver datoen og tiden:
<%@ page language="java" import="java.util.*,java.text.*" %> <html> <head><title>Tiden 4 - import af flere pakker</title></head> <body> <% DateFormat klformat, datoformat; klformat = DateFormat.getTimeInstance(DateFormat.SHORT); datoformat = DateFormat.getDateInstance(DateFormat.FULL); Date tid = new Date(); String kl = klformat.format(tid); String dato = datoformat.format(tid); %> <p>Datoen i dag er <%= dato %>, og klokken er <%= kl %>.</p> </body> </html>
Resultatet i en netlæser er:
Lad os skrive tidspunktet på dagen. Det kan vi gøre med en række kædede if-sætninger:
java_og_html_adskilt.jsp (JSTL-eksempel i afsnit 6.2.2)
<%@ page language="java" import="java.util.*" %>
<html>
<head>
<title>Java og HTML adskilt</title></head>
<body>
Det er lige nu:
<%
Date tid = new Date();
int t = tid.getHours();
if (t <= 9) out.print("morgen");
else if (t <= 12) out.print("formiddag");
else if (t <= 17) out.print("eftermiddag");
else if (t <= 21) out.print("aften");
else out.print("nat");
%>
</body>
</html>
De fleste foretrækker at bruge out-objektet til udskrivning, som vist ovenfor, for på denne måde at adskille Java og HTML.
Men det er faktisk muligt at starte og stoppe javakoden med <% og %> i stedet:
<%@ page language="java" import="java.util.*" %> <html> <head><title>Java og HTML blandet</title></head> <body> Det er lige nu: <% Date tid = new Date(); int t = tid.getHours(); if (t <= 9) { %> morgen <% } else if (t <= 12) { %> formiddag <% } else if (t <= 17) { %> eftermiddag <% } else if (t <= 21) { %> aften <% } else { %> nat <% } %> </body> </html>
For de fleste er det forvirrende med denne sammenblanding af HTML og Java. Derfor foretrækker de fleste at bruge out-objektet (en tredje mulighed er at bruge JSTL, se hvordan i afsnit 6.2).
Dette eksempel kan dog virke besnærende for nogen, fordi det ser mere overskueligt ud. Man skal dog være meget omhyggelig med at omkranse HTML-koden i {- og }-parenteser.
Husk altid at bruge { og } i betingelser og løkker hvis de har indlejret HTML
Man skal være omhyggelig med, at der altid er lige mange {-startparenteser som }-slutparenteser
Er der ikke lige mange {- og }-blokparenteser får man kryptiske1 fejlmeddelelser såsom:
'try' without 'catch' or 'finally' 'catch' without 'try' 'else' without 'if'
Out-objektet er et eksempel på et objekt, der automatisk findes i alle JSP-sider.
Der findes flere af den slags objekter (i afsnit 4.5, Appendiks: Implicit definerede objekter, er de beskrevet i detaljer), bl.a. et request-objekt (beskrevet i afsnit 4.5.1). Dette objekt repræsenterer alt det serveren ved om klienten og med det kan vi få en række ting at vide om klienten og den forespørgsel der blev foretaget.
<html> <head><title>Data om klienten</title></head> <body> <h1>Nogle data om klienten (request-objektet)</h1> <pre> Fuld URL - getRequestURL(): <%= request.getRequestURL() %> Metode - getMethod(): <%= request.getMethod() %> Protokol - getProtocol(): <%= request.getProtocol() %> Værtsnavn - getServerName(): <%= request.getServerName() %> Port - getServerPort(): <%= request.getServerPort() %> Webapp - getContextPath(): <%= request.getContextPath() %> Sti i app - getServletPath(): <%= request.getServletPath() %> Filplacering på harddisk: <%= application.getRealPath(request.getServletPath()) %> Klients IP-adresse - getRemoteAddr(): <%= request.getRemoteAddr() %> Foretrukne sprog - getLocale(): <%= request.getLocale() %> Netlæser/browser header user-agent: <%= request.getHeader("user-agent") %> </pre> </body> </html>
Prøv eksemplet på http://javabog.dk:8080/JSP/kode/kapitel_02/data_om_klienten.jsp.
Med <%-- og --%> kan man indsætte kodekommentarer i JSP. Disse fungerer lidt anderledes end HTML-kommentarer, som man laver med <!-- og -->.
<html> <head><title>Hej med HTML- og JSP-kommentarer</title></head> <body> Her kommer noget JSP-kode: <% out.println( "<h1>Hej verden!</h1>" ); %> <!-- HTML-kommentar <% out.println( "To plus to er: " ); %> --> <%-- JSP-kommentar <% out.println( 2 + 2 ); %> --%> </body> </html>
I bogen her bliver kommentarer skrevet i kursiv for læselighedens skyld.
Grunden til at JSP har sin egen måde at lave kommentarer på, er at JSP-kommentarer med <%-- og --%> (til forskel fra HTML-kommentarer med <!-- og -->) slet ikke bliver udført på serveren. De bliver også helt udeladt af koden, der sendes til klientens netlæser. Hvis ovenstående side hentes, vil netlæseren derfor kun få tilsendt (det kan ses med 'vis kilde'):
<html> <head><title>Hej med HTML- og JSP-kommentarer</title></head> <body> Her kommer noget JSP-kode: <h1>Hej verden!</h1> <!-- HTML-kommentar To plus to er: --> </body> </html>
De almindelige HTML-kommentarer lavet med <!-- og --> vil netlæseren udelade i fremvisningen, så resultatet er, at netlæseren ikke viser hverken den ene eller den anden slags kommentarer:
1Som vi senere skal se, i afsnit 7.3, Avanceret: JSP-siders interne virkemåde, bliver JSP-sider lavet om til en metode i en klasse. Derfor er det meget vigtigt at {- og }-parenteser er balancerede.
2Egentlig er servletter (se afsnit 7.1) mere velegnede til at producere binære data end JSP-sider. I eksemplet kommer således fejlen 'IllegalStateException: getOutputStream() has already been called for this response' i serverens log, selvom eksemplet virker fint.