21.07.2013 Views

Kap 16_Java for Web.pdf - Akademika forlag

Kap 16_Java for Web.pdf - Akademika forlag

Kap 16_Java for Web.pdf - Akademika forlag

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 297 Tuesday, September 24, 2002 6:07 PM<br />

KAPITTEL <strong>16</strong><br />

Case-studie II : "e-sjappe"<br />

Overblikk<br />

E-handel er en kosteffektiv strategi bedrifter kan benytte <strong>for</strong> å markedsføre og selge sine<br />

produkter og tjenester. Bedriften presenteres på et nettsted som inneholder en produktkatalog<br />

som beskriver produktene, og en mulighet <strong>for</strong> elektronisk eller "online"<br />

bestilling. Bestillingene mottas direkte, og varene sendes ut umiddelbart. Nettbaserte<br />

bokhandler og platebutikker har blitt svært populære, som <strong>for</strong> eksempel amazon.com<br />

og bokkilden.no i Norge. Dette kapitlet demonstrerer hvordan et enkelt e-handelsystem<br />

– "e-sjappa" – kan implementeres. Applikasjonen benytter en MySQL database <strong>for</strong><br />

lagring av data og seanseobjekter <strong>for</strong> betjening av flere kunder samtidig.<br />

Problemstilling<br />

Implementeringen skal fungere som en e-butikk med følgende komponenter:<br />

• Et vareutvalg/prisliste<br />

• Kunder<br />

• Handlekurver<br />

• Regninger/bestillinger<br />

En kunde etablerer en kundekonto ved å registrerer seg på en registreringsside. Kunder<br />

logger seg inn, kikker på vareutvalget og legger ønskede varer i handlekurven. I tillegg<br />

skal kunden kunne inspisere innholdet av handlekurven, totalbeløp, fjerne varer fra<br />

handlekurven og levere en bestilling. Kunden skal også kunne inspisere tidligere bestillinger.<br />

Prislister og lagerlister skal kunne endres av en administrator via et administrasjonsskjema.<br />

Applikasjonen skal kunne betjene flere kunder samtidig.<br />

Overordnet struktur<br />

Applikasjonen består av ni sider i tillegg til in<strong>for</strong>masjonssider og feilsider. Sidene er<br />

som følger: innloggingsskjema, skjema <strong>for</strong> registrering av ny kunde, hovedside <strong>for</strong><br />

navigering mellom sidene i applikasjonen, varekatalogside, handlekurvside, bestillingslisteside,<br />

side <strong>for</strong> registrering av en ny vare, personalregister og kunderegister. Sammenhengen<br />

mellom sidene er illustrert i figur <strong>16</strong>.1. En bruker som besøker nettstedet<br />

konfronteres med innloggingsskjemaet, og har mulighet til å registrere seg som kunde<br />

eller logge seg inn i systemet. Kunden kommer først til hovedsiden. Fra hovedsiden har<br />

kunden tilgang til vareutvalg, handlekurv og bestilling.<br />

297


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 298 Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

298<br />

Det er to brukerkategorier – kunde og administrator. Administratorers utvidede<br />

privilegier gir tilgang til personal- og kunderegister og muligheter <strong>for</strong> modifisering av<br />

vareutvalget.<br />

bestilling sendt<br />

velykket pålogging<br />

administrator, kunde<br />

vareut valg<br />

handlekurv<br />

bestilling<br />

innlogging registrer kunde<br />

hovedside<br />

administrator<br />

ny vare<br />

personalregister<br />

kunderegister<br />

Figur <strong>16</strong>.1: Et oversiktsdiagram som viser de <strong>for</strong>skjellige navigeringsstiene mellom sidene i<br />

applikasjonen<br />

Figur <strong>16</strong>.2: Innloggingsskjema


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 299 Tuesday, September 24, 2002 6:07 PM<br />

Figur <strong>16</strong>.3: Kunderegistreringsskjema<br />

Case-studie II : "e-sjappe"<br />

Datastruktur<br />

Datastrukturen består av fire SQL-tabeller – vare, kunde, handlevogn og bestilling, Varetabellen<br />

beskriver vareutvalget, og inneholder primærnøkkelen vareno, navnet på<br />

varen navn, beskrivelse av varen, kategori, beholdning og pris. Navn, beskrivelse og kategori<br />

er tekststrenger og beholdning og pris er heltall. Vare-tabellen er definert som følger:<br />

create table vare<br />

(<br />

vareno int NOT NULL AUTO_INCREMENT PRIMARY KEY,<br />

navn varchar(20) NULL,<br />

beskrivelse varchar(20) NULL,<br />

kategori varchar(20) NULL,<br />

beholdning int NULL,<br />

pris int NULL);<br />

299


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 300 Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

Figur <strong>16</strong>.4: Enkel navigering i applikasjonen<br />

300<br />

Kunde-tabellen inneholder kundelisten med feltene brukernavn, passord, <strong>for</strong>navn, etternavn,<br />

postnr, poststed, telefon og status. Brukernavn er primærnøkkel <strong>for</strong>di hver bruker<br />

må velge et unikt brukernavn. Korrekt brukernavn og passord gir adgang til nettbutikken.<br />

Feltene <strong>for</strong>navn, etternavn, adresse, postnr, poststed og telefon utgjør brukerens personopplysninger<br />

som brukes ved levering av vare og utsending av faktura. Statusfeltet<br />

angir brukerens status – enten som kunde eller administrator. Alle feltene er av typen<br />

varchar. Til tross <strong>for</strong> at feltene postnr og telefon kan representeres med heltall, så gir<br />

tekststrenger brukeren <strong>for</strong>materingsfrihet, <strong>for</strong> eksempel postkoden "N-0254" eller telefonnummeret<br />

"22 32 45 56". Disse symbolsekvensene er ikke heltall. Kunde-tabellen er<br />

gitt som følger:<br />

create table kunde<br />

(<br />

brukernavn varchar(20) NULL PRIMARY KEY,<br />

passord varchar(20) NULL,<br />

<strong>for</strong>navn varchar(20) NULL,<br />

etternavn varchar(20) NULL,<br />

adresse varchar(20) NULL,<br />

postnr varchar(20) NULL,<br />

poststed varchar(20) NULL,<br />

telefon varchar(20) NULL,<br />

status varchar(20) NULL<br />

);<br />

Handlevogn-tabellen inneholder alle varene kundene har plassert i handlevognene.<br />

Varer som er plassert i en handlevogn befinner seg i en midlertidig tilstand. De er valgt,<br />

eller reservert, men de er ikke kjøpt. Varene <strong>for</strong>blir i handlevognen helt til kunden<br />

