Web- og serverprogrammering

Dette materiale er under Åben Dokumentlicens, se http://www.sslug.dk/linuxbog/licens.html

Databasekommunikation - dag 6

Strategier til databaseadgang

JDBC (Java DataBase Connectivity)

JDBC RowSet

Login-eksempel: Javabønne med JDBC

Evt.: JSF fortsat

Læsning: WJSP 5, WJSP 9.5-9.7

2.8.1 Læse filer fra harddisken 37

2.8.2 Erklæring af metoder og blivende variabler 38

2.8.3 Trådsikkerhed i JSP-sider 39

2.8.4 Producere grafik fra JSP 40

2.8.5 Eksempel: JSP-side der danner et JPG-billede 40

2.8.6 Indlejre og nedskalere billeder fra harddisken 43

2.8.7 Opload af filer til server 44

3.6 Avanceret 58

3.6.1 Indkode data i en URL (URL-indkodning) 58

3.6.2 Skjulte felter i formularer 59

3.6.3 Bruge skjulte felter til at etablere et forløb 60

3.6.4 Skjule parametrene (POST-metoden) 60

3.6.5 Cookier 61

3.6.6 Sætte cookier 62

3.6.7 Aflæse cookier 62

3.7 Avanceret: HTTP-protokollen 64

3.7.1 Eksempel på kommunikation 64

3.7.2 Formulardata med GET-metoden 65

3.7.3 Formulardata med POST-metoden 66

3.7.4 Cookier 66

3.7.5 Øvelse 66

4.3 Omdirigering 73

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

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

4.4 Appendiks: Almindelige JSP-koder 75

4.5 Appendiks: Implicit definerede objekter 76

4.5.1 request - anmodningen fra klienten 76

4.5.2 response - svaret til klienten 77

4.5.3 out - skrive tekst til klienten 77

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

4.5.5 application - fælles for hele webapplikationen 79

4.5.6 config - den enkelte websides konfiguration 80

4.5.7 page - selve JSP-siden 81

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

4.5.9 pageContext - alle objekterne samlet i ét 81

4.6 Opgaver 82

7.1 Servletter 130

7.1.1 Anmodningsmetoder 131

7.1.2 Hvornår bruge JSP og hvornår bruge servletter 131

7.3 Avanceret: JSP-siders interne virkemåde 133

7.3.1 Kigge i de genererede servletter 133

7.3.2 Eksempel 133

7.3.3 JSP-siders livscyklus 135

Opgaverne sidste gang

Eksamensprojektet

Næste gang: Fremlæggelse/status på projekter

Henrik: Fotoklub

Kim D: Netbanken

Anne

Lis: Opgaveafleveringsregistrering (dueslaget)

Bjarne H

Bjarne J: Produktionsstoptidsregistrering (periode, årsag, rapporter)

Kim J

Ole Hedevang: Webbutik

Tommy: Kajakklub

Jesper

Sven-Erik og Morten: E-handel (nok tøjbutik)

Preben: Konfigurator (en slags e-handel)

Svend

Klaus Elmquist: Procedurale mønstre

Per: Hotelinformationssystem (bestilling af roomservice, bord, regning, turistinfo)

Stefan

Ratha: Internet-butik om blomster

Christian

Persistensproblemet
Strategier til databaseadgang

Rigtig mange muligheder, f.eks.:

JDBC-kode blandet sammen med resten af koden

JDBC-kode i dedikerede klasser

JDBC RowSet - ResultSet, der også opdaterer databasen

CachedRowSet - kan eksistere løsrevet fra databasen

WebRowSet giver XML, der kan transformeres, f.eks. med

XSLT (XSL style sheet)

Javas XML-behandling

EJB - Enterprise JavaBeans - ét serverobjekt pr. række

JDO - Java Data Objects - ét objekt pr. række

Proprietære løsninger

Giver mulighed for grafiske databasekomponenter

Oracle JDeveloper ADF - Application Developer Framework

Borland JBuilder: DataModule

IBM WebSphere Studio

Bedste løsning? Afhænger af omstændighederne!

Hvor omfattende databasedelen af ens applikation er

Hvor meget man forventer den senere skal vedligeholdes.

JDBC – databaseadgang

JDBC – databaseadgang

JDBC-ODBC-bro til Access-fil

Eksempel:

1. Denne computer

2. Kontrolpanel

3. Administration

4.

5.

6

7

MySQL-database

Installér MySQL

Hent fra mysql.com

test-database god i starten

Grafiske værktøjer

Installér JDBC-driver

Connector/J fra mysql.com

Læg JAR-fil i java/jre/lib/ext/

Kontakt test-database:

Forberedte SQL-kommandoer

import java.sql.*;

