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

4 Videre med JSP


4.1 Sessioner 71

4.1.1 Eksempel: En ønskeseddel 71

4.1.2 Sessioner er individuelle 72

4.1.3 At kassere en session 72

4.1.4 Avanceret: URL Rewriting 72

4.2 Eksempel: Login med adgangskode 73

4.2.1 Inkludering af kodefragmenter 75

4.3 Omdirigering 77

4.3.1 Klient-omdirigering (response.sendRedirect()) 77

4.3.2 Server-omdirigering (<jsp:forward />) 78

4.4 Appendiks: Almindelige JSP-koder 79

4.5 Appendiks: Implicit definerede objekter 80

4.5.1 request - anmodningen fra klienten 80

4.5.2 response - svaret til klienten 81

4.5.3 out - skrive tekst til klienten 81

4.5.4 session - objekt der følger den enkelte bruger 82

4.5.5 application - fælles for hele webapplikationen 83

4.5.6 config - den enkelte websides konfiguration 84

4.5.7 page - selve JSP-siden 85

4.5.8 exception - undtagelse opstået under kørsel 85

4.5.9 pageContext - alle objekterne samlet i ét 85

4.6 Opgaver 86

4.7 Test dig selv 86

4.8 Resumé 86

4.9 Avanceret: Fejlfinding i JSP 87

4.9.1 Del og hersk 87

4.9.2 Tjek om blokparenteser er balancerede 87

4.9.3 Kigge på den oversatte servlet 87

4.9.4 Kigge i log-filerne 87

4.9.5 Forstå staksporet 88

4.9.6 Hvis klasse(bibliotek)er ikke kan findes 88

En overfladisk forståelse af emnerne i dette kapitel forudsættes i det meste af bogen. Kapitlet forudsætter kapitel 3, Interaktive sider.

4.1 Sessioner

Hver bruger får tildelt et session-objekt, når de besøger en JSP-side. Sessionen følger brugeren, lige meget hvilken side han/hun er inde på og er derfor nyttig til at huske data, der skal følge brugeren.

Med den kan man gemme og hente oplysninger i løbet af en brugers besøg. Det kunne f.eks. være om brugeren har logget ind, et bruger-ID eller nogle oplysninger om hvilke valg, brugeren har foretaget. I en e-handels-applikation ville sessionsobjektet også være det helt rigtige at bruge til at huske varerne i brugerens indkøbskurv.

De vigtigste metoder i session-objektet er beskrevet i afsnit 4.5.4.

4.1.1 Eksempel: En ønskeseddel

Det følgende eksempel lader brugeren indtaste nogle ønsker. Ønskerne huskes i en liste (af type ArrayList), der gemmes i sessionsobjektet (under navnet 'ønsker').

<%@ page language="java" import="java.util.*" %>
<html>
<head><title>Ønskeseddel</title></head>
<body>
Dette eksempel demonstrerer, hvordan session-objektet kan bringes til at 
huske brugerens indtastninger.

<h3>Skriv et ønske</h3>
Skriv noget, du ønsker.
<form>
<input type="text" name="oenske">
</form>
<%
  // hent listen over ønsker
  ArrayList ønsker = (ArrayList) session.getAttribute("ønsker");

  if (ønsker == null) {                      // hvis listen ikke findes:
    ønsker = new ArrayList();                // opret den
    session.setAttribute("ønsker", ønsker);  // og registrer den under "ønsker"
  }

  // se om der kommer en parameter med endnu et ønske
  String ønske = request.getParameter("oenske");
  if (ønske != null) {
    ønsker.add(ønske);                       // tilføj ønske til listen
  }

  if (ønsker.size()>0) {                     // udskriv ønsker i listen
    %>
      <h3>Ønskeseddel</h3>
      Indtil nu har du følgende ønsker:<br>
    <%
    // udskriv hele listen
    for (int i=0; i<ønsker.size(); i++) 
    { %>
      Ønske nr. <%= i %>: <%= ønsker.get(i) %><br>
    <% }

  }
%>
</body>
</html>

4.1.2 Sessioner er individuelle

Forestil dig, at 20 personer samtidigt klikker rundt på det samme websted - f.eks. en e-butik. Oplysningerne om, hvad deres indkøbskurve indeholder, kan med fordel gemmes i sessionsobjektet.