bestiller varene eller angrer og fjerner varene fra handlevognen og plasserer varene tilbake<br />

på hyllene.


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 301 Tuesday, September 24, 2002 6:07 PM<br />

Figur <strong>16</strong>.5: Vareutvalg og prisliste<br />

Case-studie II : "e-sjappe"<br />

Handlevogn-tabellen består av tre felter – vognno, brukernavn og vareno. Heltallet vognno<br />

er en primærnøkkel som beskriver et unikt handlevognnummer <strong>for</strong> hver vare som<br />

plasseres i handlevognen. Brukernavn er en tekststreng som assosierer varen med kunden,<br />

og verdien korresponderer med brukernavn i kunde-tabellen. Det er nødvendig å<br />

identifisere kunden <strong>for</strong>di alle kunder deler handlevogn-tabellen, dvs. at handlevogntabellen<br />

inneholder alle handlevognene. Vareno er et heltall som identifiserer varen i<br />

handlevognen – verdien tilsvarer primærnøkkelen vareno i vare-tabellen. Handlevogn<br />

er definert som følger:<br />

create table handlevogn<br />

(<br />

vognnoint NOT NULL AUTO_INCREMENT PRIMARY KEY,<br />

brukernavn varchar(20) NULL,<br />

varenoint<br />

);<br />

301


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 302 Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

Figur <strong>16</strong>.6: En tom handlekurv<br />

302<br />

Varer som bestilles flyttes fra handlevogn-tabellen til bestilling. Bestilling-tabellen brukes<br />

av budet som leverer varen. Tabellen består av feltene bestno, brukernavn, vareno,<br />

dato og antall. Bestno er en primærnøkkel som angir et unikt heltall <strong>for</strong> hver varetype,<br />

brukernavn er en referanse til kunden, vareno er en referanse til varen, dato er en tekststreng<br />

som angir bestillingsdato og antall er et heltall som beskriver antall varer som er<br />

bestilt. Tabellen er definert som følger:<br />

create table bestilling<br />

(<br />

bestno int NOT NULL AUTO_INCREMENT PRIMARY KEY,<br />

brukernavn varchar(20) NULL,<br />

vareno int,<br />

dato varchar(20) NULL,<br />

antall int<br />

);<br />

Merk at tabellene er designet <strong>for</strong> å være enkle å <strong>for</strong>stå og at de der<strong>for</strong> ikke er normaliserte.<br />

Applikasjonen er avhengig av at tabellene allerede eksisterer. Databaseadministratoren<br />

er der<strong>for</strong> ansvarlig <strong>for</strong> å etablere tabellene før applikasjonen startes.<br />

Testing av applikasjonen <strong>for</strong>enkles med ferdige eksempler i tabellene. Applikasjonen<br />

kan <strong>for</strong> eksempel benyttes til å selge undervisningsmoduler, og vareutvalget kan<br />

fylles med følgende titler:


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 303 Tuesday, September 24, 2002 6:07 PM<br />

Figur <strong>16</strong>.7: Kunden velger varer fra vareutvalget.<br />

insert into vare values<br />

(<br />

NULL,'cpp',<br />

'Programmering i C++ med frode',<br />

'valgfag', 40, 38000<br />

);<br />

insert into vare values<br />

(<br />

NULL,'apput',<br />

'Applikasjonsutvikling i <strong>Java</strong> med frode',<br />

'valgfag', 80, 79000<br />

);<br />

insert into vare values<br />

(<br />

Case-studie II : "e-sjappe"<br />

303


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 304 Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

Figur <strong>16</strong>.8: Varer er plassert i handlekurven.<br />

304<br />

NULL,'sikkerhet',<br />

'Datasikkerhet med Mark',<br />

'valgfag', 80, 79000<br />

);<br />

insert into vare values<br />

(<br />

NULL,'grafikk',<br />

'Datagrafikk med Steinar',<br />

'valgfag', 20, 49000<br />

);<br />

insert into vare values<br />

(<br />

NULL,<br />

'num',<br />

'Numeriske metoder med Steinar',<br />

'valgfag', 10, 39000<br />

);


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 305 Tuesday, September 24, 2002 6:07 PM<br />

Figur <strong>16</strong>.9: Leveranselisten <strong>for</strong> en kunde<br />

Figur <strong>16</strong>.10: Kunden avslutter seansen ved å logge ut.<br />

insert into vare values<br />

(<br />

NULL,'num',<br />

'Kunstig intelligens med Eva',<br />

'valgfag', 40, 39000<br />

);<br />

Case-studie II : "e-sjappe"<br />

305


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 306 Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

Figur <strong>16</strong>.11: Applikasjonsnavigering <strong>for</strong> administratoren<br />

insert into vare values<br />

(<br />

NULL,'alg',<br />

'Algoritmer og datastrukturer med Ulf',<br />

'obligatorisk', 150, 79000<br />

);<br />

insert into vare values<br />

(<br />

NULL,<br />

'ark',<br />

'Maskinarkitektur med Lars',<br />

'obligatorisk', 150, 79000<br />

);<br />

insert into vare values<br />

(<br />

NULL,'unix',<br />

'Operativsystemer og Unix med Haarek',<br />

'obligatorisk', 150, 79000<br />

);<br />

insert into vare values<br />

(<br />

NULL,'java',<br />

'Programmering i java med Kjetil og Eva',<br />

306


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 307 Tuesday, September 24, 2002 6:07 PM<br />

Figur <strong>16</strong>.12: Personalregister<br />

'obligatorisk', 150, 79000<br />

);<br />

Case-studie II : "e-sjappe"<br />

Det er også svært nyttig å ha ferdigregistrerte brukere. Det er tidkrevende og irriterende<br />

å registrere en bruker hver gang applikasjonen startes.<br />

insert into kunde values<br />

(<br />

'palmer', 'hemmelig', 'Rosine', 'Rasmussen',<br />

'Bruveien 38','N-5254','Kristiansand','37 05 32 49','kunde'<br />

);<br />

insert into kunde values<br />

(<br />

'lex', 'drep superman', 'Lex', 'Luthor',<br />

'Hule ved Nationalteateret','N-0258','Oslo',<br />

'Hemmelig nummer','kunde'<br />

);<br />

insert into kunde values<br />

(<br />

'hansen', 'mr', 'ola', 'hansen',<br />

307


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 308 Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

Figur <strong>16</strong>.13: Kunderegister<br />

308<br />

'Bygdoy Alle 1','N-0256','Oslo','22 48 35 45','admin'<br />

);<br />

SQL-setningene definerer tre brukere – to ordinære kunder "palmer" og "lex", og administratoren<br />

"hansen".<br />

Under testing av en applikasjon kan det bli mye rot i tabellene. En effektiv <strong>for</strong>m <strong>for</strong><br />