public class ForberedtSQL {

public static void main(String[] arg) throws Exception

{

Class.forName("com.mysql.jdbc.Driver");

Connection con = DriverManager.getConnection("jdbc:mysql:///test");

// Forbered kommandoerne til databasen, f.eks. i starten af programmet:

PreparedStatement indsætPstm = con.prepareStatement(

"INSERT INTO kunder (navn,kredit) VALUES(?, ?)");

PreparedStatement hentPstm = con.prepareStatement(

"SELECT navn, kredit FROM kunder WHERE navn=?");

// under programudførelsen kan de forberedte kommandoer udføres mange gange:

for (int i=0; i<100; i++)

{

indsætPstm.setString(1, "Brian");

indsætPstm.setInt(2, i);

indsætPstm.execute();

indsætPstm.setString(1, "Hans' venner"); // bemærk ' i strengen

indsætPstm.setInt(2, 1042+i);

indsætPstm.execute();

hentPstm.setString(1, "Hans' venner"); // bemærk ' i SQL-forespørgslen

ResultSet rs = hentPstm.executeQuery();

// man løber igennem svaret som man plejer

while (rs.next())

{

String navn = rs.getString(1);

double kredit = rs.getDouble(2);

System.out.println(navn+" "+kredit);

}

}

}

}

Samlede batch-opdateringer

import java.sql.*;

public class Batchopdateringer

{

public static void main(String[] arg) throws Exception

{

Class.forName("com.mysql.jdbc.Driver");

Connection con = DriverManager.getConnection("jdbc:mysql:///test");

PreparedStatement pstmt = con.prepareStatement(

"INSERT INTO kunder (navn,kredit) VALUES(?, ?)");

pstmt.setString(1, "Hans");

pstmt.setInt(2, 142);

pstmt.addBatch();

pstmt.setString(1, "Grethe");

pstmt.setInt(2, 242);

pstmt.addBatch();

// send ændringer til databasen

pstmt.executeBatch();

}

}

Uden automatisk commit

import java.sql.*;

public class UdenAutocommit

{

public static void main(String[] arg) throws Exception

{

Class.forName("oracle.jdbc.driver.OracleDriver");

Connection forb = DriverManager.getConnection(

"jdbc:oracle:thin:@ora.javabog.dk:1521:student","jacob","jacob");

try {

forb.setAutoCommit(false);

Statement stmt = forb.createStatement();

stmt.executeUpdate("insert into KUNDER(NAVN,KREDIT) values('Jacob',-17)");

stmt.executeUpdate("insert into KUNDER(NAVN,KREDIT) values('Brian', 0)");

// flere transaktioner ...

System.err.println("Alt gik godt, gør ændringerne forpligtigende");

forb.commit();

}

catch (Exception e)

{

e.printStackTrace();

System.err.println("Noget gik galt! Annullerer ændringerne...");

forb.rollback();

}

finally

{

// Husk at sætte auto-commit tilbage, af hensyn til andre transaktioner

forb.setAutoCommit(true);

}

}

}

Rydde op med finally

Finally-blokke bliver altid udført, selv når undtagelsen ikke fanges, eller der hoppes ud af metoden på anden vis

public void metode1()

{

try

{

...

if (...) return;

if (...) throw new IllegalArgumentException(...);

...

}

catch (NullPointerException e)

{

System.out.println("Intern fejl:");

e.printStackTrace();

}

finally

{

System.out.println("Dette bliver altid udført.");

}

System.out.println("Slut på metode1()");

}

Metadata

import java.sql.*;

public class BenytMetadataOgUdskrivTabel

{

/** Udskriver et ResultSet pænt. Finder selv ud af kolonnenavnene. */

public static void udskriv(String titel, ResultSet rs) throws Exception {

ResultSetMetaData rsmd = rs.getMetaData();

int antalKolonner = rsmd.getColumnCount();

System.out.println();

System.out.println(" --------- " + titel + " ("+antalKolonner+" kolonner)");

// udskriv kolonnenavnene

for (int i=1; i<=antalKolonner; i++) skrivFormateret(rsmd.getColumnName(i));

System.out.println();

// udskriv cellerne i hver række

while (rs.next())

{

for (int i=1; i<=antalKolonner; i++) skrivFormateret(""+rs.getString(i));

System.out.println();

}

System.out.println(" -----------------------------");

}

public static void main(String[] arg) throws Exception

{

Class.forName("oracle.jdbc.driver.OracleDriver");

Connection forb = DriverManager.getConnection(

"jdbc:oracle:thin:@ora.javabog.dk:1521:student","jacob","jacob");

DatabaseMetaData dmd = forb.getMetaData();

System.out.println("DatabaseProductName = "+dmd.getDatabaseProductName());

System.out.println("DriverName = "+dmd.getDriverName());

System.out.println("MaxRowSize = "+dmd.getMaxRowSize());

ResultSet rs = dmd.getTables(null, "JANO", "%", null);

udskriv("tabeller i databasen", rs);

Statement stmt = forb.createStatement();

rs = stmt.executeQuery("select * from KUNDER");

udskriv("kunder", rs);

}

public static void skrivFormateret(String str) {

System.out.print(str);

String KOL = " | ";

if (str.length()<KOL.length()) System.out.print(KOL.substring(str.length()));

}

}