For at kunne identificere brugerne i forhold til hinanden, sådan at to brugere ikke ved et uheld får byttet session (og dermed varer i indkøbskurven!) bruger serveren et unikt ID, som gemmes i en HTTP cookie (en lille tekstfil på brugerens PC, se afsnit 3.6.5). Brug af sessioner kræver derfor normalt, at brugeren har slået understøttelse af cookier til i sin netlæser (ellers må man ty til 'URL Rewriting' beskrevet i afsnit 4.1.4).

4.1.3 At kassere en session

Vil du smide sessionen helt væk, kan det gøres med kaldet

  session.invalidate()

Herefter er sessionen og alle dens data væk.

Hvis den pågældende bruger besøger en side igen, vil hun blive tildelt en ny, tom session.

4.1.4 Avanceret: URL Rewriting

Dette afsnit er ikke omfattet af Åben Dokumentslicens.
Du skal købe bogen for at måtte læse dette afsnit.
Jeg erklærer, at jeg allerede har købt bogen
Jeg lover at anskaffe den i nær fremtid.

4.2 Eksempel: Login med adgangskode

Dette afsnit er ikke omfattet af Åben Dokumentslicens.
Du skal købe bogen for at måtte læse dette afsnit.
Jeg erklærer, at jeg allerede har købt bogen
Jeg lover at anskaffe den i nær fremtid.

4.2.1 Inkludering af kodefragmenter

I det foregående eksempel skulle alle beskyttede sider have et ovenstående tjek for, om brugeren er logget korrekt ind.

Det kunne derfor nok betale sig at have denne stump kode i en separat fil:

logintjek.jsp

<%
  // Filnavn: logintjek.jsp

  // Se om attributten "logget ind" er sat i sessionen
  if (session.getAttribute("logget ind") == null) {
    // brugeren er ikke logget ind, så send ham tilbage til login-siden
    response.sendRedirect("login1.html");
  }
%>

Herefter kan siderne blot inkludere fragmentet logintjek.jsp for at få tjekket om brugeren er logget ind:

login4.jsp

<%@ include file="logintjek.jsp" %>
<html>
<head><title>login4</title></head>
<body>

<h1>En anden beskyttet side</h1>
Denne tekst kan du kun se, hvis du er logget korrekt på.

</body>
</html>

4.3 Omdirigering

Ovenstående eksempel viser også, hvordan man omdirigerer brugeren til en anden side:

  response.sendRedirect("login1.html");

Brugeren vil da få siden login1.html i stedet for den side han egentlig spurgte om.

Omdirigering forudsætter, at der endnu ikke er sendt nogen data til brugeren. For JSP-sider sendes data normalt først, når afviklingen af siden er afsluttet (output er buffered), så en beslutning om omdirigering bør ske tidligt1 på siden.

Omdirigering kan faktisk gøres på to måder for JSP-sider: med response.sendRedirect():

<% response.sendRedirect("login1.html") %>

eller med JSP-koden <jsp:forward />:

<jsp:forward page="login1.html"/>

Forskellen mellem de to måder er måden, som omdirigeringen til den nye side foregår på: I det første tilfælde er klienten involveret i omdirigeringen, i det andet tilfælde sker omdirigeringen internt på serveren, uden at klienten ved det.

Modsat hvad man måske umiddelbart skulle tro, bliver al javakoden efter (d.v.s. neden under) en omdirigering faktisk udført, selvom outputtet fra siden skal kasseres2.

4.3.1 Klient-omdirigering (response.sendRedirect())

Med response.sendRedirect() sendes et speciel svar til netlæseren om, at den side, den lige har spurgt på, midlertidigt er flyttet et andet sted hen, hvorefter netlæseren vil spørge en gang til på den nye adresse.

Teknisk set sker der det, at serveren udnytter HTTP-protokollen (beskrevet i afsnit 3.7) til at omdirigere klienten. Når klienten spørger på login3.jsp med:

GET /JSP/kode/kapitel_04/login3.jsp HTTP/1.1
Host: javabog.dk:8080

vil serveren, i stedet for at kvittere med et '200 OK' og sende data som normalt, svare med et '302 Moved Temporarily' og fortælle klienten at den 'nye adresse' er login1.html:

HTTP/1.1 302 Moved Temporarily
Location: http://javabog.dk:8080/JSP/kode/kapitel_04/login1.html

Netlæseren reagerer på '302 Moved Temporarily' ved omgående at sende en ny anmodning, der spørger på den nye adresse:

GET /JSP/kode/kapitel_04/login1.html HTTP/1.1
Host: javabog.dk:8080

Herefter forløber HTTP-kommunikationen som den plejer.

Netlæseren har været involveret i omdirigeringen og viser den nye URL i adresselinjen. Parametrene til den oprindelige anmodning sendes ikke igen sammen med den nye anmodning, de mistes.

Omdirigering med JavaScript

JavaScript kan også bruges til at omdirigering. Følgende omdirigerer også til login1.html:

<html>
<head><title>Omdirigering med JavaScript</title></head>
<body>
<script>document.location="/JSP/kode/kapitel_04/login1.html"</script>
</body>
</html>

JavaScript udføres i brugerens netlæseren og kan ikke bruges til sikkerhedsforanstaltninger, j.v.f. afsnit 8.5, Sikkerhed i en webapplikation (det kan f.eks. deaktiveres af brugeren).

4.3.2 Server-omdirigering (<jsp:forward />)

Med <jsp:forward /> omdirigeres anmodningen internt i serveren. Det vil sige at den oprindelige anmodning klienten foretog (med de samme parametre etc.), besvares af en anden side i serveren.

Svaret sendes derefter tilbage til klientens netlæser, der ikke ved, at der skete en omdirigering. Den viser derfor den oprindelige URL i adresselinjen, ikke den nye adresse.

F.eks. kunne det være at klienten skulle omdirigeres til login-siden:

<jsp:forward page="login2.jsp"/>

Denne omdirigeringsmetode tillader at sende parametre videre til modtagersiden, da det samme request-objekt genbruges.

Man kan endda også tilføje parametre. Hvis brugeren eksempelvis kom ind på en side hvor der i JSP-siden, serveren udførte, stod:

<jsp:forward page="login2.jsp">
  <jsp:param name="brugernavn" value="Jacob"/>
  <jsp:param name="adgangskode" value="hemli"/>
</jsp:forward>

ville han blive automatisk logget ind (i øvrigt nok ikke videre hensigtsmæssigt).

Server-omdirigering fra javakode

Fra en servlet, eller fra Java-koden i en JSP-side kunne man skrive:

request.getRequestDispatcher("login2.jsp").forward(request,response);

4.4 Appendiks: Almindelige JSP-koder

Her er en oversigt over almindelige JSP-koder, som kan være nyttig til senere opslag.

JSP-kode

Betydning

<% kode %>

Javakode der udføres på serveren hver gang siden hentes.

<%= udtryk %>

Et udtryk. Værdien af udtrykket vil blive beregnet og indsat i stedet for koden. Eksempel (se også afsnit 2.2.1 Indlejrede java-udtryk):

Syv gange 2 er <%= 7*2 %>
<%-- kommentar --%>

En kommentar. Vil ikke blive udført af serveren og vil aldrig blive sendt til klienten. Se også afsnit 2.5 Kommentarer.

<%! erklæring %>

Variabel- og metodeerklæringer. Disse oprettes/defineres én gang når siden indlæses (se afsnit 2.8.2). Bruges sjældent.

<%@ page ... %>

Side-direktivet, der indeholder information om siden, f.eks.:
language="java" (beskrivelse af sproget i siderne)
import="java.util.*" (import af klassedefinitioner)
session="false" (webserveren skal ikke holde styr på brugersessioner)
contentType="text/html;charset=UTF-8" (indholdstype og evt. tegnsæt)
errorPage="fejl.jsp" (opstår en undtagelse så vis fejl.jsp i stedet)
isErrorPage="true" (hvis denne side er en fejlmeddelelsesside - får defineret objektet exception, der beskriver fejlen. Se også afsnit 10.4.5).

<%@ taglib ... %>

Et JSP-kodebibliotek (eng.: Tag library). En kraftfuld måde at definere og anvende foruddefinerere JSP-funktioner på (se afsnit 6).

<%@ include ... %>