rydding er å slette tabellene. Dette gjøres som følger:<br />

drop table vare;<br />

drop table kunde;<br />

drop table handlevogn;<br />

drop table bestilling;<br />

Implementering<br />

Applikasjonen er implementert som en servlet – sjappe. Servleten benytter følgende<br />

biblioteker:<br />

import java.io.*;<br />

import java.util.*;<br />

import javax.servlet.*;<br />

import javax.servlet.http.*;<br />

import java.sql.*;


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 309 Tuesday, September 24, 2002 6:07 PM<br />

Figur <strong>16</strong>.14: Registrering av ny vare<br />

Case-studie II : "e-sjappe"<br />

Klassen sjappe implementerer SingleThreadedModel <strong>for</strong> å garantere trådsikkerhet og<br />

unngå synkroniseringsproblemer (Se kapittel 21 <strong>for</strong> utfyllende in<strong>for</strong>masjon om SIngleThreadedInterface).<br />

public class sjappe<br />

extends HttpServlet<br />

implements SingleThreadModel<br />

{<br />

Sjappe har tre medlemsvariabler – jdbcDriver, dbURL og dbForbindelse. JdbcDriverstrengen<br />

beskriver databasedriveren, dbURL beskriver stien til databasen og dbForbindelse<br />

er en objektreferanse til en database<strong>for</strong>bindelse.<br />

private String jdbcDriver = "org.gjt.mm.mysql.Driver";<br />

private String dbURL = "jdbc:mysql://cube.iu.hio.no/frodes";<br />

private Connection dbForbindelse = null;<br />

Skapelse og destruksjon<br />

Servleten implementerer både init og destroy. Init laster inn databasedriveren og etablerer<br />

en <strong>for</strong>bindelse til databasen. Database<strong>for</strong>bindelsen er aktiv så lenge servleten ligger<br />

309


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 310 Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

310<br />

i tjenerens minne og brukes til å håndtere alle klienthenvendelser. Init varsler om en<br />

vellykket databasepålogging på tjenerens konsoll.<br />

public void init()<br />

{<br />

try // Åpne en database<strong>for</strong>bindelse og ha den klar.<br />

{<br />

Class.<strong>for</strong>Name(jdbcDriver).newInstance();<br />

dbForbindelse =<br />

DriverManager.getConnection(dbURL,"frodes","");<br />

System.out.println("Databasen pålogging ok");<br />

}<br />

catch (Exception e)<br />

{<br />

System.out.println("Feil: database pålogging: "<br />

+dbURL+e.getLocalizedMessage()+e.getMessage());<br />

}<br />

}<br />

Destroy-metoden kaller close-metoden på Connection-objektet. Resultatet er at database<strong>for</strong>bindelsen<br />

frigis.<br />

public void destroy()<br />

{<br />

try// Rydde opp<br />

{<br />

if (dbForbindelse != null)<br />

{<br />

dbForbindelse.close();<br />

}<br />

}<br />

catch (Exception e)<br />

{<br />

System.out.println("Feil: database frakobling: "<br />

+ dbURL+", "+e.getMessage());<br />

}<br />

}<br />

Hjelpemetoder<br />

Applikasjonen benytter en rekke selv<strong>for</strong>klarende hjelpemetoder – lagHtmlHode, lag-<br />

HtmlHale, knapp, resetknapp, åpneSkjema og lukkeSkjema. Hjelpefunksjonene skriver<br />

ut HTML-sekvenser som <strong>for</strong>ekommer ofte, og har mye til felles med tilsvarende hjelpemetoder<br />

som er beskrevet i case-studie I – spørreskjemaundersøkelse.<br />

private void lagHtmlHode(PrintWriter ut,<br />

String tittel,<br />

String instruksjon)<br />

{


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 311 Tuesday, September 24, 2002 6:07 PM<br />

ut.println("");<br />

ut.println("");<br />

ut.println(""+tittel+"");<br />

ut.println("");<br />

ut.println("");<br />

ut.println(""+tittel+"");<br />

ut.println(instruksjon+"");<br />

}<br />

private void lagHtmlHale(PrintWriter ut)<br />

{<br />

ut.println("");<br />

ut.println("");<br />

}<br />

private void knapp(PrintWriter ut,<br />

String tekst,<br />

String navn)<br />

{<br />

ut.println("");<br />

}<br />

private void resetKnapp(PrintWriter ut)<br />

{<br />

ut.println("");<br />

}<br />

private void åpneSkjema(PrintWriter ut)<br />

{<br />

ut.println("");<br />

}<br />

private void lukkeSkjema(PrintWriter ut)<br />

{<br />

ut.println("");<br />

}<br />

}<br />

Case-studie II : "e-sjappe"<br />

Applikasjonslogikk<br />

Applikasjonen implementerer service-metoden som fanger alle klient<strong>for</strong>espørsler.<br />

Først etableres et seanseobjekt. Hvis seanseobjektet er nytt, betyr det at applikasjonen<br />

ikke har en pågående seanse med klienten. I dette tilfellet returnerer applikasjonen et<br />

innloggingsskjema til brukeren (se figur <strong>16</strong>.2). Innloggingsskjemaet genereres av metoden<br />

logginn_skjerm.<br />

Forespørselen som genereres når brukeren fyller inn innloggingsskjemaet og trykker<br />

på innloggingsknappen, fanges av service som videre<strong>for</strong>midler kontrollen til<br />

311


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 312 Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

312<br />

valider_logginn-metoden. Valider_logginn (<strong>for</strong>klart i et senere avsnitt) returnerer en<br />

sannhetsverdi. Hvis denne verdien er "true" er innloggingsskjemaet gyldig og hovedsiden<br />

vises (vis_hovedside se figur <strong>16</strong>.4). Hvis sannhetsverdien derimot er "false", returneres<br />

en in<strong>for</strong>masjonsside som in<strong>for</strong>merer om at innloggingen ikke var vellykket<br />

(vis_beskjed).<br />

Strukturen på den resterende delen av service-metoden likner på strukturen i<br />

doPost-metoden i case-studie 1. Hver side i applikasjonen har navigeringsknapper.<br />

Service-metoden detekterer hvilke knapper som er benyttet av brukeren og benytter<br />

denne in<strong>for</strong>masjonen sammen med navigeringshierarkiet til å kalle de rette metodene.<br />

For eksempel inneholder hovedsiden (se figur <strong>16</strong>.4), som presenteres når brukeren logger<br />

seg inn, knapper <strong>for</strong> vareutvalg og handlekurv. Hvis brukeren trykker på knappen<br />