Metadata

import java.sql.*;

public class BenytMetadataOgUdskrivTabel

{

/** Udskriver et ResultSet pænt. Finder selv ud af kolonnenavnene. */

public static void udskriv(String titel, ResultSet rs) throws Exception {

ResultSetMetaData rsmd = rs.getMetaData();

int antalKolonner = rsmd.getColumnCount();

System.out.println();

System.out.println(" --------- " + titel + " ("+antalKolonner+" kolonner)");

// udskriv kolonnenavnene

for (int i=1; i<=antalKolonner; i++) skrivFormateret(rsmd.getColumnName(i));

System.out.println();

// udskriv cellerne i hver række

while (rs.next())

{

for (int i=1; i<=antalKolonner; i++) skrivFormateret(""+rs.getString(i));

System.out.println();

}

System.out.println(" -----------------------------");

}

public static void main(String[] arg) throws Exception

{

Class.forName("oracle.jdbc.driver.OracleDriver");

Connection forb = DriverManager.getConnection(

"jdbc:oracle:thin:@ora.javabog.dk:1521:student","jacob","jacob");

DatabaseMetaData dmd = forb.getMetaData();

System.out.println("DatabaseProductName = "+dmd.getDatabaseProductName());

System.out.println("DriverName = "+dmd.getDriverName());

System.out.println("MaxRowSize = "+dmd.getMaxRowSize());

ResultSet rs = dmd.getTables(null, "JANO", "%", null);

udskriv("tabeller i databasen", rs);

Statement stmt = forb.createStatement();

rs = stmt.executeQuery("select * from KUNDER");

udskriv("kunder", rs);

}

public static void skrivFormateret(String str) {

System.out.print(str);

String KOL = " | ";

if (str.length()<KOL.length()) System.out.print(KOL.substring(str.length()));

}

}

DatabaseProductName = Oracle

DriverName = Oracle JDBC driver

MaxRowSize = 2000

--------- tabeller i databasen (5 kolonner)

TABLE_CAT | TABLE_SCHEM | TABLE_NAME | TABLE_TYPE | TABLE_REMARKS |

null | JANO | KUNDER | TABLE | null |

null | JANO | PERSONER | TABLE | null |

-----------------------------

--------- kunder (2 kolonner)

NAVN | KREDIT |

Jacob | -1799 |

Brian | 0 |

Hans | 500 |

-----------------------------

Opdatere og navigere i ResultSet

De fleste ResultSet har metoder til at bevæge sig aktivt rundt i svaret og endda opdatere databasen gennem svaret.

Det gøres med f.eks.:

Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,

ResultSet.CONCUR_UPDATABLE);

ResultSet rs = stmt.executeQuery("select NAVN, KREDIT from KUNDER");

Derefter kan man navigere rundt i ResultSet-objektet med f.eks.:

rs.absolute(3); // går til 3. række i svaret (regnet fra 1 af)

rs.previous(); // går en række tilbage (modsatte af next())

rs.first(); // går til starten af svaret (svarende til rs.absolute(1))

rs.relative(3); // går 3 rækker frem, dvs. til 4. række

int r = rs.getRow();// giver hvilken række vi nu er i (her returneres 4)

Man kan ændre i data med f.eks.:

rs.updateString("NAVN", "Jakob"); // ændrer kundens navn til Jakob

rs.updateRow(); // opdaterer rækken i databasen

rs.moveToInsertRow(); // flyt til speciel indsættelses-række

rs.updateString("NAVN", "Søren"); // sæt navn

rs.updateDouble("KREDIT", 1000); // sæt kredit

rs.insertRow(); // indsæt rækken i databasen

rs.moveToCurrentRow(); // gå væk fra speciel indsættelsesrække

Derudover findes cancelRowUpdates(), der annullerer opdateringer i en række, deleteRow(), der sletter den aktuelle række fra både svaret og databasen, refreshRow(), der opfrisker ResultSet-objektet med de nyeste data.

JDBC RowSet

RowSet = et sæt rækker hentet fra databasen

=ResultSet+oprindelse+ændringer

RowSet-objekter giver mulighed ny arbejdsform

Man behøver kun at spørge på data (f.eks. med SELECT) hvorefter man får et RowSet-objekt.