Inklusions-direktivet. Inkluderer en fil (som om dens indhold blev klistret ind her - se afsnit 4.2.1 Inkludering af kodefragmenter). Eksempel

<%@ include file="hej.jsp" %>
<jsp:include ... />

Kald en anden fil på køretidspunktet (som om der blev lavet en forespørgsel på den) og inkluderer dens uddata her, f.eks.:

<jsp:include page="hej.jsp"/>
<jsp:forward ... />

Omdirigerer til en anden side (som bliver kaldt i stedet, se afsnit 4.3.2):

<jsp:forward page="hej.jsp"/>
<jsp:plugin ... />

Genererer HTML-kode til en plugin. Bruges sjældent.
F.eks. Java-plugin til appletter der skal køre under JDK1.2:

<jsp:plugin type="applet" code="MinApplet.class" 
jreversion="1.2" width="160" height="150" />

<jsp:...>-koderne anvender XML-syntaks: Koder der begynder med <jsp: skal afsluttes med et /> eller også skal der være en tilsvarende slutkode. Det betyder at f.eks.:

<jsp:forward page="login1.html">

ikke må stå alene, men skal afsluttes af den tilsvarende slut-kode:

</jsp:forward>

For at slippe for at skrive en masse slut-koder i de (mange!) tilfælde, hvor koden skal afsluttes lige efter at den er startet, er der indført en forkortet skrivemåde:

<jsp:forward page="login1.html"/>

hvor man afslutter koden med /> til sidst. Dette svarer altså til

<jsp:forward page="login1.html"></jsp:forward>

4.5 Appendiks: Implicit definerede objekter

Der findes en række implicit definerede objekter, som man altid har adgang til i en JSP-side. I det følgende vil disse objekter og deres vigtigste metoder blive beskrevet.

4.5.1 request - anmodningen fra klienten

Objektet request (af type HttpServletRequest i pakken javax.servlet.http) repræsenterer anmodningen fra klienten (i en servlet bliver request-objektet overført i doGet()-metoden).

Objektet kan bruges til at få information om klienten (se eksempel i afsnit 2.4), formulardata fra klienten (se afsnit 3.2.5) og informationer om gemte cookier (se afsnit 3.6.5).

String getRequestURL()
Giver den fulde URL på siden, der anmodes om, med maskinnavn og med evt parametre

String getMethod()
Giver anmodningsmetoden, som normalt er "GET". For formularer kan "POST" også forekomme (en tredje mulighed, "PUT" bruges til at sende filer til serveren). Se afsnit 3.6.4.

String getProtocol()
Giver versionen af HTTP-protokollen klienten har anvendt, typisk "HTTP/1.1"

String getServerName()
Giver værtsnavnet (eng.: host name), f.eks: "javabog.dk".

String getContextPath()
Giver stien til webapplikationens rod.

String getServletPath()
Giver stien på serveren på siden, der anmodes om (evt. parametre er fjernet), relativt til webapplikationens rod. Med application.getRealPath(request.getServletPath()) kan man finde den absolutte sti og filnavnet til, hvor en JSP-side ligger fysisk på harddisken (vist i afsnit 2.8.1).

String getRemoteAddr() og getRemoteHost()
Giver adressen (som IP-nummer eller evt med navn) på klienten, der foretager anmodningen

String getLocale()
Giver brugerens foretrukne sprog
(se eksempel på brug i afsnit 2.4 og afsnit 13.2)


String getParameter(String parameternavn)
Giver værdien af en parameter fra klienten - typisk fra en udfyldt formular, eller fra URLen. F.eks hvis en side bliver kaldt som side.jsp?x=a siges det, at den har parameteren x med værdien a og getParameter("x") vil returnere strengen "a".

String[] getParameterValues(String parameternavn)
Giver et array af værdier for et parameternavn. HTTP-protokollen tillader, at parametre har flere værdier. F.eks. vil side.jsp?x=aaa&x=bbb&x=ccc, hvor parameteren "x" har tre værdier, få getParameterValues("x") til at returnere et array med værdier {"aaa", "bbb", "ccc"}. Se afsnit 3.2.5.