vareutvalg vil service-metoden detektere tilstedeværelsen av <strong>for</strong>espørselsstrengen "vareutvalg",<br />

og kalle metoden vis_varer som frembringer vareutvalgsiden (se figur <strong>16</strong>.5).<br />

Hvis brukeren derimot trykker på handlekurvknappen detekterer service <strong>for</strong>espørselstrengen<br />

"handlekurv", og kaller metoden vis_handlekurv som frembringer handlekurvsiden<br />

(se figur <strong>16</strong>.6).<br />

Videre, hvis brukeren trykker på en utloggingsknapp, detekterer service-metoden<br />

<strong>for</strong>espørselstrengen "loggut" og kaller invalidate på seanseobjektet etterfulgt av<br />

vis_beskjed-metoden. Vis_beskjed returnerer en in<strong>for</strong>masjonsside til brukeren med<br />

beskjed om at vedkommende er logget ut av systemet (se figur <strong>16</strong>.10). Invalidate deaktiverer<br />

seanseobjektet, slik at en ny <strong>for</strong>espørsel fra samme klient håndteres som en helt<br />

ny seanse.<br />

public void service(HttpServletRequest spørsmål,<br />

HttpServletResponse svar)<br />

throws IOException<br />

{<br />

svar.setContentType("text/html");<br />

PrintWriter ut = svar.getWriter();<br />

HttpSession s = spørsmål.getSession(true);<br />

if (s.isNew())<br />

{<br />

logginn_skjerm(ut);<br />

}<br />

else if (spørsmål.getParameter("validerlogginn")!= null)<br />

{<br />

if (valider_logginn(spørsmål))<br />

{<br />

vis_hovedside(spørsmål,ut);<br />

}<br />

else<br />

{<br />

beskjed_side(ut,"Mislykket logginn");<br />

}<br />

}<br />

else if (spørsmål.getParameter("nykunde") != null)


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 313 Tuesday, September 24, 2002 6:07 PM<br />

Case-studie II : "e-sjappe"<br />

{<br />

skjema_til_tabell(ut,"kunde");<br />

}<br />

else if (spørsmål.getParameter("nydata") != null)<br />

{<br />

nydata(spørsmål);<br />

vis_hovedside(spørsmål,ut);<br />

}<br />

else if (spørsmål.getParameter("loggut") != null)<br />

{<br />

s.invalidate();<br />

beskjed_side(ut,"Adjø, og velkommen tilbake");<br />

}<br />

else if (spørsmål.getParameter("vareutvalg") != null)<br />

{<br />

vis_varer(spørsmål,ut);<br />

}<br />

else if (spørsmål.getParameter("kjøpe") != null)<br />

{<br />

kjøpe_vare(spørsmål);<br />

vis_handlekurv(spørsmål,ut);<br />

}<br />

else if (spørsmål.getParameter("handlekurv") != null)<br />

{<br />

vis_handlekurv(spørsmål,ut);<br />

}<br />

else if (spørsmål.getParameter("fjerne") != null)<br />

{<br />

fjerne_fra_handlekurv(spørsmål);<br />

vis_handlekurv(spørsmål,ut);<br />

}<br />

else if (spørsmål.getParameter("fjernekunde") != null)<br />

{<br />

fjerne_kunde(spørsmål);<br />

vis_kunder(spørsmål,ut);<br />

}<br />

else if (spørsmål.getParameter("kunderegister") != null)<br />

{<br />

vis_kunder(spørsmål,ut);<br />

}<br />

else if (spørsmål.getParameter("personalregister")!=null)<br />

{<br />

vis_personell(spørsmål,ut);<br />

}<br />

else if (spørsmål.getParameter("leveranseliste")!= null)<br />

{<br />

vis_bestilling(spørsmål,ut);<br />

}<br />

313


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 314 Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

314<br />

else if (spørsmål.getParameter("bestill") != null)<br />

{<br />

bestill(spørsmål);<br />

vis_bestilling(spørsmål,ut);<br />

}<br />

else if (spørsmål.getParameter("tilkunde") != null)<br />

{<br />

vare_avlevert(spørsmål);<br />

vis_bestilling(spørsmål,ut);<br />

}<br />

else if (spørsmål.getParameter("nyvare") != null)<br />

{<br />

skjema_til_tabell(ut,"vare");<br />

}<br />

else if (spørsmål.getParameter("admin") != null)<br />

{<br />

vis_hovedside(spørsmål,ut);<br />

}<br />

else<br />

{<br />

s.invalidate();<br />

beskjed_side(ut,"Du er kastet ut av systemet");<br />

}<br />

}<br />

Skjermbilder <strong>for</strong> kunder<br />

Innloggingsskjermen (se figur <strong>16</strong>.2) genereres av metoden logginn_skjerm, som returnerer<br />

et enkelt skjema med et tekstfelt <strong>for</strong> brukernavn, et tekstfelt <strong>for</strong> passord, en knapp<br />

<strong>for</strong> å sende skjemaet tilbake til tjeneren og en knapp <strong>for</strong> kunderegistrering.<br />

public void logginn_skjerm(PrintWriter ut)<br />

{<br />

lagHtmlHode(ut,"Esjappe : Logg inn","");<br />

åpneSkjema(ut);<br />

ut.println("Brukeravn:"<br />

+""<br />

+"Passord:"<br />

+"");<br />

knapp(ut,"Logg inn","validerlogginn");<br />

knapp(ut,"Ny kunde","nykunde");<br />

lukkeSkjema(ut);<br />

lagHtmlHale(ut);<br />

}<br />

Innloggingsskjemaet som fylles inn av kunden og returneres til tjeneren valideres av<br />

valider_logginn-metoden.


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 315 Tuesday, September 24, 2002 6:07 PM<br />

Case-studie II : "e-sjappe"<br />

public boolean valider_logginn(<br />

HttpServletRequest spørsmål)<br />

{<br />

HttpSession s = spørsmål.getSession();<br />

try// Sjekker om bruker og passord er riktig<br />

{ // hvis ikke invalidiseres session-objektet.<br />

Statement stmt = dbForbindelse.createStatement();<br />

String sql = "select * from kunde where brukernavn='"<br />

+spørsmål.getParameter("navn")+"';";<br />

ResultSet rs = stmt.executeQuery(sql);<br />

rs.next();<br />

String passord = spørsmål.getParameter("passord");<br />

if (passord.equals(rs.getString("passord")))<br />

{<br />

s.setAttribute("brukernavn",<br />

rs.getString("brukernavn"));<br />

s.setAttribute("status",<br />

rs.getString("status"));<br />

rs.close();<br />

stmt.close();<br />

return true;<br />

}<br />

else<br />

{<br />

s.invalidate();<br />

}<br />

}<br />

catch (Exception e)<br />

{<br />

s.invalidate();<br />

}<br />

return false;<br />

}<br />