Når man skal opdatere nogle rækker, slette eller oprette nye, opererer man blot det eksisterende RowSet-objekt

Slut med at rode med INSERT-, DELETE- eller UPDATE-sætninger i SQL.

Flere undertyper af RowSet i JDK 1.5

JdbcRowSet =ResultSet+oprindelse+ændringer

CachedRowSet =rækkerne er gemt i hukommelsen

kan altså eksistere afbrudt fra databasen!

Undertyper: FilteredRowSet og JoinRowSet

WebRowSet =CachedRowSet repræsenteret som XML

JdbcRowSet

CachedRowSet

WebRowSet

Login og brugeroprettelse

Eksempel på javabønne

Bemærk: Serveren kan klare brugervalidering for dig

Login og brugeroprettelse

Bruger mail.jar og activation.jar og MySQL-driver

Når klasserne ikke kan findes

programmer startet fra kommandolinien: Sæt ind i CLASSPATH-variablen

i et udviklingsværktøj (f.eks. for at kunne oversætte nogle klasser/JSP-sider der bruger klasserne): Inkludér de rigtige biblioteker (med de JAR-filer, der indeholder klasserne, opret evt. et nyt bibliotek) i dit projekt

Hvis klasserne skal være kendt i ALLE Java-programmer (der kører på en bestemt JDK): Kopier JAR-filerne over i jdk-et, under jre/lib/ext/-mappen

Hvis klasserne skal være kendt i ALLE web-applikationer (der kører på en bestemt Tomcat webserver): Kopier JAR-filerne over i Tomcats common/lib/-mappe

Hvis klasserne skal være kendt i en web-applikation, sådan at denne web-applikation også kunne flyttes over på en anden server: Kopier JAR-filerne over i webapplikationens WEB-INF/lib/-mappe (opret evt mappen)

Åben Dokumentlicens

Dette foredragsmateriale er under Åben Dokumentlicens (ÅDL)

Du har derfor lov til frit at kopiere dette værk

Bruger du dele af værket i et nyt værk, skal de dele, der stammer fra dette værk, igen frigives under ÅDL

Den fulde licens kan ses på
http://www.sslug.dk/linuxbog/licens.html

Web- og serverprogrammering

Forelæsningsnoter til lærebogen http://javabog.dk/JSP/

Værket er omfattet af Åben dokumentlicens (ÅDL).
Licensens ordlyd kan findes herunder eller på http://www.sslug.dk/linuxbog/licens.html
Åben dokumentlicens (ÅDL) version 1.0 (25. januar 2002)
1. Kopiering og distribution af værket i uændret form
Du må frit kopiere dette værk uændret og distribuere det på ethvert medium, forudsat at du sammen med hver kopi bibeholder denne licens og en henvisning til værkets kilde.
Du kan vælge at kræve penge for kopiering og distribution af indholdet, for undervisning i indholdet, for brugerstøtte og garantier i forbindelse med indholdet. Hvis du videregiver værket til andre, har du pligt til at se til, at du selv eller andre giver modtageren gratis adgang i minimum 3 år til en elektronisk udgave af indholdet - i et åbent redigérbart format - for eksempel via internettet, og at der i hvert eksemplar tydeligt angives, hvordan man kan få den elektroniske udgave.
2. Ændring af indholdet
Du må gerne ændre i dette værk eller dele af det (og dermed lave et nyt værk baseret på dette værk) og distribuere det som nævnt ovenfor, forudsat at du opfylder alle følgende krav:
* a) Du skal sørge for at det nye værk indeholder en tydelig anmærkning om at du ændrede det, hvad du ændrede og datoen for ændringerne.
* b) Det skal være omfattet af samme rettigheder og betingelser ("licens"), som det oprindelige værk.
Alternativt kan det nye værk bære en anden licens eller almindelig ophavsretlig beskyttelse, forudsat at samtlige dele, der oprindeligt stammer fra dette værk, tydeligt er markeret (f.eks i sidefoden på hver side) som værende under denne licens, og at licensen følges for disse dele af værket, herunder at der gives gratis elektronisk adgang som nævnt under afsnittet om kopiering og distribution.
3. Pligter
Enhver anvendelse, kopiering eller distribuering betragtes som en accept af denne licens og dens betingelser. Ved overtrædelse af licensbetingelserne, vil almindelig ophavsretlig beskyttelse være gældende for hele værket og vil dermed gøre person eller personer erstatningspligtige for enhver uautoriseret anvendelse.
4. Garanti
Indholdet leveres "som det er", uden nogen form for garanti for købs-, brugs- eller nytteværdi, medmindre der er givet en særskilt skriftlig garanti herom.

2004-08-30T12:23:21