Enumeration getParameterNames()
Giver en opremsning (eng.: enumeration) hvor hvert element er navnet på en parameter.
F.eks vil getParameterNames() give en opremsning med "x", "y" og "y2" for en side kaldt med: side.jsp?x=aaa&y=bbb?y2=ccc. Se et eksempel på brug i afsnit 3.2.5.

Cookie[] getCookies()
Giver et array af cookier, der er sat hos klienten (netlæseren). Se afsnit 3.6.5, hvor der også er et eksempel.

4.5.2 response - svaret til klienten

Objektet response (af type HttpServletResponse i pakken javax.servlet.http) repræsenterer svaret på anmodningen (i en servlet bliver response-objektet overført i doGet()-metoden). Objektet har information og data til klienten, herunder hvilke cookier der evt. skal sættes i klienten.

De vigtigste metoder er:

void setContentType(String indholdstype)
Sætter indholdstypen (MIME-typen). Indholdstypen er fra systemets side sat til "text/html".
Ønsker man at sende andre slags data, f.eks. binære, skal indholdstypen sættes til "image/jpeg" (jpeg-billeder), "audio/x-wav" (wav-lyde) eller "application/x-dit-eget-valg" hvis det er en helt selvopfunden indholdstype. Se et eksempel i afsnit 2.8.4, Producere grafik fra JSP.
Tegnsættet kan også sættes, f.eks. til Unicode (indholdstype="text/html;charset=UTF-8").

void addCookie(Cookie cookie)
Sætter eller tilføjer en cookie hos klienten (netlæseren). Se afsnit 3.6.5.

void sendRedirect(String url)
Omdirigerer klienten til en anden side, den skal spørge på i stedet for denne side. Adressen i url kan godt være relativ. Relateret til <jsp:forward ... />, se afsnit 4.3, Omdirigering.

4.5.3 out - skrive tekst til klienten

Objektet out (af type JspWriter i pakken javax.servlet.jsp) repræsenterer datastrømmen, der bliver sendt til klienten.

Det bruges lige som System.out:

  out.println( "<h1>Hej verden!</h1>" );

4.5.4 session - objekt der følger den enkelte bruger

Hver bruger får3 tildelt et session-objekt (af type HttpSession i pakken javax.servlet.http), der repræsenterer brugerens session. Det følger brugeren, lige meget hvilken side han/hun er inde på, og er derfor nyttigt til at huske data, der skal følge brugeren, f.eks om vedkommende er logget ind, sessions-ID og brugeroplysninger.

void setAttribute(String nøgle, Object værdi)
Gemmer et objekt under navnet nøgle.

Object getAttribute(String nøgle)
Henter objektet under navnet nøgle.

void removeAttribute(String nøgle)
Sletter referencen til objektet under navnet nøgle.

String[] getAttributeNames()
Giver et array af alle nøgler der er defineret.

long getLastAccessedTime()
Giver antal millisekunder siden sessionen sidst var i brug

int getMaxInactiveInterval()
Hvor lang tid (i sekunder) der går før sessionen bliver smidt væk, hvis den ikke bruges.

void setMaxInactiveInterval(int sekunder)
Sætter hvor lang tid (i sekunder) der går før en session, der ikke bruges, skal smides væk.

void invalidate()
Smider sessionen væk. Hvis den pågældende bruger besøger en side igen, vil hun blive tildelt en ny session.

4.5.5 application - fælles for hele webapplikationen

Objektet application (af type ServletContext i pakken javax.servlet) er fælles for alle sider og alle brugere af webapplikationen. Det kan bruges til at huske 'globale' data4.

Derudover kan den bruges til logning i webserverens log og til at fremfinde initialiseringsparametre fra web.xml, den globale konfigurationsfil for webapplikationen.

void setAttribute(String nøgle, Object værdi)
Gemmer et objekt under navnet nøgle.

Object getAttribute(String nøgle)
Henter objektet under navnet nøgle.

void removeAttribute(String nøgle)
Sletter referencen til objektet under navnet nøgle.

Enumeration getAttributeNames()
Giver en opremsning af alle nøgler der er defineret.

void log(String besked)

Logger en besked.

void log(String besked, Throwable undtagelse)

Logger en fejlmeddelelse og en supplerende undtagelse, hvis stakspor skrives til loggen.

String getRealPath(String url_i_webapp)