Valider_logginn sender en <strong>for</strong>espørsel til databasen <strong>for</strong> å fremhente in<strong>for</strong>masjon om<br />

kunden. SQL-setningen som benyttes er:<br />

select *<br />

from kunde<br />

where brukernavn='(BRUKERNAVN)';<br />

Hvis kunden ikke er registrert, returnerer valider_logginn sannhetsverdien "false". Hvis<br />

kunden er registrert i databasen, sammenliknes det lagrede passordet med det passordet<br />

som er oppgitt av brukeren. Hvis passordene er identiske gis brukeren adgang til<br />

nettbutikken, brukernavnet lagres i seanseobjektet på tjeneren sammen med brukerens<br />

status som er gitt av status-attributten i bruker-tabellen (enten "kunde" eller "admin"),<br />

og valider_logginn returnerer sannhetsverdien "true". Hvis passordet i databasen og<br />

315


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 3<strong>16</strong> Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

3<strong>16</strong><br />

passordet på innloggingsskjemaet er ulike, nektes kunden adgang til nettbutikken og<br />

valider_logginn returnerer "false".<br />

Metoden beskjed_side returnerer en enkel side med en beskjed til brukeren – vanligvis<br />

en beskjed om at noe er galt.<br />

public void beskjed_side(PrintWriter ut,String beskjed)<br />

{<br />

lagHtmlHode(ut,"Esjappe : "+beskjed,<br />

"For å logge inn klikk her");<br />

lagHtmlHale(ut);<br />

}<br />

Hovedsiden, som vises når brukeren er innlogget, genereres av vis_hovedside (se figur<br />

<strong>16</strong>.4).<br />

public void vis_hovedside(HttpServletRequest spørsmål,<br />

PrintWriter ut)<br />

{<br />

lagHtmlHode(ut,"Velkommen til esjappa "<br />

+getBrukernavn(spørsmål),"");<br />

åpneSkjema(ut);<br />

knapp(ut,"Vareutvalg","vareutvalg");<br />

knapp(ut,"Handlekurv","handlekurv");<br />

knapp(ut,"bestilling","leveranseliste");<br />

if (erAdmin(spørsmål)) // Dette er administratøren.<br />

{<br />

knapp(ut,"Personalregister","personalregister");<br />

knapp(ut,"Kunderegister","kunderegister");<br />

knapp(ut,"ny ansatt","nykunde");<br />

knapp(ut,"ny vare","nyvare");<br />

}<br />

knapp(ut,"Logg ut","loggut");<br />

ut.println(""<br />

+"Avslutte");<br />

lukkeSkjema(ut);<br />

lagHtmlHale(ut);<br />

}<br />

Hovedsiden består av navigeringsknapper som gir tilgang de andre sidene i applikasjonen.<br />

Fire knapper er reservert brukere med administratorstatus – personalregister,<br />

kunderegister, ny ansatt og ny vare. Disse knappene vises der<strong>for</strong> kun hvis brukeren har<br />

"admin"-status (se figur <strong>16</strong>.11). erAdmin er en hjelpemetode som henter brukerens status<br />

fra seanseobjektet, og hjelpemetoden getBrukernavn henter brukerens brukernavn.<br />

De fire resterende knappene vareutvalg, handlekurv, bestilling, loggut er tilgjengelige<br />

<strong>for</strong> alle brukere.


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 317 Tuesday, September 24, 2002 6:07 PM<br />

Case-studie II : "e-sjappe"<br />

public boolean erAdmin(HttpServletRequest spørsmål)<br />

{<br />

return (((String)spørsmål.getSession().getAttribute(<br />

"status")).equals("admin"));<br />

}<br />

public String getBrukernavn(HttpServletRequest spørsmål)<br />

{<br />

return (String)spørsmål.getSession().getAttribute(<br />

"brukernavn");<br />

}<br />

Metoden vis_varer genererer siden som lister vareutvalget (se figurene <strong>16</strong>.5 og <strong>16</strong>.7).<br />

Vareutvalgssiden består av en tabell og navigeringsknapper. Varetabellen genereres av<br />

hjelpemetoden vis_tabell (se avsnittet om databasehåndtering), som henter vareutvalgtabellen<br />

fra databasen.<br />

public void vis_varer(HttpServletRequest spørsmål,<br />

PrintWriter ut)<br />

{<br />

lagHtmlHode(ut,"Vareutvalg "+getBrukernavn(spørsmål),"");<br />

åpneSkjema(ut);<br />

vis_tabell("vare","", ut,true);<br />

knapp(ut,"Kjøp varer","kjøpe");<br />

knapp(ut,"Se handlekurv","handlekurv");<br />

knapp(ut,"Administrere","admin");<br />

knapp(ut,"Logg ut","loggut");<br />

resetKnapp(ut);<br />

lukkeSkjema(ut);<br />

lagHtmlHale(ut);<br />

}<br />

select *<br />

from vare;<br />

Varetabellen frembringes med følgende SQL-setning:<br />

Metoden vis_handlekurv returnerer en side som viser kundens handlekurv (se figurene<br />

<strong>16</strong>.6 og <strong>16</strong>.8). I likhet med vis_varer består siden av tabeller og navigeringsknapper.<br />

Tabellene frembringes med metoden vis_avansert_tabell (vis_avansert_tabell er beskrevet<br />

i et senere avsnitt). Den første tabellen viser kundens handlekurv og frembringes<br />

med følgende SQL-setning:<br />

Select vognno, navn, beskrivelse, pris<br />

from vare, handlevogn<br />

where vare.vareno=handlevogn.vareno<br />

and brukernavn='brukernavn';<br />

317


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 318 Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

318<br />

Setningen demonstrerer hvordan en tabell med ønskede kolonner (navn, beskrivelse og<br />

pris) fremhentes basert på tabellene vare og handlevogn. I tillegg demonstrerer setningen<br />

hvordan synlighetsoperatoren "." benyttes til å spesifisere hvilket vareno det refereres<br />

til – i dette tilfellet vareno i tabellen vare.<br />

Den andre tabellen består kun av én celle, nemlig totalkostnadene av varene i handlevognen.<br />

Summen regnes ut direkte fra databasen ved hjelp av summen i følgende<br />

SQL-setning:<br />

select sum(pris)<br />

from vare, handlevogn<br />

where vare.vareno=handlevogn.vareno;<br />

Vis_handlevogn er implementert som følger:<br />

public void vis_handlekurv(HttpServletRequest spørsmål,<br />

PrintWriter ut)<br />

