Kap 16_Java for Web.pdf - Akademika forlag
Kap 16_Java for Web.pdf - Akademika forlag
Kap 16_Java for Web.pdf - Akademika forlag
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.