Giver den rigtige sti (på harddisken) ud fra en URL i webapplikationen. Er nyttigt til at indlæse og behandle filer fra harddisken, der befinder sig i samme webapplikation, se afsnit 2.8.6.
Med application.getRealPath(request.getServletPath()) kan man finde den absolutte sti og filnavnet til hvor en JSP-side ligger fysisk på harddisken (dette er vist i afsnit 2.8.1).

String getInitParameter(String navn)

Giver værdien af initialiseringsparameteren navn defineret i webapplikationens web.xml.

Enumeration getInitParameterNames()

Giver en opremsning af navnene på alle initialiseringsparametrene defineret i web.xml.

Initialiseringsparametre

application-objektet giver også adgang til initialiseringsparametre fra web.xml.

Initialiseringsparametre er meget hensigtsmæssige til f.eks. at lægge navne på databasedrivere og database-URLer og lignende faste oplysninger. Det gøres ved at lave en indgang af typen context-param, f.eks. med databasedriveren, i web.xml:

<web-app>
  ...
  <context-param>
    <param-name>dbDriver</param-name>
    <param-value>com.mysql.jdbc.Driver</param-value>
  </context-param>
  ...
</web-app>

Nu vil man i en JSP-side kunne hente værdien af initialiseringsparameteren dbDriver med:

    String drv = application.getInitParameter("dbDriver");

hvorefter strengen drv vil have indholdet 'com.mysql.jdbc.Driver'. Der er et eksempel på dette i afsnit 8.5.8.

Fra en servlet (se afsnit 7.1, Servletter) er application-objektet tilgængeligt med:

    ServletContext application = getServletContext();

hvorefter værdien fås som i en JSP-side med:

    String drv = application.getInitParameter("dbDriver");

I afsnit 9.5, Eksempel: Login og brugeroprettelse, kan man se hvordan en ekstern klasse (en javabønne, vist i afsnit 9.5.2) kan bruge application-objektet til af få initialiseringsparametre.

4.5.6 config - den enkelte websides konfiguration

Objektet config (af type ServletConfig i pakken javax.servlet) giver adgang til konfiguration i web.xml for den enkelte JSP-side eller servlet.

String getInitParameter(String navn)

Giver værdien af initialiseringsparameteren navn defineret for websiden i web.xml.

Enumeration getInitParameterNames()

Giver en opremsning af navnene på alle initialiseringsparametrene for websiden.

Eksempel

<web-app>
  .. 
  <servlet>
    <servlet-name>jspside</servlet-name>
    <jsp-file>/jspside.jsp</jsp-file>
    <init-param>
      <param-name>tekst</param-name>
      <param-value>Dette er en tekst fra web.xml</param-value>
    </init-param>
  </servlet>

</web-app>

Fra en JSP-side ville det kunne dette hentes med

    config.getInitParameter("tekst")

som ville returnere strengen "Dette er en tekst fra web.xml".

Fra en servlet kunne teksten hentes med

    getInitParameter("tekst"));

4.5.7 page - selve JSP-siden

Dette objekt repræsenterer selve JSP-siden. Det er her taget med for en ordens skyld, selvom der ikke er meget man kan bruge det til i praksis.

4.5.8 exception - undtagelse opstået under kørsel

Objektet exception (af type Exception) repræsenterer en undtagelse der opstod under kørsel af en JSP-side. Objektet er kun defineret på fejlmeddelelsessider (hvor side-direktivet isErrorPage er sat til "true").

Se også afsnit 10.4.5. Et eksempel findes i afsnit 4.4.

4.5.9 pageContext - alle objekterne samlet i ét

Objektet pageContext (af type PageContext i pakken javax.servlet.jsp) giver adgang til alle de andre implicit definerede objekter. Det kan være nyttigt at bruge, hvis man ønsker at have alle de implicitte objekter samlet i ét objekt - f.eks. til et metodekald.

JspWriter getOut()
Giver out-objektet

HttpSession getSession()
Giver session-objektet

Object getPage()
Giver page-objektet

ServletRequest getRequest()
Giver request-objektet

ServletResponse getResponse()
Giver response-objektet

Exception getException()
Giver exception-objektet

ServletConfig getServletConfig()
Giver config-objektet

ServletContext getServletContext()
Giver application-objektet

4.6 Opgaver