{<br />

lagHtmlHode(ut,"Handlekurv "+getBrukernavn(spørsmål),<br />

"Du har puttet følgende varer i handlekurven");<br />

åpneSkjema(ut);<br />

vis_avansert_tabell("handlevogn",<br />

new String[] {"vognno","navn",<br />

"beskrivelse","pris"},<br />

"select vognno, navn, beskrivelse, pris "+<br />

"from vare, handlevogn "+<br />

"where vare.vareno=handlevogn.vareno "+<br />

"and brukernavn='"+getBrukernavn(spørsmål)<br />

+"';",ut,true);<br />

vis_avansert_tabell("handlevogn",<br />

new String[] {"pris å betale"},<br />

"select sum(pris) from vare, handlevogn "+<br />

"where vare.vareno=handlevogn.vareno;",<br />

ut,false);<br />

knapp(ut,"Ta ut av handlekurv","fjerne");<br />

knapp(ut,"Se vareutvalg","vareutvalg");<br />

knapp(ut,"Send bestilling","bestill");<br />

knapp(ut,"Administrere","admin");<br />

knapp(ut,"Logg ut","loggut");<br />

resetKnapp(ut);<br />

lukkeSkjema(ut);<br />

lagHtmlHale(ut);<br />

}<br />

Metoden vis_bestilling genererer dokumenter som viser kundenes leveranselister (se<br />

figur <strong>16</strong>.9). Sidens ut<strong>for</strong>ming er avhengig av brukerens status. Brukere med "admin"status<br />

kan slette oppføringer på leveranselisten, dvs. at varen er levert. Vis_bestilling<br />

kaller metoden vis_tabell som henter bestillingstabellen fra databasen og plasserer innholdet<br />

i dokumentet.


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 319 Tuesday, September 24, 2002 6:07 PM<br />

Case-studie II : "e-sjappe"<br />

public void vis_bestilling(HttpServletRequest spørsmål,<br />

PrintWriter ut)<br />

{<br />

String hvis = new String();<br />

if (!erAdmin(spørsmål))// hvis det er en vanlig kunde<br />

{<br />

hvis = "where brukernavn='"<br />

+getBrukernavn(spørsmål)+"'";<br />

}<br />

lagHtmlHode(ut,"Leveranseliste "<br />

+getBrukernavn(spørsmål),"");<br />

åpneSkjema(ut);<br />

vis_tabell("bestilling",hvis, ut,erAdmin(spørsmål));<br />

knapp(ut,"Administrere","admin");<br />

if (erAdmin(spørsmål))// Kun admin kan slette varer<br />

{<br />

knapp(ut,"Vare avlevert","tilkunde");<br />

}<br />

knapp(ut,"Logg ut","loggut");<br />

resetKnapp(ut);<br />

lukkeSkjema(ut);<br />

lagHtmlHale(ut);<br />

}<br />

Skjermbilder <strong>for</strong> administrator<br />

Applikasjonen består av to sider som kun er tilgjengelige <strong>for</strong> administratorer – en kundeliste<br />

(se figur <strong>16</strong>.13) og en personalliste (se figur <strong>16</strong>.12). Sidene genereres henholdsvis<br />

med metodene vis_kunder og vis_personell:<br />

public void vis_kunder(HttpServletRequest spørsmål,<br />

PrintWriter ut)<br />

{<br />

lagHtmlHode(ut,"Kunderegister "<br />

+getBrukernavn(spørsmål),"");<br />

åpneSkjema(ut);<br />

vis_tabell("kunde","where status="kunde"", ut, true);<br />

knapp(ut,"Administrere","admin");<br />

knapp(ut,"Fjerne kunde","fjernekunde");<br />

knapp(ut,"Logg ut","loggut");<br />

resetKnapp(ut);<br />

lukkeSkjema(ut);<br />

lagHtmlHale(ut);<br />

}<br />

public void vis_personell(HttpServletRequest spørsmål,<br />

PrintWriter ut)<br />

{<br />

319


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 320 Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

320<br />

lagHtmlHode(ut,"Personalregister "<br />

+getBrukernavn(spørsmål),"");<br />

åpneSkjema(ut);<br />

vis_tabell("kunde","where status="admin"", ut, true);<br />

knapp(ut,"Administrere","admin");<br />

knapp(ut,"Sparke ansatt","fjernekunde");<br />

knapp(ut,"Logg ut","loggut");<br />

resetKnapp(ut);<br />

lukkeSkjema(ut);<br />

lagHtmlHale(ut);<br />

}<br />

Hver side viser en tabell med brukere og navigeringsknapper. Følgende SQL-setning<br />

frembringer kundelisten:<br />

select *<br />

from kunde<br />

where status='kunde';<br />

og personallisten frembringes med SQL-setningen:<br />

select *<br />

from kunde<br />

where status='admin'<br />

Metoden vis_tabell, som henter frem tabellene, er beskrevet i neste avsnitt.<br />

Databasemanipulasjon<br />

Dette avsnittet beskriver metodene som gjør inngrep og modifiserer tabellene i databasen.<br />

Den første metoden kjøpe_vare kalles når en kunde velger en vare fra handlelisten<br />

og trykker på "kjøp"-knappen. Vareutvalgssiden tillater brukeren kun å velge én vare av<br />

gangen. Valget overføres til tjeneren i <strong>for</strong>espørselstrengen "vare". Metoden er implementert<br />

som følger:<br />

public void kjøpe_vare(HttpServletRequest spørsmål)<br />

{<br />

// kopiere til handlekurv<br />

oppdater_tabell("insert into handlevogn values ( NULL,'"<br />

+getBrukernavn(spørsmål)+"', "<br />

+spørsmål.getParameter("vare")+" );");<br />

// trekke fra beholding<br />

oppdater_tabell("update vare "<br />

+"set beholdning=(beholdning-1) "<br />

+"where vareno="+<br />

spørsmål.getParameter("vare"));<br />

}


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 321 Tuesday, September 24, 2002 6:07 PM<br />

Case-studie II : "e-sjappe"<br />

Metoden kaller oppdater_tabell to ganger. Først kopieres varen inn i handlekurven med<br />

SQL-setningen:<br />

insert into handlevogn<br />

values<br />

(<br />

NULL,<br />

'(BRUKERNAVN)',<br />

"(vareID)"<br />

);<br />

hvor (BRUKERNAVN) angir brukerens brukernavn og (vareID) er identifikasjonskoden<br />

som beskriver varen (primærnøkkelen i vare-tabellen). Deretter trekkes en vare<br />

fra beholdningen i varetabellen med følgende SQL-setning.<br />

update vare<br />

set beholdning=(beholdning-1)<br />

where vareno=(vareID);<br />