Forbedring af ønskeseddel

  1. Forbedr ønskeseddel-eksemplet i afsnit 4.1.1, sådan at brugeren også kan angive sit navn. Navnet huskes efterfølgende i session-objektet og skrives i sidens titel.

  2. Lav mulighed for, at brugeren kan slette alle sine ønsker (navnet forbliver)

  3. Lav mulighed for, at brugeren kan 'logge ud' (alle ønsker og navnet slettet).
    Prøv at bruge session.invalidate() (beskrevet i afsnit 4.5.4) for at smide sessionen væk.

Opgave: Afgiv din stemme

Lav et program, hvor man kan angive, hvem man vil stemme på til næste valg. Lad f.eks. brugeren vælge mellem 4 partier: Venstre, Konservative, Socialdemokratiet og SF.

Benyt radioknapper, sådan at man kun kan stemme på et parti ad gangen.
Optæl stemmerne og vis resultatet på skærmen hver gang brugeren har stemt.
Vink: Brug session- og application-objektet. Du kan søge inspiration ved at kigge i afsnit 3.3, Appendiks: Typer af formularfelter.

4.7 Test dig selv

Dette afsnit er ikke omfattet af Åben Dokumentslicens.
Du skal købe bogen for at måtte læse dette afsnit.
Jeg erklærer, at jeg allerede har købt bogen
Jeg lover at anskaffe den i nær fremtid.

4.8 Resumé

Dette afsnit er ikke omfattet af Åben Dokumentslicens.
Du skal købe bogen for at måtte læse dette afsnit.
Jeg erklærer, at jeg allerede har købt bogen
Jeg lover at anskaffe den i nær fremtid.

4.9 Avanceret: Fejlfinding i JSP

Det kan til tider være svært at finde og rette fejl i JSP-sider. Her følger et par idéer til, hvordan du kan lokalisere og rette fejlene.

4.9.1 Del og hersk

Har du en fejl, der driller, er det altid en god strategi, at prøve at isolere fejlen.

Ofte står man med en udgave af koden, der virker og en, der ikke virker. Prøv da 'del og hersk'-metoden: Find frem til fejlen ved langsomt at kopiere koden over (eller kommentere den ud og derpå kommentere den ind igen, bid for bid), sådan at du tilnærmer den kode, der virker, til den, der ikke virker.

4.9.2 Tjek om blokparenteser er balancerede

Som nævnt i afsnit 2.3.1, Blandet Java og HTML, skal man være meget omhyggelig med at omkranse HTML-kode i {- og }-parenteser og sørge for, at der altid er lige mange {-startparenteser som }-slutparenteser.

Er der rod med parenteserne får man typisk fejlmeddelelserne:

  'try' without 'catch' or 'finally'
  'catch' without 'try'
  'else' without 'if'

4.9.3 Kigge på den oversatte servlet

JSP-siden bliver internt oversat til en servlet, der så oversættes igen, fra .java-kildetekst til en binær .class-fil (beskrevet i afsnit 7.3, Avanceret: JSP-siders interne virkemåde).

Det er ofte svært at finde fejl i en JSP-side, fordi de linjenumre, der angives i fejlmeddelelsen, normalt henviser til linjenumre i servlettens .java-kildetekst i stedet for de oprindelige linjenumre i JSP-siden.

Udviklingsmiljøer som (den kommercielle udgave af) Borland JBuilder, Sun One Studio o.s.v. tager højde for dette og finder de oprindelige linjenumre og tjekker også løbende JSP-sidernes syntaks, så man med det samme ser fejlen det rigtige sted.

De oversatte servletter ligger normalt i work/-mappen i webserveren og hedder nogenlunde det samme som JSP-siderne (beskrevet i afsnit 7.3).

4.9.4 Kigge i log-filerne

Når der opstår en fejl skrives en fejlmeddelelse i webserverens log. Det kan derfor være en god idé at kigge i disse.

Under Tomcat findes logfilerne i mappen logs/.

En snild måde under Linux til at kigge i alle logfilerne på én gang er fra kommandolinjen at skrive:

tail -f -n0 logs/*

Kommandoen 'tail' åbner herefter alle logfilerne og følger med i dem (-f), sådan at alle nye fejlmeddelelser skrives ud på skærmen.

Husk altid at udskrive fejlmeddelelserne og staksporene

Det er selvfølgelig afgørende for, om der er noget interessant at se i logfilerne, at dit program ikke undertrykker eventuelle fejl, men i stedet skriver dem ud.

Det er altså meget væsentligt at der ingen steder står:

      try {
        ...
      } catch (Exception e) { } // Forkert! Fejlen undertrykkes!

men i stedet, i alle try-catch-blokke, står:

      try {
        ...
      } catch (Exception e) { e.printStackTrace(); } // Udskriv stakspor i loggen

sådan at staksporet udskrives i loggen

4.9.5 Forstå staksporet

Et eksempel på et stakspor er vist nedenfor. Staksporet fortæller præcist hvad der skete, men det er kun meget få dele af det (herunder fremhævet med fed), der har vores interesse. De andre afspejler nemlig blot måden webserveren og klassebibliotekerne fungerer på:

java.sql.SQLException: General error,  message from server: "Table 'test.gaestebog' doesn't exist"
  com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:1825)
  com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1020)
  com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1109)
  com.mysql.jdbc.MysqlIO.sqlQuery(MysqlIO.java:1070)
  com.mysql.jdbc.Connection.execSQL(Connection.java:2027)
  com.mysql.jdbc.Connection.execSQL(Connection.java:1984)
  com.mysql.jdbc.Statement.executeQuery(Statement.java:1152)
  org.apache.jsp.JSP.kode.kapitel_05.gaestebog_jsp._jspService(gaestebog_jsp.java:58)
  org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:133)
  javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
  org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:311)
  org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:301)
  org.apache.jasper.servlet.JspServlet.service(JspServlet.java:248)
  javax.servlet.http.HttpServlet.service(HttpServlet.java:856)

Oversat til dansk siger fejlmeddelelsen at:

Som regel fortæller staksporet alene nok til at man kan finde fejlen. Kigger man på gaestebog.jsp (den kommer i afsnit 5.5, Eksempel - gæstebog) ser man at executeQuery() kun kaldes ét sted, og man har således fundet frem til stedet, hvor fejlen opstod.

Et man stadig i tvivl om, præcis hvor fejlen opstod (måske er der flere steder med kald til executeQuery()), må man bruge sin viden om, at det skete i linje 58 i gaestebog_jsp.java og kigge på den oversatte servlet (ligger normalt i work/-mappen i webserveren, se afsnit 7.3.1, Kigge i de genererede servletter).

4.9.6 Hvis klasse(bibliotek)er ikke kan findes

Får du fejlen NoClassDefFoundError, er det et symptom på, at en klasse ikke kan findes. Det kan f.eks. ske, når du prøver at indlæse en databasedriver (der kan du også få 'No suitable driver') eller, hvis du bruger ekstra klassebiblioteker ud over de, der er defineret i standard Java JDK.

Ekstra klassebiblioteker og drivere fås næsten altid som JAR-filer (der er et ZIP-arkiv med en række .class-filer).

Der er mange muligheder for at løse problemet med, at en klasse ikke kan findes:

I princippet kan alle mulighederne være lige gode til at løse problemet, men når du har fået det til at virke, så brug lidt tid på at overveje om løsningen er den rigtige for dig (det er f.eks. lidt kedeligt hvis du ofte skifter JDK og du netop har lagt databaseklasserne ind i dit JDK).

1Omdirigering skal ske så tidligt på siden, at man kan være sikker på, at der ikke er genereret så meget HTML, at bufferen er løbet fuld og HTTP-hovedet (se afsnit 3.7) og den første del af data således er sendt til klienten. Når først data er sendt til klienten, kan webserveren ikke 'fortryde' og i stedet omdirigere til en anden side.
For servletter er der ingen output-buffer, så i servletter skal omdirigering ske inden der har været noget output overhovedet.

2Som 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. Man kan undgå at den efterfølgende kode i metoden udføres ved at returnere fra metoden, med 'return;'. I afsnit 10.4.4 er der et eksempel på dette.

3Denne opførsel kan slås fra ved at sætte session="false" i sidedirektivet med
<%@ page session="false" %>

4En mindre hensigstmæssig måde kunne være at bruge en klassevariabel i en separat klasse.

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.