Metodene fjerne_fra_handlekurv, fjerne_kunde og vare_avlevert har det til felles at de<br />

fjerner oppføringer fra tabeller. Fjerne_fra_handlekurv brukes til å oppdatere handlekurven<br />

når en bruker angrer og tar en vare ut av handlekurven. Fjerne_kunde benyttes<br />

av administratoren til å slette en ansatt eller en kunde fra registeret. Ansatte som slutter<br />

å arbeide i organisasjonen fjernes fra personalregisteret, i likhet med uønskede kunder.<br />

Vare_avlevert fjerner en vare fra bestillingslisten, når et bud har levert varen til kunden.<br />

De tre metodene er implementert som følger:<br />

public void fjerne_fra_handlekurv(<br />

HttpServletRequest spørsmål)<br />

{<br />

oppdater_tabell("delete from handlevogn where vognno=""<br />

+spørsmål.getParameter("handlevogn")+"";");<br />

}<br />

public void fjerne_kunde(HttpServletRequest spørsmål)<br />

{<br />

oppdater_tabell("delete from kunde where brukernavn=""<br />

+spørsmål.getParameter("kunde")+"";");<br />

}<br />

public void vare_avlevert(HttpServletRequest spørsmål)<br />

{<br />

oppdater_tabell("delete from bestilling where bestno=""<br />

+spørsmål.getParameter("bestilling")<br />

+"";");<br />

}<br />

Alle metodene benytter en SQL-setning med følgende struktur:<br />

321


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 322 Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

delete<br />

from tabellnavn<br />

where primærnøkkel=element_som_skal_slettes;<br />

322<br />

bestill kalles når brukeren bestemmer seg <strong>for</strong> å kjøpe varene som er plassert i handlekurven.<br />

Varene må da "flyttes" fra handlekurvtabellen til bestillingstabellen. Flytteoperasjonen<br />

utføres ved å kopiere varene i handlekurvtabellen til bestillingstabellen og deretter<br />

slette varene fra handlekurven:<br />

public void bestill(HttpServletRequest spørsmål)<br />

{<br />

try// Vi leser inn alle varene i handlevognen<br />

{ // flytter disse til bestillingstabellen.<br />

Statement stmt = dbForbindelse.createStatement();<br />

String sql = "select * from handlevogn "<br />

+"where brukernavn='"<br />

+getBrukernavn(spørsmål)+"';";<br />

ResultSet rs = stmt.executeQuery(sql);<br />

while (rs.next())<br />

{<br />

oppdater_tabell("insert into bestilling values"+<br />

" (NUll,'"+<br />

rs.getString("brukernavn")+"', '"+<br />

rs.getInt("vareno")+"', '"+<br />

new java.util.Date()+"',1);");<br />

}<br />

rs.close();<br />

stmt.close();<br />

oppdater_tabell("delete from handlevogn");<br />

}<br />

catch (Exception e)<br />

{<br />

}<br />

}<br />

Elementene hentes ut fra handlevogntabellen med SQL-setningen:<br />

select *<br />

from handlevogn<br />

where brukernavn='(BRUKERNAVN)';<br />

Bestill-metoden benytter en while-løkke som itererer gjennom alle radene i tabellen.<br />

For hver rad i handlevogntabellen settes det en vare inn i bestillingstabellen, med SQLsetningen:<br />

insert into bestilling<br />

values<br />

(<br />

NUll,


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 323 Tuesday, September 24, 2002 6:07 PM<br />

'(BRUKERNAVN)',<br />

'(vareID)',<br />

'(nåværende tid og klokkeslett)',<br />

1<br />

);<br />

Til slutt slettes innholdet i handlekurven:<br />

delete<br />

from handlevogn<br />

where brukernavn=(BRUKERNAVN);<br />

Case-studie II : "e-sjappe"<br />

En hjelpemetode som benyttes mye er vis_tabell. Vis_tabell tar fire parametere; navnet<br />

på tabellen som skal vises, en tekststreng ekstra som kan benyttes til å spesifisere valgkriterier<br />

i SQL-setningen (where ...), et skriveobjekt og en sannhetsverdi lagRadio. Hvis<br />

lagradio har verdien "true" plasseres en radioknapp <strong>for</strong>an hver rad i tabellen.<br />

public void vis_tabell(String tabell,<br />

String extra,<br />

PrintWriter ut,<br />

boolean lagRadio)<br />

{<br />

try // Først skrive ut hode på tabellen<br />

{<br />

Statement stmt = dbForbindelse.createStatement();<br />

String sql = "show columns from "+tabell+";";<br />

ResultSet rs = stmt.executeQuery(sql);<br />

ut.print("");<br />

int rader=0;<br />

if (lagRadio)<br />

{<br />

ut.println("Velg");<br />

}<br />

while (rs.next())<br />

{<br />

rader++;<br />

ut.println(""<br />

+rs.getObject(1)+"");<br />

}<br />

sql = "select * from "+tabell+" "+extra+";";<br />

vis_tabell_kropp(ut,sql,tabell,rader,lagRadio);<br />

}<br />

catch (Exception e)<br />

{<br />

ut.println("Kan ikke utføre operasjonen: "<br />

323


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 324 Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

324<br />

}<br />

}<br />

+e.getMessage());<br />

Første rad i tabellen består av et hode som beskriver kolonnen. Dette hodet frembringes<br />

med SQL-setningen:<br />

show columns<br />

from (tabell_navn);<br />

Radene med data vises av vis_tabell_kropp som kalles mot slutten av vis_tabell.<br />

Vis_tabell_kropp har parameteren sql, som inneholder SQL-setningen som henter den<br />

ønskede tabellen. Parameteren lagRadio videre<strong>for</strong>midles til vis_tabell:<br />

public void vis_tabell_kropp(PrintWriter ut,<br />

String sql,<br />

String tabell,<br />

int rader,<br />

boolean lagRadio)<br />

{<br />

try<br />

{<br />

Statement stmt = dbForbindelse.createStatement();<br />

ResultSet rs = stmt.executeQuery(sql);<br />

while (rs.next())<br />

{<br />

ut.print("");<br />

if (lagRadio)<br />

{<br />

ut.println("");<br />

}<br />

<strong>for</strong> (int i=1;i


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 325 Tuesday, September 24, 2002 6:07 PM<br />

}<br />

{<br />

ut.println("Kan ikke utføre operasjonen: "<br />

+e.getMessage());<br />

}<br />

Metoden oppdater_tabell kalles mange steder i koden:<br />

Case-studie II : "e-sjappe"<br />

public void oppdater_tabell(String sql)<br />

{<br />

try // Hjelpefunksjon <strong>for</strong> SQL oppdatering.<br />

{<br />

Statement stmt = dbForbindelse.createStatement();<br />

int rader_affektert = stmt.executeUpdate(sql);<br />

stmt.close();<br />

}<br />

catch (Exception e)<br />

{<br />

System.out.println("Kan ikke utføre operasjonen: "<br />

+e.getMessage());<br />

}<br />

}<br />

Metodens parameter består av SQL-setningen som benyttes i kallet til executeUpdate på<br />

kommandoobjektet, og metoden benyttes der<strong>for</strong> til å sette inn, slette og oppdatere<br />

rader i tabeller.<br />

Metoden vis_avansert_tabell har mye til felles med vis_tabell. Hoved<strong>for</strong>skjellen er<br />

at den første raden i tabellen, som beskriver innholdet av kolonnene, er gitt av parameteren<br />

– hode, et array med strenger. Metoden benytter en <strong>for</strong>løkke som genererer den<br />

første raden basert på innholdet i strengarrayet. Deretter kalles vis_tabell_kropp som<br />

viser selve tabellen:<br />

public void vis_avansert_tabell(String tabell,<br />

String[] hode,<br />

String sql,<br />

PrintWriter ut,<br />

boolean lagRadio)<br />

{<br />

try // Først skrive ut hode på tabellen<br />

{<br />

ut.print("");<br />

if (lagRadio)<br />

{<br />

ut.println("Velg");<br />

}<br />

<strong>for</strong> (int i=0;i


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 326 Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

326<br />

{<br />

ut.println(""+hode[i]+"");<br />

}<br />

vis_tabell_kropp(ut,sql,tabell,hode.length,lagRadio);<br />

}<br />

catch (Exception e)<br />

{<br />

ut.println("Kan ikke utføre operasjonen: "<br />

+e.getMessage());<br />

}<br />

}<br />

Skjemaer<br />

Det er to situasjoner hvor brukeren oppgir data ved å fylle inn skjemaer – ved registrering<br />

av nye kunder (se figur <strong>16</strong>.3) og ved registrering av nye varer (se figur <strong>16</strong>.4). Til<br />

dette benyttes metoden skjema_til_tabell, som genererer skjemaer basert på attributtene<br />

til en tabell.<br />

Metoden tar tabellens navn som parameter, og sender SQL-setningen "show<br />

columns from tabellnavn" til databasen. En tabell som inneholder navnet på alle attributtene<br />

i første kolonne returneres. Metoden itererer gjennom attributtene og lager et<br />

tekstfelt <strong>for</strong> hver attributt med navnet på attributten som <strong>for</strong>klarende tekst. Denne<br />

generiske metoden er der<strong>for</strong> i stand til å dynamisk generere skjemaer <strong>for</strong> vilkårlige<br />

tabeller. Hvert tekstfelt navngis med en tallkode i økende rekkefølge ("1", "2", "3" osv.).<br />

Brukeren fyller inn skjemaet og sender det tilbake til tjeneren. Kontrollen videre<strong>for</strong>midles<br />

til nydata som leser de utfylte feltene fra <strong>for</strong>espørselstrengen og plasserer<br />

in<strong>for</strong>masjonen i databasen med en insert-setning. Insert-setningen genereres dynamisk<br />

avhengig av hvor mange kolonner det er i tabellen.<br />

public void skjema_til_tabell(PrintWriter ut,<br />

String tabell)<br />

{<br />

try// Dynamisk skjema basert på kolonnene i en tabell.<br />

{<br />

lagHtmlHode(ut,"Fyll inn "+tabell+"detaljer",<br />

"Fyll inn feltene og trykk på send knapen.");<br />

åpneSkjema(ut);<br />

Statement stmt = dbForbindelse.createStatement();<br />

String sql = "show columns from "+tabell+";";<br />

ResultSet rs = stmt.executeQuery(sql);<br />

int kolonner=0;<br />

ut.println("");<br />

while (rs.next())<br />

{<br />

kolonner++;<br />

ut.println(""<br />

+rs.getObject(1)


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 327 Tuesday, September 24, 2002 6:07 PM<br />

Case-studie II : "e-sjappe"<br />

+""<br />

+"");<br />

}<br />

ut.println("");<br />

rs.close();<br />

stmt.close();<br />

knapp(ut,"Send","nydata");<br />

resetKnapp(ut);<br />

ut.println("");<br />

lukkeSkjema(ut);<br />

lagHtmlHale(ut);<br />

}<br />

catch (Exception e)<br />

{<br />

ut.println("Kan ikke utføre operasjonen: "<br />

+e.getMessage());<br />

}<br />

}<br />

public void nydata(HttpServletRequest spørsmål)<br />

{ // legger data fra skjema inn i databasen.<br />

String sql = "insert into "<br />

+spørsmål.getParameter("tabell")<br />

+" values ('"+spørsmål.getParameter("1");<br />

int paramno=1;<br />

while (spørsmål.getParameter(""+(++paramno)) != null)<br />

{<br />

sql = sql + "','" + spørsmål.getParameter(""+paramno);<br />

}<br />

sql = sql+"');";<br />

oppdater_tabell(sql);<br />

}<br />

Veien videre<br />

Dette kapitlet viser hvordan en e-butikk implementeres ved å benytte en MySQLrelasjonsdatabase<br />

til oppbevaring av applikasjonsdata. Neste del av boken beskriver<br />

JSP (<strong>Java</strong> Server Pages)-teknologien som <strong>for</strong>enkler arbeidet med å utvikle avanserte<br />

webapplikasjoner.<br />

327


<strong>Java</strong> <strong>for</strong> <strong>Web</strong>.book Page 328 Tuesday, September 24, 2002 6:07 PM<br />

<strong>Kap</strong>ittel <strong>16</strong><br />

328<br />

Oppgaver<br />

1 Hvordan kan tabellene i "e-sjappe"-applikasjonen omstruktureres slik at de er normaliserte?<br />

2 Utvid "e-sjappe"-applikasjonen slik at den sjekker om de nødvendige tabellene, med<br />

de riktige, feltene eksisterer når applikasjonen starter. Hvis de nødvendige tabellene<br />

ikke eksisterer skal applikasjonen opprette de ønskede tabellene.<br />

3 Metoden bestill benytter seg av en <strong>for</strong>løkke. Er det mulig å utføre denne operasjonen<br />

kun ved bruk av SQL?<br />

4 Hvor "innbruddssikker" er applikasjonen?<br />

5 Utvid applikasjonen ved å tilføre klientsidevalidering av skjemaer.<br />

6 Applikasjonen er implementert som en servlet. Omstrukturer applikasjonen slik at det<br />

er en separat servlet <strong>for</strong> kunder og en <strong>for</strong> administratorer.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!