104
Java - Napredni kurs -

Java - · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Embed Size (px)

Citation preview

Page 1: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Java - Napredni kurs -

Page 2: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Sadržaj kursa:

Apleti - AWT i Swing korisnički interfejs Višenitno programiranje u javi Rad sa fajl sistemom Kreiranje JavaBeans-a Tehnike mrežnog programiranja (programiranje koristeći java.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomoću java.sql paketa, korišćenje JDBC, tehnike integrisane Database podrške u Web aplikacijama) Servleti

2

Page 3: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Višenitno programiranje

Prvi računari mogli su obavljati zadatke samo jedan po jedan. Svi su se programi izvršavali sekvencijalno, jedan po jedan i svaki je zauzimao sve resurse računara. Takav način rada naziva se batch obrada. To je efikasan način za postizanje maksimalne iskorišćenosti skupih računara jer se gotovo sve CPU vreme troši na stvarnu obradu. Međutim, batch obrada je nepovoljna ako programi koji traju nekoliko sekundi moraju čekati na završetak programa od nekoliko dana.

Time sharing operacijski sastavi su izmišljeni kako bi se omogućilo da više ljudi istovremeno koristi jedan računar. Operacijski sastav ovdje upravlja raspodelom vremena između različitih programa koji se istovremeno izvršavaju.

Jednom kad su računari omogućavali različitim korisnicima istovremeno izvršavanje programa, preostao je još samo mali korak do toga da isti korisnik izvršava istovremeno više programa (multitasking). Svaki aktivni program (proces) imao je svoj sopstveni memorijski prostor, svoj skup promenljivih, svoj stack i heap i tako dalje. Jedan proces je mogao pokrenuti drugi proces, ali nakon toga svaki od njih se ponašao manje ili više nezavisno. Mehanizmi kao što je poziv udaljenih procedura (remote procedure call, RPC) razvijeni su kako bi omogućili procesima međusobnu interakciju, ali takva interakcija je bila skupa i komplikovana.

Međutim, nisu samo korisnici ti koji imaju potrebu da obavljaju više poslova istovremeno. Mnogi programi su po svojoj prirodi takođe takvi. Web browser na primer, može da ispisuje datoteku u pozadini dok istovremeno skida stranicu u jednom prozoru i formatira je kako sadržaj pristiže. Sposobnost individualnog programa da radi više od jedne stvari istovremeno najefikasnije se implementira kroz koncept niti, tj. threadova (multithreading). Višenitni program ima 2 ili više delova koji mogu istovremeno da se izvršavaju. Svaki deo ovakvog programa naziva se nit (thread), a svaka nit definiše poseban tok izvršavanja.

Danas svi operativni sistemi podržavaju višeprogramski rad. Međutim, postoje dve vrste višeprogramskog rada: rad sa više procesa i rad sa više programskih niti. Treba razumeti razliku između ova 2 načina rada. Proces je u suštini program koji se izvršava, pa prema tome, rad sa više procesa omogućava da na računaru istovremeno rade 2 ili više programa. Na primer, rad sa više procesa omogućava da na računaru istovremeno koristimo program za obradu teksta i Javin prevodilac. U radu sa više procesa, program je najmanja jedinica za izvršavanje kojom operativni sistem može da upravlja.

U okruženju koje može da radi sa više programskih niti, programska nit je najmanja jedinica za izvršavanje. To upravo znači da jedan program istovremeno može da obavlja više poslova. Dakle, rad sa više niti omogućuje detaljniju kontrolu izvršavanje nego rad sa više procesa.

Rad sa više niti racionalnije koristi resurse nego rad sa više procesa. Niti dele isti adresni proctor i sarađuju unutar istog programskog procesa. Komunikacija izmedju niti je u programerskom smislu jeftina, kao i prelazak sa jedne niti na drugu, što nije slučaj sa procesima. Rad sa više programskih niti omogućava pisanje vrlo efikasnih

3

Page 4: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

programa koji potpuno iskorišćavaju processor pošto se njegov prazan hod može svesti na minimum. Ova činjenica je posebno važna u interaktivnom, mrežnom okruženju u kome radi Java.

Javin model programske niti

Thread (u prevodu: nit) možemo definisati kao tok izvođenja operacija koji se događa nezavisno od procesa ili događaja u okolini. Nit je poput klasičnog programa koji započinje u tački A i završava se u tački B. Ona nema u sebi petlju koja očekuje događaje već se izvršava ne gledajući šta se događa oko nje. Bez niti bi ceo program povremeno morao da stoji zbog nekog procesa koji intenzivno koristi procesor ili zbog neke beskonačne petlje, stavljene u njega (namerno ili greškom). Koncept niti omogućava da zahtevni procesi ne ometaju ostale procese u njihovom izvršavanju.

Niti postoje u više stanja. Nit može da bude u stanju izvršavanja. Ona može da bude spremna za izvršavanje čim joj se dodeli procesorsko vreme. Nit koja se izvršava može da bude suspendovana, čime se njena aktivnos privremeno prekida. Suspendovana nit može da bude nastavljena, pri čemu svoju aktivnost nastavlja od tačke gde je zaustavljena. Nit može da bude blokirana, kada čeka da pristupi resursu. U bilo kom trenutku, nit može da se završi, što trenutno prekida njeno izvršavanje. Jednom završena nit ne može da nastavi rad.

Prioritet niti

Svakoj programskoj niti dodeljuje se određeni prioritet čime se definiše kako će se sa njom postupati u odnosu na druge niti. Prioritet se označava celim brojevima, koji određuju relativni redosled njihovog izvršavanja. Prioritet se koristi u odlučivanju kada će se kontrola prebaciti sa jedne na drugu nit ako se te dve niti istovremeno izvršavaju. Ovo se zove smena okruženja ili prebacivanje konteksta (engl. context switch). Pravila koja određuju kada će doći do prebacivanja iz jednog okruženja u drugi su sledeća:

1. Nit može dobrovoljno da preda kontrolu. Nit predaje kontrolu, privremeno se zaustavlja ili se blokira isključivo zbog čekanja na neku ulazno-izlaznu operaciju. U takvom slučaju ispituju se sve druge niti i procesor se dodeljuje niti najvišeg prioriteta koja je spremna za izvršavanje.

2. Kontrolu može da preuzme nit višeg prioriteta. U ovom slučaju, nit nižeg prioriteta ne predaje dobrovoljno kontrolu, već nit višeg prioriteta bukvalno otima procesor bez obzira na to šta on u tom trenutku radi. Jednostavno, čim nit višeg prioriteta bude spremna za rad, ona to i čini. Ovakav način rada zovemo predupredni višeprogramski rad (engl. preemptive multitasking).

Komplikovanija situacija nastaje kada se za procesorsko vreme bore 2 niti istog prioriteta.

4

Page 5: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Sinhronizacija

Višenitni rad u programe uvodi asinhrono ponašanje, pa mora postojati način da se niti sinhronizuju kada je to potrebno. Npr. u situacijama kada 2 ili više niti dele islu složenu strukturu podataka, moramo obezbediti da se niti ne sukobljavaju. Drugim rečima, moramo da sprečimo da jedna nit upisuje ili menja podatke baš u trenutku kada ih druga iščitava. Za ovu svrhu Java obezbeđuje monitore. Monitor je jedan kontrolni mehanizam. Možemo ga zamisliti kao kutiju u koju staje samo jedna programska nit. Kada u monitor uđe jedna programska nit, sve druge moraju da čekaju dok ona ne izađe. Na taj način monitor sprečava da više niti u isto vreme radi sa jednim deljenim resursom.

U Javi svaki objekat unapred sadrži sopstveni monitor u koji se automatski ulazi čim se pozove neka od sinhronizovanih metoda objekta. Kada se nit nađe unutar sinhronizovane metode, nijedna druga nit ne može da pozove bilo koju sinhronizovanu metodu istog objekta.

Osim sinhronizacije, potrebno je definisati i kako će niti međusobno da komuniciraju. Java obezbeđuje malozahtevan način za komuniciranje niti, preko pozivanja unapred definisanih metoda koje imaju svi objekti. Sistem slanja poruka omogućava da nit uđe u sinhronizovanu metodu nekog objekta i da tamo čeka dok je neka druga metoda ne opomene da iz nje izađe.

Klasa Thread i interfejs Runnable

Osnovna klasa za rad sa više niti u Javi je klasa Thread, a osnovni interfejs je Runnable. Neke od najčešće korišćenih metoda klase Thread su:

getName – vraća ime niti

getPriority – vraća prioritet niti

isAlive – utvrđuje da li se nit još izvršava

join – čeka da se nit završi

run – ulazna tačka u nit

sleep – privremeno zaustavlja izvršavanje niti

start – započinje izvršavanje niti pozivanjem njene metode run

Glavna programska nit

Kada se pokrene Java program, jedna nit odmah počinje da se izvršava. Ona se obično zove glavna programska nit (main thread) zato što se izvršava na početku programa. Ona je važna iz 2 razloga:

1. Ona će pokrenuti sve druge podređene niti.

5

Page 6: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

2. Njome često mora da se završava program, pošto ona izvodi razna čišćenja radnog okruženja.

Iako se glavna nit automatski stvara prilikom pokretanje programa, njome možemo i da upravljamo preko objekta tipa Thread tako što pročitamo njenu referencu pozivajući javnu i statičnu metodu currentThread() klase Thread. Ova metoda vraća referencu na nit u kojoj je pozvana.

Primer: Upravljanje glavnom programskom niti

public class GlavnaNit { public static void main(String args[]) { Thread t = Thread.currentThread(); System.out.println("Tekuca nit: " + t); //menjanje imena niti t.setName("Moja nit"); System.out.println("Posle promene imena: " + t); try { for(int n = 5; n > 0; n--) { System.out.println(n); Thread.sleep(1000); } } catch(InterruptedException e) { System.out.println("Glavna nit je prekinuta."); } } }

Kada t upotrebimo kao argument metode println prikazuje se ime niti, njen prioritet i ime njene grupe. Podrazumevano ime glavne niti je main, podrazumevani prioritet 5, a ime grupe kojoj nit pripada takođe main. Metoda sleep suspenduje izvršavanje niti tokom perioda zadatog u milisekundama.

Pravljenje niti

Niti najčešće pravimo tako što obrazujemo instancu objekta tipa Thread. To možemo uraditi na 2 načina:

1. Realizovanjem metode Runnable

2. Proširivanjem klase Thread

6

Page 7: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Realizovanje interfejsa Runnable

Da bi klasa realizovala interfejs Runnable, potrebno je samo da poseduje metodu run() koja se deklariše na sledeći način:

public void run()

Unutar metode run() definiše se kod koji predstavlja novu nit. Metoda run() može da poziva druge metode, da koristi druge klase i da deklariše promenljive kao i glavna nit. Jedina razlika je u tome što metoda run() u programu uspostavlja ulaznu tačku za drugu, uporednu tačku izvršavanja. Ta nit se završava kada se završi metoda run().

Nakon što napravimo klasu koja realizuje interfejs Runnable, pomoću te klase pravimo instancu objekta tipe Thread. Klasa Thread ima nekoliko konstruktora, npr:

Thread(Runnable objekatNit, String imeNiti)

objekatNit je upravo instanca klase koja realizuje interfejs Runnable.

Kada napravimo novu nit, ona neće početi da se izvršava dok ne pozovemo njenu metodu start(), deklarisanu unutar klase Thread. Zapravo, metodom start() se upućuje poziv metodi run(). Metoda start ima sledeću deklaraciju:

void start()

Primer:

class NovaNit implements Runnable { Thread t; public NovaNit() { //Pravljenje nove, druge niti t = new Thread(this, "Demonstraciona nit"); System.out.println("Nit potomak: " + t); t.start(); } //ulazna tacka za drugu nit public void run() { try { for(int i = 5; i > 0; i--) { System.out.println("Nit potomak: " + i); Thread.sleep(500); } }

7

Page 8: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

catch(InterruptedException e) { System.out.println("Nit potomak prekinuta"); } System.out.println("Izlazak iz niti potomka."); } } public class PrimerNiti { public static void main(String args[]) { new NovaNit(); //pravljenje nove niti try { for(int i = 5; i > 0; i--) { System.out.println("Glavna nit: " + i); Thread.sleep(1000); } } catch(InterruptedException e) { System.out.println("Glavna nit prekinuta"); } System.out.println("Izlazak iz glavne niti."); } }

Komentar: Unutar konstruktora Novanit() pravimo objekat klase Thread:

t = new Thread(this, "Demonstraciona nit");

Prvi argument this označava da nova nit treba da pozove metodu run() tekućeg objekta. Zatim se poziva metoda start() koja započinje izvršavanje niti. to izaziva pokretanje niti for potomka. Posle pozivanja metode start(), konstruktor klase NovaNit vraća se metodi main. Kada glavna nit nastavi sa radom, ona ulazi u svoju for petlju. Obe niti nastavljaju da se uporedo izvršavaju deleći vreme procesora, sve dok se njihove petlje ne završe.

Glavna nit je često ona kojom program treba da se završi. Ukoliko se glavna nit završi pre potomka, može se desiti da se Javin izvršni sistem ukoči. Ovde je obezbeđeno da se glavna nit završi poslednja tako što se ona u svakoj iteraciji zadržava 1 sekundu, a nit potomak samo pola sekunde.

8

Page 9: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Nasleđivanje klase Thread

Drugi način pravljenja niti je proširivanjem klase Thread. Nova potklasa mora da redefiniše metodu run() koja predstavlja ulaznu tačku za novu nit.

Primer:

class NovaNit extends Thread { public NovaNit() { //Pravljenje nove, druge niti super("Demonstraciona nit"); System.out.println("Nit potomak: " + this); start(); } //ulazna tacka za drugu nit public void run() { try { for(int i = 5; i > 0; i--) { System.out.println("Nit potomak: " + i); Thread.sleep(500); } } catch(InterruptedException e) { System.out.println("Prekinuta nit potomak."); } System.out.println("Izlazak iz niti potomka."); } } public class NasledjivanjeThread { public static void main(String args[]) { new NovaNit(); //pravljenje nove niti try { for(int i = 5; i > 0; i--) { System.out.println("Glavna nit: " + i); Thread.sleep(1000); }

9

Page 10: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

} catch(InterruptedException e) { System.out.println("Prekinuta glavna nit."); } System.out.println("Izlazak iz glavne niti."); } }

Koji pristup je bolji?

Klasa Thread definiše više metoda nego interfejs Runnable koje izvedena klasa može da redefiniše. Ali od svih tih metoda samo metodu run() moramo uvek redefinisati. Naravno, nju moramo redefinisati i kada klasa realizuje interfejs Runnable. Međutim, mnogi programeri generalno smatraju da klase treba proširivati samo ako se time na neki način dopunjuju ili menjaju. Ovo bi značilo da, ukoliko nemamo nameru da redefinišemo i neke druge metode klase Thread, možda je najjednostavnije da ipak implementiramo interfejs Runnable. Izbor je, naravno, slobodan.

Korišćenje metoda isAlive() i join()

Postoje dva načina da utvrdimo da li se neka nit završila. Jedan od njih je poziv metode isAlive() koja je definisana u klasi Thread i ima sledeću deklaraciju:

final boolean isAlive()

Ova metoda vraća true ako se pozvana nit još izvršava. Ako je nit završena, vraća se false.

Kada hoćemo da sačekamo da se nit završi, koristimo metodu join() čiji je opšti oblik:

final void join() throws InterruptedException

Ova metoda čeka sve dok se pozvana nit ne završi. Postoje oblici ove metode koji nam omogućuju da zadamo maksimalno vreme čekanja.

10

Page 11: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Prioritet izvršavanja niti

Oznaka prioriteta niti se koristi pri odlučivanju kojoj niti da se dozvoli izvršavanje. Teoretski, niti višeg prioriteta bi trebalo da dobiju više procesorskog vremna, međutim, u praksi ovo zavisi i od drugih faktora. Nit višeg prioriteta može i da preotme kontrolu od niti nižeg prioriteta. Kako bi niti istog prioriteta trebalo da dobiju jednak pristup procesoru, one bi trebalo povremeno da dobrovoljno predaju kontrolu. Na taj način obezbeđuje se šansa svim nitima da se izvršavaju u okruženju koje ne podržava preotimanje kontrole. U praksi, čak i u takvim okruženjima, većina niti će dobiti šansu da se izvršava jer svaka od njih povremeno mora da se blokira, npr. zbog čekanja na ulazno-izlazne operacije. Kada se to dogodi, blokirana nit se suspenduje i ostale niti mogu da se izvršavaju.

Kada želimo da se višenitni rad odvija ne predvidiv način, tj. da nekoj niti dodelimo prioritet izvršavanje, koristimo metodu setPriority() koja je definisana u klasi Thread:

final void setPriority(int nivo)

gde nivo predstavlja prioritet niti koja je pozvala ovu metodu. Nivo mora da se nalazi između vrednosti MIN_PRIORITY (1) i MAX_PRIORITY (10). Ako niti želimo da vratimo podrazumevani prioritet, kao argument zadajemo vrednost NORM_PRIORITY (5).

Prioritet određene niti možemo da saznamo pomoću metode getPriority(), takođe iz klase Thread:

final int getPriority().

Sinhronizacija niti

Kada dve ili više niti dele neki resurs, moramo naći način da ga u jednom trenutku koristi isključivo jedna nit. Postupak kojim se ovo postiže je sinhronizacija.

Ključan pojam za sinhronizaciju je monitor (ili semafor). Monitor je objekat koji se koristi kao uzajamno isključiva brava (engl. mutex). U jednom trenutku samo jedna nit može biti u jednom monitoru. Kada nit uđe u monitor, ona ga zatvori, a ostale niti koje pokušavaju da uđu u zatvoreni monitor bivaju zadržane sve dok prva nit ne izađe iz njega. Za te niti kažemo da čekaju na monitor. Nit koja zauzima monitor može ponovo da uđe u njega po potrebi.

Izvršavanje programa možemo sinhronizovati na dva načina. Oba načina koriste ključnu reč synchronized.

Korišćenje sinhronizovanih metoda

U Javi svaki objekat ima sopstveni monitor. Da bismo ušli u monitor određenog objekta, treba da pozovemo metodu koja je modifikovana pomoću rezervirane reči synchronized. Dok nit boravi unutar sinhronizovane metode, sve druge niti koje

11

Page 12: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

pokušavaju da pozovu tu metodu (ili bilo koju drugu sinhronizovanu metodu) iste instance objekta, moraju da čekaju. Da bi napustila monitor i predala kontrolu nad njim nekoj drugoj niti, nit koja je trenutno u monitoru mora da izađe iz sinhronizovane metode.

Naredba synchronized

Sinhronizovanim metodama unutar klase efikasno se postiže sinhronizacija niti. Međutim, ovaj postupak nije uvek moguć. Npr, klasa koja nije namenjena višenitnom programiranju ne koristi sinhronizovane metode. Takođe, može se desiti da koristimo instance klase čiji izvorni kod nemamo, pa nije moguće metodama unutar nje dodati rezervisanu reč synchronized. Java, naravno, nudi rešenje: pozive upućene metodama iz ove klase postavljamo unutar sinhronizovanog bloka.

Opšti oblik naredbe synchronized izgleda ovako:

synchronized(objekat)

{

//naredbe koje treba sinhronizovati

}

gde objekat predstavlja reference na objekat koji treba da se sinhronizuje. Sinhronizovani blok obezbeđuje da se poziv metodi koja je član objekta uputi tek pošto aktuelna nit uspešno uđe u monitor objekta.

Komuniciranje između niti

Već je rečeno da rad sa više niti zamenjuje programiranje koje koristi petlju događaja, tako što poslove deli u logične celine ograničene veličine. Rad sa nitima ima i dodatnu prednost: prozivanje događaja postaje izlišno. Bez višenitnog programiranja, prozivanje događaja se obično izvršava u petlji koja stalno proverava da li je ispunjen neki uslov. Kada se utvrdi da je uslov zadovoljen, preduzima se odgovarajuća akcija. Ovakav postupak nepotrebno angažuje procesor.

Java sadrži mehanizam za komuniciranje između niti, koji koristi metode wait(), notify() i notifyAll(). Ove metode su kao finalne definisane u klasi Object, tako da su na raspolaganju svim klasama. Sve tri metode mogu se pozvati samo iz sinhronizovanog konteksta (synchronized metode ili synchronized bloka).

Pravila za njihovo korišćenje su sledeća:

1. wait() naređuje niti koja ju je pozvala da napusti monitor i da prestane da se izvršavasve dok neka druga nit ne zauzme isti monitor i ne pozove metodu notify()

2. notify() ponovo pokreće prvu nit koja je pozvala metodu wait() istog objekta

12

Page 13: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

3. notifyAll() ponovo pokreće sve niti koje su pozivale metodu wait() istog objekta. Pristup će biti odobren jednoj od niti.

Deklaracija ovih metoda izgleda ovako:

final void wait() throws InterruptedException

final void notify()

final void notifyAll()

Postoji i oblik metode wait() koji omogućava da zadamo period čekanja.

13

Page 14: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Uzajamna blokada

Posebna vrsta greške koja se javlja pri radu sa više niti je uzajamna blokada (engl. deadlock). Ona nastaje kada dve niti uzajamno zavise od para sinhronizovanih objekata. Na primer, neka jedna nit uđe u monitor objekta X, a druga u monitor objekta Y. Ako nit u monitoru objekta X pokuša da pozove bilo koju sinhronizovanu metodu uz objekat Y, biće blokirana, kao što se i očekuje. Međutim, ako nit u monitoru objekta Y pokuša da pozove bilo koju sinhronizovanu metodu uz objekat X, večno će čekati, jer da bi pristupila objektu X, prvo mora da napusti monitor objekta Y kako bi prva nit mogla da se završi.

Deadlock se teško otkriva iz 2 razloga:

1. događa se retko, jer je za to potrebno da se izvršavanje 2 niti poklopi na poseban način

2. u deadlock može da bude uključeno više niti i isto toliko sinhronizovanih objekata. Ovo znači da do blokade može da dovede niz događaja koji je mnogo složeniji od opisanog.

Suspendovanje, nastavljanje i zaustavljanje niti

Ponekad je korisno da suspendujemo izvršavanje neke niti. Na primer, za prikazivanje vremena može da bude upotrebljena posebna nit. Ukoliko korisnik ne želi časovnik, ta nit može da bude suspendovana. U ranijim verzijama Jave, za privremeno zaustavljanje i nastavak izvršavanja niti korišćene su metode suspend() i resume(), definisane u klasi Thread. One se, medjutim, danas smatraju zastarelim, jer se pokazalo da, npr. metoda suspend() može da dovede do ozbiljnog otkazivanja sistema.

14

Page 15: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

AWT komponente

Klasa Component je nadklasa svih komponenti. Ona definiše osnovna svojstva i metode koje dele sve komponente. Klasa Container daje mogućnosti objektu klase Component da sadrži ostale komponente. Klasa Window dodaje klasi Container metode specifične za prozor, kao sto su sposobnost rukovanja događajima koji nastaju iz korisničke interakcije sa prozorom. Konačno, klasa Frame je originalna klasa u java.awt koja obezbeđuje prikladan prozor, sa linijom naslova i granicom.

Klasa JFrame iz biblioteke, definisana u javax.swing, je mnogo korisnija za pravljenje prozora, jer osim linije naslova i granice obezbeđuje mnogo druge opreme. Dodaje funkcionalnost klasi Frame da bi podržala mnogo sofisticiraniju opremu za crtanje i prikaz ostalih komponenti.

Metoda setDefaultCloseOperation() određuje šta će se desiti kada zatvorite prozor pritiskom na close dugme. Konstanta koju smo upotrebili kao argument metode, EXIT_ON_CLOSE, je definisana u klasi JFrame. Postoje tri druge vrednosti definisane u interfejsu WindowConstants, koje se mogu upotrebiti:

15

Page 16: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

DISPOSE_ON_CLOSE - Okvir i sve komponente koje sadrži bivaju uništeni, ali ne okončava aplikaciju.

DO_NOTHING_ON_CLOSE - Čini da operacija zatvaranja nema efekat.

HIDE_ON_CLOSE - Samo sakriva prozor pozivom metode setVisible(false).

Metoda setVisible(true) postavlja prozor naše aplikacije preko bilo kog drugog prozora koji se trenutno vidi na ekranu. Ako želimo da ga sakrijemo negde drugde u programu, samo pozovemo sa setVisible(false). Uvek ga možemo ponovo prikazati sa setVisible(true).

Komponenta predstavlja grafički entitet koji se može prikazati na ekranu. Komponenta je bilo koji objekat klase koja je potklasa od Component.

Sve klase, izvedene iz klase Container, mogu da sadrže druge objekte bilo koje od klasa izvedenih iz Component i uopšteno se nazivaju kontejneri. Kako je Container potklasa od Component onda kontejner može sadržati druge kontejnere. Izuzetak je klasa Window i njene potklase, one ne mogu biti sadrzane u drugom kontejneru.

JFrame – Koristi se kao osnovni prozor Java aplikacije. Objekat ove klase ima liniju naslova i obezbeđeno dodavanje menija. Takođe mu se mogu dodati i druge komponente.

JDialog – Služi za definisanje prozora za dijalog, koji se koristi za različite načine unosa podataka u program.

16

Page 17: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

JApplet – Osnovna klasa za Java 2 aplet – program dizajniran da se izvršava ugrađen u web stranici.

JComponent – Potklase JComponent definišu mnoštvo standardnih komponenti kao što su meniji, dugmad, kućice za potvrđivanje, itd.

Prozorska okna

Kada želimo da dodamo GUI komponentu mi je dodajemo na prozorsko okno. To je kontejner koji predstavlja površinu prozora. Postoji nekoliko različitih tipova. Oblast ispod linije naslova JFrame prozora odgovara JRootPane objektu. To sadrži jos jedno okno, objekat layeredPane na slici, koji je tipa JLayeredPane. Ovo okno odgovara celoj površini koju u prozoru zauzima JRootPane objekat i ono upravlja linijom menija ako je prozor poseduje. Oblast u layeredPane ispod linije menija odgovara contentPane objektu, a tu obicno dodajemo GUI komponente. Postoji i dodatno okno koje nije prikazano na dijagramu, to je glassPane koji takođe odgovara JRootPane oblasti. Elementi glassPane objekta su prikazani preko svakog drugog okna, pa se koristi za komponente koje želite da budu uvek prikazane preko bilo čega drugog u prozoru.

Klasa JFrame definiše metode koje obezbeđuju referencu na bilo koje okno:

getRootPane() – Vraća okno korena tipa JRootPane.

17

Page 18: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

getLayeredPane() – Vraća okno sloja tipa JLayeredPane.

getContentPane() – Vraća okno sadržaja tipa Container. Ovu metodu ćemo najčešće koristiti jer se obično komponente ovde dodaju.

getGlassPane() – Vraća okno stakla tipa Component.

Sve klase o kojima smo govorili pripadaju javax.swing paketu. Objekat JApplet ima istu postavku okna kao JFrame.

Osnove komponenti

Kada je komponenta sadržana unutar druge komponente, spoljašnji objekat se naziva roditelj i dobijamo ga pozivanjem metode getParent(). Ukoliko roditelj ne postoji, vratiće se null.

Osnovni atributi:

Pozicija (location) fiksira objekat x i y koordinatama u odnosu na kontejner u kome se nalazi.

Ime (name) pohranjuje se String objektom.

Veličina (size) se zapisuje kao širina i veličina objekta.

Prednja boja i boja pozadine (foreground i background color) se odnose na objekat, koriste se kada se objekat prikazuje.

Font (font) koji objekat se koristi kada prikazuje tekst

Kursor (cursor) definiše izgled kursora kada se miš nađe iznad objekta.

Osposobljen (enabled) ako je komponenta osposobljena, ona je aktivna i korisnik je može pristupiti

Vidljiv (visible) ako objekat nije označen kao vidljiv, neće se prikazivati na ekranu

Validan (valid) ako objekat nije validan, raspored entiteta, koji čine objekat, nije bio određen. To je slučaj pre nego što se objekat učini vidljivim. Container objekat možemo učiniti nevalidnim promenom njgovih elemenata. Onda će biti potrebno da on bude potvrđen pre nego što se prikaže.

18

Page 19: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Pozicija se definise x i y koordinatama tipa int ili objektom tipa Point. Point ima dva javna podatka clana x i y tipa int. Potpisi metode setLocation() su:

setLocation(int x, int y) i setLocation(Point p). Za dobijanje informacije o poziciji koristimo getLocation() koji vraca objekat tipa Point.

Veličinu difinišemo metodama setSize(Dimension d) i setSize(int width, int height), gde prva vrednost predstavlja širinu a druga visinu komponente. Obe metode imaju povratnu vrednost tipa void. Za dobijanje veličine koristimo getSize() koji vraća objekat tipa Dimension.

Obe vrednosti možemo postaviti odjednom korišćenjem metoda setBounds. Takođe postoje dva potpisa oblika setBounds(int x, int y, int width, int height) i setBounds(Rectangle r). Objekat tipa Rectangle ima javne podatke članove x i y koje predstavljaju gornji levi ugao pravougaonika i članove width i height koji definišu širinu i visinu. Svi podaci su tipa int. Naravno, metod getBounds() vraća poziciju i veličinu objekta kao objekat tipa Rectangle.

Izgled osnovne komponente možemo izmeniti pozivom metode objekta. Sledeće metode utiču na izgled Component objekta:

void setBackground(Color c)

Color getBackground()

void setForeground(Color c)

Color getForeground()

void setCursor(Cursor c)

Cursor getCursor()

void setFont(Font f)

Font getFont()

19

Page 20: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

20

Vrednost boje definišemo kao kombinaciju tri osnovne boje: crvenu, zelenu i plavu. Intenzitet svake od njih se navodi kao vrednost između 0 i 255.

Color crna = new Color(0, 0, 0);

Color bela = new Color(255, 255, 255);

Color zelena = new Color(0, 255, 0);

Klasa Color definiše izvestan broj standardnih konstanti boja kao public static final promenljive. To su:

white, lightGray, gray, darkGray, black, red, orange, yellow, green, pink, magenta, cyan, blue.

Objekat klase Cursor predstavlja kursor miša. Sadrži spektar static final članova koji određuju standardne tipove kursora.

DEFAULT_CURSOR

CROSSHAIR_CURSOR

WAIT_CURSOR

TEXT_CURSOR

HAND_CURSOR

N_RESIZE_CURSOR

S_RESIZE_CURSOR

E_RESIZE_CURSOR

W_RESIZE_CURSOR

MOVE_CURSOR

NE_RESIZE_CURSOR

NW_RESIZE_CURSOR

SE_RESIZE_CURSOR

SW_RESIZE_CURSOR

Page 21: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Obratimo pažnju da oni nisu tipa Cursor i služe kao argument u konstruktoru, za razliku od Color konstanti koje su Color objekti, kursori su tipa int.

Da napravimo objekat klase Cursor, koji predstavlja tekst kursor, pišemo:

Cursor mojKursor = new Cursor(Cursor.TEXT_CURSOR);

Alternativno možemo izvaditi kursor iz predefinisanog tipa koristeći static medotu klase. Ovo je posebno zgodno ako samo želimo da prosledimo u metudu (kao što je setCursor() za Component objekat) a ne i da napravimo Cursor objekat:

setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));

Objekat klase Font sadrži tabelu koja mapira Unicode vrednost svakog karaktera u kod koji stvara vizuelnu predstavu znaka. Da bi napravili Font objekat moramo priložiti ime fonta, stil i veličinu, npr.

Font f = new Font("Serif", Font.ITALIC, 12);

Druge opcije koje se mogu koristiti za stil su PLAIN i BOLD. Ime “Serif” koje smo ovde dali je logičko ime. Ostala logička imena su Dialog, DialogInput, Monospace, SansSerif ili Symbol. Umesto logičkih imena možemo koristiti odgovarajuće ime fonta kao što su Times New Roman ili Tahoma.

Stil i veličinu Font objekta izvlačimo pomocu getStyle() i getSize() metoda gde obe vraćaju vrednost tipa int.

Pre nego što napravimo font korišćenjem određenog imena, treba da znamo da li je on dostupan na sistemu na kom se izvršava. Za to koristimo metodu getAllFonts() iz klase GraphicEnvironment definisanoj u paketu java.awt.

21

Page 22: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

GraphicsEnvironment e =

GraphicsEnvironment.getLocalGraphicsEnvironment();

String[] fontNames = e.getAvailableFontFamilyNames();

GraphicsEnvironment se ne može direktno napraviti, ali možemo dobiti referencu objekta za tekuću mašinu pozivom statičke metode getLocalGraphicsEnvironmetn(). Onda koristimo getAvailableFontNames() koja nam vraća imena svih fontova koji su raspoloživi na tekućem sistemu.

22

Page 23: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Swing komponente

Sve Swing komponente imaju JComponent kao bazu, koja i sama proširuje klasu Component. Dodaje mogućnosti kao što su priključivi izgled i utisak komponenti (look and feel) dozvoljavajući nam da menjamo programerski ili da za prikazane komponente implementiramo sopstveni izgled i utisak, podrzava tultipe (tooltips), automatsko pomeranje sadržaja listi, tabela ili u drvetu kada se komponenta vuče mišem, specijalna podrška za otklanjanje grešaka, lako se proširuju da bismo napravili sopstvenu komponentu, itd. Sve klase Swing komponenti su definisane u javax.swing paketu i imaju imena klasa koja počinju slovom J.

Dugmad

Klasa JButton definiše pravougaono dugme koje bi se koristilo za dijalog ili liniju alata. JToolbar se koristi u spoju sa klasom JButton da bi napravili liniju alata koja sadrži dugmad. Postoji i JToggleButton koje definiše dugme sa dva stanja, pritisnuto ili ne, a postoje i specijalizovane verzije JCheckBox i JRadioButton. Radio dugmad uglavnom rade u grupi tako da samo jedno od njih moze biti u stanju pritisnuto. Ovo udruživanje se uspostavlja dodavanjem u ButtonGroup objekat koji vodi računa o stanju dugmadi u grupi. U osnovi svi imaju istu AbstractButton klasu.

23

Page 24: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Meni

Klasa JMenuBar definiše liniju alata koja se obično nalazi na vrhu prozora aplikacije. JMenu objekat predstavlja najvisi član menija na liniji menija koji izbacuje listu članova kada se na nju pritisne. Članovi menija su definisani klasom JMenuItem. Klasa JPopupMenu definiše kontekst meni koji se tipično implementira kada se pojavi na tekućoj poziciji kursora kada se pritisne desno dugme miša. JCheckBoxMenuItem i JRadioMenuItem definišu isto kao i odgovarajuća obična dugmad samo prilagođena za meni. Radio dugmad i ovde možemo grupisti u ButtonGroup objektu.

Tekst komponente

Najosnovnija tekst komponenta je JLabel koja je pasivna i ne može se editovati. JTextField prikazuje jednu liniju teksta ali se može editovati. JTextArea definiše komponentu koja dozvoljava editovanje teksta od više linija. Sadrži trake za pomeranje i može prikazati višestruke vrste i kolone. Komponente JEditPane i JTextPane su drugačijeg stepena složenosti u odnosu na ostale. Prva podrzava editovanje običnog teksta, u formatima HTML i RTF, dok druga proširuje prvu i dozvoljava nam da unutar teksta ugradimo slike i ostale komponente.

24

Page 25: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Ostale Swing komponente

Klasa JPanel definiše nešto kao fizički panel koji možemo upotrebiti za grupisanje skupa komponenti. Na primer, možemo upotrebiti dva panela da bismo podrzali dve odvojene grupe JButton komponenti u oknu sadržaja prozora aplikacije.

JList implementira listu članova, dok JTable implementira tabelu članova iz koje možemo da izaberemo vrstu ili kolonu ili jedan element. Komponenta JTable automatski vodi računa o pamćenju kolona kada se kolona, korišćenjem miša, prevuče na novu poziciju.

Svakoj komponenti možemo dodati granice, a paket javax.swing.border sadrzi osam klasa koje predstavljaju različite vrste granice koje možemo koristiti.

25

Page 26: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Apleti u Swing-u

Jedna od najznačajnijih klasa swing paketa je klasa Japplet koja proširuje klasu Aplet. apleti koji koriste Swing moraju da budu potklase klase Japplet. Klasa Japplet donosi mnoge novine u odnosu na klasu Applet. Na primer, klasa Japplet ima različita okna kao što su okno za sadržaj (content pane), prozirno okno (glass pane) i osnovno okno (root pane).

Napomena: Pre J2SE 5 nismo mogli da pozovemo metodu add() apleta da bismo instanci klase Japplet dodali neku komponentu, već smo morali da pozovemo metodu add() okna za sadržaj. To znači da smo prilikom dodavanja komponente klasi Japplet morali da pišemo otprilike ovakav kod:

// vrati referencu na okno za sadržaj

Container okno_za_sadrzaj = getContentPane();

// dodaj komponentu u okno za sadržaj:

okno_za_sadrzaj.add(komponenta);

Isti postupak bio je neophodan za korišćenje metoda remove() i setLayout(). U J2SE 5 direktno iz klase Japplet možemo da zovemo metode add(), remove() i setLayout(). Međutim, ako pišemo kod koji prevodi prevodilac za neku od prethodnih verzija Jave, moramo voditi računa da primenimo stariji postupak.

Pravilno rukovanje nitima

U poslednjim verzijama Jave, Sun preporučuje da se grafički korisnički interfejs ne pravi iz niti koja poziva init(), nego iz niti koja rukuje događajima. Da bismo omogućili apletu da napravi grafički korisnički interfejs (ili da ga izmeni) iz niti koja ne rukuje događajima, moramo upotrebiti jednu od dve metode definisane klasim SwingUtilities. To su metodi: invokeLater() i invokeAndWait(), čije deklaracije izgledaju ovako:

static void invokeLater(Runnable obj)

static void invokeAndWait(Runnable obj) throws InterruptedException, InvocationTargetException

Ovde je obj objekat sa interfejsom Runnable, čiju će metodu run() pozvati nit koja rukuje događajima. Razlika između ove dve metode je u tome što se invokeLater() vraća odmah, a invokeAndWait() čeka dok se ne vrati obj.run(). U većini sličajeva koristi se invokeLater(), a invokeAndWait() kada pravimo početni korisnički grafički interfejs za aplet.

26

Page 27: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Polja za potvrdu

Za kreiranje polja za potvrdu koristi se klasa JCheckBox. Neki od njenih konstruktora su:

JCheckBox(Icon i)

JCheckBox(Icon i, boolean stanje)

JCheckBox(String s)

JCheckBox(String s, boolean stanje)

JCheckBox(String s, Icon i)

JCheckBox(String s, Icon i, boolean stanje)

Argument i predstavlja ikonicu za dugme, teks zadajemo argumentom s. Ako argument ima stanje true, polje za potvrdu je podrazumevano potvrđeno.

Metoda:

void setSelected(boolean stanje)

menja stanje polja za potvrdu.

Kada se u polje potvrde unese znak za potvrdu ili se on ukloni, generiše se događaj stavke. O tome se brine metoda itemStateChanged(). U okviru nje, metoda getItem vraća polje za potvrdu koje je generisalo događaj. Zatim se metodom getStateChange() utvrđuje da li je znak za potvrdu upisan ili obrisan. Ako je upisan, metoda vraća SELECTED, u protivnom vraća DESELECTED.

Radio-dugmad

Klasa JradioButton kapsulira radio-dugmad. Neki od njenih konstruktora su:

JRadioButton(Icon i)

JRadioButton (Icon i, boolean stanje)

JRadioButton (String s)

JRadioButton (String s, boolean stanje)

JRadioButton (String s, Icon i)

JRadioButton (String s, Icon i, boolean stanje)

27

Page 28: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Radio-dugmad mogu da budu grupisana. U jednom trenutku može da bude potvrdjemo samo jedno dugme iz grupe. Klasa ButtonGroup je namenjena pravljenju grupa dugmadi. Elementi se u grupu dodaju pomoću metode add().

Pritisci mišem na radio-dugme generišu događaje koje obrađuje metoda actionPerformed(). Metoda getActionCommand() vraća text pridružen radio-dugmetu.

Okna sa karticama

Komponenta okno sa karticama (tabbed pane) izgleda kao grupa fascikli u kartoteci. Svaka fascikla ima ime. Kada korisnik izabere fasciklu, njen sadržaj postaje vidljiv. U jednom trenutku može biti izabrana samo jedna kartica. Ova okna se obično koriste za zadavanje konfiguracionih prametara.

Klasa koja se koristi za pravljenje okna sa karticama je JtabbedPane koja proširuje klasu Jcomponent. Kartice se dodaju metodom addTab(), koja ima oblik:

void addTab(String str, Component komp)

Argument str predstavlja naslov kartice, a komp komponentu koju bu trebalo dodati na karticu. Obično se dodaje klasa Jpanel ili neka njena potklasa.

Opšta procedura za korišćenje okna sa krticama u apletu je sledeća:

1. Napraviti objekat klase JtabbedPane. 2. Pozvati metodu addTab() da bismo oknu dodali karticu. 3. Ponoviti korak 2 za svaku karticu. 4. Dodati okno sa karticama u okno za sadržaj apleta.

Okna sa klizačima

Komponenta okno sa klizačima (scroll pane) predstavlja pravougaoni prostor u kome se može videti neka komponenta. Ako je potrebno, postavljaju se horizontalna i/ili vertikalna traka za pomeranje. Okna sa klizačima kapsulira klasa JscrollPane. Neki od njenih konstruktora su:

JScrollPane(Component komp)

JScrollPane(int vtp, int htp)

JScrollPane(Component komp, int vtp, int htp)

28

Page 29: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Argument komp predstavlja komponentu koja se postavlja u okno sa klizačima, a vtp i htp su celobrojne konstante koje određuju kada se prikazuju trake za pomeranje. Te konstante definisane su interfejsom ScrollPaneConstants. Postoje sledeće konstante:

Konstanta Opis HORIZONTAL_SCROLLBAR_ALWAYS Uvek se vidi horiz. traka za pomeranje HORIZONTAL_SCROLLBAR_AS_NEEDED Horiz. traka se vidi samo kada je

potrebna HORIZONTAL_SCROLLBAR_NEVER Nema horiz. trake za pomeranje VERTICAL_SCROLLBAR_ALWAYS Uvek se vidi vertikalna traka za

pomeranje VERTICAL_SCROLLBAR_AS_NEEDED Vertikalna traka se vidi samo kada je

potrebna VERTICAL_SCROLLBAR_NEVER Nema vertikalne trake za pomeranje

Da bismo u nekom apletu koristili okno sa klizačima, potrebno je da uradimo sledeće:

1. Napraviti objekat klase JComponent. 2. Napraviti objekat klase JScrollPane. 3. Dodati okno sa klizačima u okno za sadržaj apleta.

29

Page 30: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Ulaz i izlaz, rad sa fajl sistemom

Stream

Stream je niz podataka koji ima neodređenu dužinu. Naziv stream (struja, tok) je odabran jer je ta struktura nalik struji vode koja neprekidno teče i nema definisan kraj. Još bolja analogija je red čekanja. Za vreme dok se uslužuju ljudi na početku reda, novi dolaze na njegov kraj. Red je diskretna struktura, ali to ne znači da njegovi članovi nisu međusobno povezani raznim relacijama.

U Javi se stream sastoji od niza diskretnih bajtova. Oni mogu predstavljati znakove ili neke druge vrste podataka. Mogu dolaziti brže nego što ih je moguće obraditi ili pak process može čekati dok ne dođe sledeći za obradu.

Ključ obrade streama je while petlja koja obrađuje svaki pojedini element streama dok ne učita znak za kraj streama ili dok se ne pojavi neki drugi uslov. Na Unixu je <Ctrl-D> znak za završetak streama. Windows za tu svrhu koristi <Ctrl-Z>.

Klase stream-ova

Gotove sve klase koje rade sa streamovima delovi su paketa java.io. (Postoji takođe nekoliko dodatnih u paketima sun.io i sun.net, ali te su namerno skrivene. Ima i nekoliko klasa u paketu java.util.zip.) Dve glavne klase su java.io.InputStream i java.io.OutputStream. To su apstraktne klase i one čine temelj mnogih potklasa sa specijalizovanim mogućnostima. Među njima se najčešće koriste:

• BufferedInputStream • BufferedOutputStream • ByteArrayInputStream • ByteArrayOutputStream • DataInputStream • DataOutputStream • FileInputStream • FileOutputStream • FilterInputStream • FilterOutputStream • LineNumberInputStream • ObjectInputStream • ObjectOutputStream • PipedInputStream • PipedOutputStream • PrintStream • PushbackInputStream • SequenceInputStream

30

Page 31: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

• StringBufferInputStream

Stream System.out je, recimo, OutputStream; i to posebno, PrintStream. Postoji odgovarajući System.in koji je InputStream namenjen čitanju podataka s konzole.

Podaci za streamove dolaze takođe i iz datoteka. Klase FileInputStream i FileOutputStream se koriste za čitanje podataka iz datoteka i pisanje u njih.

Mrežne konekcije obično daju streamove. Kad se povežemo na neki web ili ftp ili neki drugi servis, čitamo podatke koje on šalje tako da s njim povežemo jedan InputStream i jedan OutputStream.

Java programi i sami proizvode streamove. Na primer, ByteArrayInputStream, ByteArrayOutputStream, StringBufferInputStream, PipedInputStream, i PipedOutputStream se koriste za prenos podataka iz jednog dela Java programa u drugi.

Ponešto neočekivano, komponente kao što je TextArea ne proizvode streamove. Međutim, stringove koje oni stvaraju uvek možete koristiti da biste kreirali ByteArrayInputStream ili StringBufferInputStream.

Klasa InputStream

Klasa java.io.InputStream je apstraktna klasa koja sadrži osnovne metode za čitanje čistih bajtova podataka iz streama. Iako je to apstraktna klasa, mnoge metode u biblioteci vraćaju objekat tipa InputStream, tako da ćete često raditi direktno s nekom od metoda deklarisanih u toj klasi.

public abstract int read() throws IOException public int read(byte[] data) throws IOException public int read(byte[] data, int offset, int length) throws IOException public long skip(long n) throws IOException public int available() throws IOException public void close() throws IOException public synchronized void mark(int readlimit) public synchronized void reset() throws IOException public boolean markSupported()

Primetite da gotovo sve ove metode mogu izbaciti IOException. To važi uglavnom za sve što se odnosi na ulaz i izlaz. Jedini izuzetak od tog pravila je klasa PrintStream koja će progutati sve izuzetke.

31

Page 32: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Čitanje bajtova

Osnovna read() metoda iz klase java.io.InputStream čita pojedinačni neoznačeni byte podataka i vraća njegovu int vrednost. To je broj između 0 i 255. Kad se naiđe na kraj streama, vraća se -1, i to možete koristiti kao flag pomoću kojeg ćete ustanoviti da ste došli do kraja streama.

public abstract int read() throws IOException

Čitanje više bajtova odjednom

Dok osnovna read() metoda čita bajt po bajt, sledeće dve overloaded varijante čitaju polja bajtova.

public int read(byte[] data) throws IOException public int read(byte[] data, int offset, int length) throws IOException

Prva metoda čita onoliko bajtova koliko joj treba da napuni polje data. Druga čita onoliko bajtova iz ulaznog streama koliko joj je zadato u argumentu length i sprema ih u polje data počevši od pozicije offset.

Te metode su blokorane dok ne stignu raspoloživi podaci. Tada učitaju onoliko podataka koliko stane u polje ili koliko je navedeno u length.

Nakon toga vraćaju broj bajtova koje su učitale. Ne smete pretpostaviti da će polje biti uvek napunjeno ili da će zaista biti učitano length bajtova. Ako naiđe kraj streama, vraća se -1.

Prebrojavanje dostupnih bajtova

Metoda available() ispituju koliko bajtova sa uzlaznog streama je spremno za učitavanje bez blokiranja.

public int available() throws IOException

Preskakanje bajtova

Metoda skip() čita i odbacuje odredjeni broj bajtova.

public int skip(long n) throws IOException

Markiranje i resetovanje

Često je korisno ako možete učitati nekoliko bajtova, a zatim se vratiti nazad i učitati ih ponovo. Na primer, pri oblikovanju nekog kompajlera ne možete znati da li treba učitati znak <, <<, ili

32

Page 33: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

<<= sve dok ne učitate dva ili više bajtova. Bilo bi korisno ako biste se mogli vratiti nazad i ponovo učitati token nakon što ste okrili o kojem se radi.

Neki, ali ne svi streamovi dopuštaju vam da markirate određenu poziciju u streamu i da se onda vratite na nju. To se radi pomoću sledećih metoda:

public synchronized void mark(int readlimit) public synchronized void reset() throws IOException public boolean markSupported()

Metoda markSupported() vraća true ako taj stream podržava markiranje, a false inače.

Pod pretpostavkom da je markiranje podržano, metoda mark() stavlja oznaku na mesto gde kasnije želite da se vratite pomoću metode reset(). Istovremeno u jednom streamu može postojati samo jedna takva oznaka. Sledeće markiranje izbrisaće prethodno. Ako markiranje nije podržano, ove metode će izbaciti IOException.

Zatvaranje streamova

Kad ste završili s nekim streamom, trebalo bi da ga zatvoriti kako bi se oslobodili resursi koji su s njim povezani. Jednom kad je stream zatvoren, svaki pokušaj čitanja iz njega izbaciće IOException.

Stream (u ovom slučaju ulazni) zatvarate pomoću metode close():

public void close() throws IOException

Ako se stream ne može zatvoriti, izbaciće se IOException.

Izlazni streamovi

Klasa java.io.OutputStream šalje čiste bajtove podataka na neko odredište, npr. konzolu ili mrežni servis. Ova klasa je apstraktna, isto kao i InputStream. Međutim, mnoge metode u biblioteci klasa napravljene su tako da vraćaju objekate tipa OutputStream umesto objekate iz njenih specifičnih podklasa. Takođe, mnoge metode klase OutputStream su opšte korisne. To su:

public abstract void write(int b) throws IOException public void write(byte[] data) throws IOException public void write(byte[] data, int offset, int length) throws IOException public void flush() throws IOException public void close() throws IOException

Nekoliko različitih write() metoda šalju čiste bajtove podataka svakom procesu koji osluškuje dati stream.

33

Page 34: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Ponekad operativni sistem baferira izlazne streamove zbog boljih performansi. To znači da se bajtovi pre ispisa akumuliraju u bafer čija veličina može biti od nekoliko bajtova do nekoliko hiljada bajtova. Kad se on napuni, svi podaci se ispisuju odjednom. Metoda flush() pokrenuće, međutim, ispis bez obzira da li je bafer pun ili nije.

Primetite da to nije isto što i baferisanje koje sprovodi klasa BufferedOutputStream koje izvodi Java runtime. Ovde se radi o native baferisanju, dakle procesu na nivou operativnog sistema. Međutim, poziv metode flush() trebalo bi da isprazni oba bafera.

Metoda close() zatvara stream i otpušta resurse koji su s njim povezani. Jednom kad je stream zatvoren, pokušaj pisanja u njega izbaciće IOException.

Čitanje iz datoteke

Klasa java.io.FileInputStream predstavlja InputStream koji čita bajtove iz datoteke. Ima sledeće public konstruktore i metode:

public FileInputStream(String name) throws FileNotFoundException public FileInputStream(File file) throws FileNotFoundException public FileInputStream(FileDescriptor fdObj) public native int read() throws IOException public int read(byte[] data) throws IOException public int read(byte[] data, int offset, int length) throws IOException public native long skip(long n) throws IOException public native int available() throws IOException public native void close() throws IOException public final FileDescriptor getFD() throws IOException

S izuzetkom konstruktora i metode getFD(), ove metode samo prekrivaju istoimene metode klase java.io.InputStream. Jedina je razlika što čitaju podatke iz datoteke.

Novi objekat tipa FileInputStream konstruišete tako što konstruktoru prosledite ime datoteke, na primer:

FileInputStream fis = new FileInputStream("ulaz.txt");

Ako datoteka ne postoji, izbaciće se izuzetak FileNotFoundException, potklasa od IOException. Uopšteno, Java će tražiti datoteke u aktivnom direktorijumu, ali one se ne moraju neophodno nalaziti u direktorijumu u kojem se nalazi .class datoteka.

Pisanje u datoteku

Klasa java.io.FileOutputStream predstavlja OutputStream koji upisuje bajtove u datoteku. Ima sledeće public konstruktore i metode:

34

Page 35: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

public FileOutputStream(String name) throws IOException public FileOutputStream(String name, boolean append) throws IOException public FileOutputStream(File file) throws IOException public FileOutputStream(FileDescriptor fdObj) public native void write(int b) throws IOException public void write(byte[] data) throws IOException public void write(byte[] data, int offset, int length) throws IOException public native void close() throws IOException public final FileDescriptor getFD() throws IOException

S izuzetkom konstruktora te metode getFD(),ove metode samo prekrivaju istoimene metode klase java.io.OutputStream. Jedina razlika je što pišu podatke u datoteku.

Novi objekat tipa FileOutputStream konstruišete tako da konstruktoru prosledite ime datoteke, na primer:

FileOutputStream fos = new FileOutputStream("izlaz.txt");

Ako datoteka postoji u aktivnom direktorijumu, biće prebrisana i u nju upisani novi podaci. Ako ne postoji, kreiraće se.

Dodavanje na kraj datoteke

Ako želite da se novi sadržaj doda na kraj datoteke umesto da prebriše prethodni sadržaj, prosledićete vrednost true kao drugi argument konstruktoru FileOutputStream(). Na primer:

FileOutputStream fos = new FileOutputStream("izlaz.txt", true);

Filtriranje streamova

Klase java.io.FilterInputStream i java.io.FilterOutputStream su konkretne potklase od InputStream i OutputStream koje na neki način modifikuju podatke osnovnih streamova. Retko ćete ih koristiti direktno, ali njihove potklase su veoma važne, posebno DataInputStream i DataOutputStream.

Filter-stream povezujete s osnovnim tako da osnovni prosledite konstruktoru filter-streama. Na primer, da biste kreirali novi objekat tipa DataOutputStream iz objekata FileOutputStream mogli biste postupiti ovako:

FileOutputStream fos = new FileOutputStream("ln.txt"); DataOutputStream dos = new DataOutputStream(fos);

To se može kombinovati i u jednoj liniji:

35

Page 36: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

DataOutputStream dos = new DataOutputStream(new FileOutputStream("ln.txt"));

Filtrirani streamovi

BufferedInputStream i BufferedOutputStream

Ove klase buferišu čitanje i pisanje tako da podatke najpre učitavaju u bafer (buffer, interrno polje bajtova). Tako neka aplikacija može čitati bajtove iz streama bez pozivanja native metoda koje iza toga stoje. Podaci se učitavaju iz bafera ili u njega upisuju u blokovima, a naknadni pristupi usmeravaju se direktno prema baferu.

DataInputStream i DataOutputStream

Ove klase čitaju i pišu podatke koji pripadaju primitivnim Java tipovima, kao i podatke tipa String na način koji ne zavisi od mašine (Big-endian za integer, IEEE-754 za float i double, UTF-8 za Unicode)

PrintStream

Ovu ste klasu već susretali preko njenih implementacija System.out i System.err. Omogućuje vrlo jednostavno ispisivanje primitivnih vrednosti, objekata i string literala. Klasa hvata sve izuzetke tipa IOException i namenjena je pre svega za debagovanje.

PushbackInputStream

Ova klasa osigurava pushback bafer pomoću kojeg je moguće "poništiti" čitanje bajtova sa streama. Kod sledećeg čitanja sa streama biće učitani ti “poništeni” bajtovi.

GZIPInputStream i GZIPOutputStream

Ovo su klase iz paketa java.util.zip i obavljaju kompresiju i dekompresiju podataka.

DigestInputStream i DigestOutputStream

Ovo su klase iz paketa java.security i izračunavaju tzv. MessageDigest za streamove koristeći neku jaku hash funkciju, npr SHA.

CipherInputStream i CipherOutputStream

Klase su iz paketa javax.crypto koji je deo Java Cryptography Extension (JCE), standardnog proširenja Jave, a uključen je u JavaTM 2 Platform Std. Ed. v1.4.0. i

36

Page 37: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

izračunavaju enkripcije i dekripcije streamova koristeći razne algoritme kao DES, RSA, Blowfish i druge.

ObjectInputStream i ObjectOutputStream

Potklase od DataInputStream i DataOutputStream koje mogu serijalizovati i deserijalizovati Java objekte u čiste bajtove (i obrnuto). Koristi se kod udaljenog pozivanja metoda (RMI) i za JavaBeans.

Možete kreirati i svoje sopstvene potklase od java.io.FilterInputStream i java.io.FilterOutputStream koje će izvoditi filtriranja prema vašim potrebama.

Bufferisani streamovi

Klase java.io.BufferedInputStream i java.io.BufferedOutputStream omogućuju čitanje i pisanje na način da se podaci prvo spremaju u bafer (buffer) koji je zapravo interno polje bajtova. Program tada čita bajtove iz streama bez prethodnog pozivanja native metode dok god ima podataka u baferu. Podaci se čitaju iz bafera ili pišu u njega u blokovima, a nakon toga su dostupni direktno iz bafera.

Sa stanovišta programera, jedina razlika između običnog i baferisanog streama je u konstruktorima:

public BufferedInputStream(InputStream in) public BufferedInputStream(InputStream in, int size) public BufferedOutputStream(OutputStream out) public BufferedOutputStream(OutputStream out, int size)

Argument size je broj bajtova u baferu. Ako nije naveden, podrazumeva se 512.

Optimalna veličina bafera zavisi od platforme i povezana je sa veličinom bloka na disku, barem za datotečne streamove. Manje od 512 će verovatno biti premalo, a više od 4096 previše. Idealno bi bilo da veličina bafera bude celobrojni umnožak veličine bloka diska. Za nepouzdane mrežne konekcije bolje je odabrati manju veličinu bafera. Na primer,

URL u = new URL("http://java.developer.com"); BufferedInputStream bis = new BufferedInputStream(u.openStream(), 256);

Klase podataka streamova

Klase java.io.DataInputStream i java.io.DataOutputStream čitaju i pišu primitivne Java tipove podataka i stringove na način koji ne zavisi od mašine. DataInputStream ćete koristiti za čitanje

37

Page 38: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

podataka koji su napisani pomoću DataOutputStream. Taj format koristi standard IEEE 754 za floating point, big-endian za integer, i modifikovani UTF-8 za Unicode.

DataOutputStream deklariše sledeće konstruktore i metode:

public DataOutputStream(OutputStream out) public synchronized void write(int b) throws IOException public synchronized void write(byte[] data, int offset, int length) throws IOException public final void writeBoolean(boolean b) throws IOException public final void writeByte(int b) throws IOException public final void writeShort(int s) throws IOException public final void writeChar(int c) throws IOException public final void writeInt(int i) throws IOException public final void writeFloat(float f) throws IOException public final void writeDouble(double d) throws IOException public final void writeBytes(String s) throws IOException public final void writeChars(String s) throws IOException public final void writeUTF(String s) throws IOException public final int size() public void flush() throws IOException

Metoda size() vraća broj bajtova koji su ispisani na izlazni stream.

Klasa File

Klasa java.io.File predstavlja eksterno ime datoteke na računaru. Njome se pokušavaju apstrahovati delovi imena koji su zavisni od računara, na primer put, separator i slično.

Dva su načina referenciranja datoteka, relativni i apsolutni. Apsolutno imenovanje daje potpuni put do datoteke, počevši od imena diska pa dalje. Detalji zavise od operativnog sistema. Na primer:

Unix: "/math/vedris/file1" DOS: "C:\math\vedrisfile1" MacOS: "Macintosh HD:math:vedris:file1"

Sva ova tri stringa referenciraju datoteku file1 na glavnom disku u direktorijumu /math/vedris/. Razlikuju se na primer po separatoru. Unix koristi /, Dos i Windows \, MacOS :. Drugi sistemi mogu koristiti nešto sasvim drugo.

Takođe, nema garancije da se glavni disk na Macu zove baš “Macintosh HD” ili da uopšte postoji disk s tim imenom. Na Unixu “/” i “/math” mogu biti na različitim diskovima, pa čak i na različitim mašinama. Zbog takvih razloga apsolutna imena treba uglavnom izbegavati.

38

Page 39: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Relativno imenovanje koje treba koristiti kad god je moguće, ne daje potpuni put do datoteke. Umesto toga daje put koji je relativan prema nekoj poznatoj datoteci. Relativni put može pokazivati datoteku u istom direktorijumu u kojem se nalazi poznata datoteka jednostavno navođenjem njenog imena. Ili može pokazivati na datoteku u poddirektorijumu poznatog direktorijuma.

Opšte se jedan direktorijum uzima za “radni” i metode koje traže datoteke činiće to u odnosu na taj direktorijum. Uobičajeno je da to bude direktorijum iz kojeg započinjete da izvršavate aplikaciju.

Objekat tipa java.io.File može biti ime direktorijuma isto kao i ime datoteke.

Konstruktori klase File

Postoje tri konstruktora klase File. Svaki uzima neku varijaciju imena datoteke kao argument. Najjednostavniji je

public File(String path)

Ovde je path String koji sadrži potpuni ili relativni put do datoteke, napisan na isti način kao za operativni sistem računara. Na primer:

File f1 = new File("ulaz.txt"); File f2 = new File("/etc/passwd");

Ako želite, možete put do datoteke odvojiti od njenog imena koristeći sledeći konstruktor:

public File(String path, String name)

Ovde je name ime datoteke, a path ime direktorijuma u kome se ona nalazi. Na primer:

File f2 = new File("/etc", "passwd");

Na kraju, imamo i konstruktor

public File(File dir, String name)

koji se ponaša kao i prethodni, ali je dir ovde objekat tipa File, a ne String.

Neke metode u drugim klasama takođe vraćaju objekat tipa File, na primer metode iz klase java.awt.FileDialog. Takvi objekti će poštovati sve konvencije operativnog sistema na kojem se aplikacija izvršava.

39

Page 40: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Metode klase File

Kad jednom imate objekat tipa File, postoji mnogo stvari koje o njemu možete pitati i koje s njim možete učiniti.

public String getName()

Elementarno pitanje o datoteci je ono o njenom imenu. Ime ćete saznati pomoću metode getName() koja ne uzima nikakve argumente, a vraća String koji sadrži eksterno ime datoteke (bez putanje). Na primer, dobićete "file1" umesto "/math/vedris/file1".

public String getPath()

Metoda getPath() vraća String koji sadrži putanju do datoteke. Ta putanje će biti relativna ili apsolutna, u zavisnosti od načina na koji je dati objekat bio kreiran.

public String getAbsolutePath()

Metoda getAbsolutePath() vraća punu, apsolutni putanju do datoteke.

public String getCanonicalPath() throws IOException

Metoda getCanonicalPath() vraća kanonsku formu putanje do datoteke. Ta forma je zavisna od operativnog sistema i mašine.

public String getParent()

Metoda getParent() vraća String koji sadrži ime jedinstvenog nadređenog direktorija u odnosu na onaj u kojem se datoteka nalazi, ili null ako je već dosegnut vrh hijerarhije.

public boolean exists() throws SecurityException

Metoda exists() označava da li određena datoteka postoji na mestu gde je očekujete.

public boolean canWrite() throws SecurityException

Metoda canWrite() daje odgovor da li imate pravo pisanja u datoteku. To nije loše proveriti prije nego što stvarno pokušate nešto da upišete.

public boolean canRead() throws SecurityException

Metoda canRead() daje odgovor da li imate pravo čitanja iz datoteke

public boolean isFile() throws SecurityException

40

Page 41: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Metoda isFile() odgovara na pitanje da li se radi o datoteci (za razliku od direktorijuma).

public boolean isDirectory() throws SecurityException

Metoda isDirectory() vraća true ako se radi o (postojećem) direktorijumu.

public boolean isAbsolute()

Metoda isAbsolute() vraća true ako je dato ime apslolutna putanja, a false ako nije.

public long lastModified() throws SecurityException

Metoda lastModified() vraća vreme zadnje promjene. Kako je konverzija u pravi datum dugačka, a procedura zavisi od platforme, treba je koristiti uglavnom za upoređivanje vremena zadnje promene dve različite datoteke.

public long length() throws SecurityException

Metoda length() daje veličinu datoteke u bajtovima.

public boolean mkdir()

Metoda mkdir() pokušava da kreira direktorijum sa zadatim imenom. Ako uspe, vratiće true, inače false.

public boolean mkdirs() throws SecurityException

Metoda mkdirs() za dato ime kreira ne samo jedan, nego sve potrebne nadređene direktorijume koji čine putanju do datoteke. Ako sva kreiranja uspeju, vratiće se true, inače false (čak ako su neka kreiranja i uspela).

public boolean renameTo(File destination) throws SecurityException

Metoda renameTo() pokušava da preimenuje datoteku. Na primer, f1.renameTo(f2) pokušava da preimenuje f1 u f2. To može značiti i premeštanje u drugi direktorijum ako imena tako naznačavaju. Ako f2 već postoji, biće prebrisana sa f1 (pod uslovom da imate odgovarajuće dozvole). Ako preimenovanje uspe, vraća se true, inače false.

public String[] list() throws SecurityException

Metoda list() vraća polje stringova koji sadrže imena datoteka u navedenom direktorijumu. Korisna je za procesiranje svih datoteka unutar direktorijuma odjednom.

public String[] list(FilenameFilter filter) throws SecurityException

41

Page 42: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Ova varijanta metode list() čini isto što i prethodna, ali možete koristiti objekat klase koja implementira FilenameFilter (pogledajte poglavlje o tome) za filtriranje imena datoteka.

public boolean delete() throws SecurityException

Metoda delete() pokušava da izbriše datoteku na koju se odnosi. Vraća true ako je datoteka postojala i sad je izbrisana, inače false.

Klasa File sadrži i uobičajene metode equals(), hashCode() i toString() koje se ponašaju tačno onako kao što biste očekivali. Ne sadrži posebnu metodu clone().

Klase Reader i Writer

Klase java.io.Reader i java.io.Writer su apstraktne natklase klasama koje obavljaju čitanje i pisanje podataka zasnovanih na znakovima (characters). Značajne su za konvertovanje znakova između različitih znakovnih sistema (character sets).

Ulazni i izlazni streamovi su opšte zasnovani na bajtovima, ali klase Reader i Writer su zasnovane na znakovima koji mogu imati različite veličine, zavisno od sistema znakova. Na primer ASCII i ISO Latin-1 koriste znakove veličine jedan bajt. Unicode koristi znakove od dva bajta. UTF-8 koristi znakove varijabilne dužine, od jednog do tri bajta. Reader i Writer znaju kako da rukuju tim znakovnim sistemima kao i mnogim drugim.

Klasa Reader

Metode iz klase java.io.Reader namerno su napravljene tako da budu slične metodama iz klase java.io.InputStream. Međutim, umesto da rade s bajtovima, one rade sa znakovima (char).

Osnovna read() metoda čita pojedinačni znak (koji može zauzimati od jednog do četiri bajta, u yavisnosti od znakovnog sistema) i vraća ga kao int između 0 i 65535. Ako naiđe na kraj streama, vraća -1.

public int read() throws IOException

Možete učitati i više znakova odjednom u polje znakova. Metode koje to rade vraćaju broj uspešno učitanih znakova ili -1 ako naiđu na kraj streama.

public int read(char[] text) throws IOException public abstract int read(char[] text, int offset, int length) throws IOException

Sve read() metode blokiraju se ako nije dostupan neki input, ako se pojavi I/O error ili ako naiđu na kraj streama.

42

Page 43: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Možete preskočiti određeni broj znakova pomoću metode skip(). Ona će se takođe blokirati ako nema dostupnog ulaza. Vraća broj preskočenih znakova ili -1 ako je naišla na kraj streama.

public long skip(long n) throws IOException

Metoda ready() vraća true ako je Reader spreman za čitanje, false inače. Uopšteno, to će biti ako pripadni stream ima dostupnih podataka.

public boolean ready() throws IOException

Reader može ili ne mora podržavati markiranje i resetovanje. Metoda markSupported() vraća true ako pripadni stream podržava markiranje i resetovanje, false inače.

public boolean markSupported() public void mark(int readAheadLimit) throws IOException public void reset() throws IOException

Konačno, metoda close() zatvara stream i slobađa resurse koji su s njim povezani.

public abstract void close() throws IOException

Klasa Writer

Metode iz klase java.io.Writer napravljene su tako da budu slične metodama iz java.io.OutputStream. Takođe, umesto da rade s bajtovima, one rade sa znakovima (char).

Osnovna write() metoda ispisuje pojedinačni znak od dva bajta sa vrednošću između 0 i 65535. Vrednost se uzima iz dva niža bajta argumenta (preostala dva viša bajta se ignorišu). Potklase koje žele efikasno da pišu znakove moraće da prekriju ovu metodu.

public void write(int c) throws IOException

Takođe, možete ispisati polje znakova, podpolje znakova, string ili substring.

public void write(char[] text) throws IOException public abstract void write(char[] text, int offset, int length) throws IOException public void write(String s) throws IOException public void write(String s, int offset, int length) throws IOException

Kao svi izlazni streamovi, i ovi će možda biti baferisani na nivou operativnog sistema. Ako želite sami da odredite kada će se ispis izvršiti, pozovite metodu flush().

public abstract void flush() throws IOException

Konačno, metoda close() zatvara stream i oslobađa resurse koji su s njim povezani.

43

Page 44: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

public abstract void close() throws IOException

Klasa InputStreamReader

Klasa java.io.InputStreamReader služi kao most između streamova bajtova i streamova znakova. Čita bajtove s ulaznog streama i prevodi ih u znakove u skladu sa zadatim znakovnim sistemom.

Znakovni sistem (encoding) može se zadati u konstruktoru ili se može prihvatiti default sistem sa računara.

public InputStreamReader(InputStream in) public InputStreamReader(InputStream in, String encoding) throws UnsupportedEncodingException

Na primer, da biste priključili InputStreamReader na System.in sa pretpostavljenim znakovnim sistemom (najčešće ISO Latin-1), stavili biste:

InputStreamReader isr = new InputStreamReader(System.in);

S druge strane, ako želite da čitate datoteku koja je bila napisana u fontu Macintosh Symbol, možete to učiniti ovako:

FileInputStream fis = new FileInputStream("symbol.txt"); InputStreamReader isr = new InputStreamReader(fis, "MacSymbol");

Metoda getEncoding() vraća string koji sadrži ime znakovnog sistema koji se trenutno koristi.

public String getEncoding()

Ostale metode predefinišu metode iz java.io.Reader, ali se, iz programske perspektive, ponašaju na isti način kao i one.

public int read() throws IOException public int read(char c[], int off, int length) throws IOException public boolean ready() throws IOException public void close() throws IOException

Klasa OutputStreamWriter

Klasa java.io.OutputStreamWriter povezuje izlazne bajt streamove i znakovne streamove. Ispisuje bajtove na pripadni izlazni stream nakon prevođenja znakova u skladu sa zadatim znakovnim sistemom.

Znakovni sistem može se zadati u konstruktoru ili se može prihvatiti default sistem sa platforme.

44

Page 45: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

public OutputStreamWriter(OutputStream out, String enc) throws UnsupportedEncodingException public OutputStreamWriter(OutputStream out)

Na primer, da biste priključili OutputStreamWriter na System.out sa pretpostavljenim znakovnim sistemom (najčešće ISO Latin-1), stavili biste:

OutputStreamWriter osw = new OutputStreamWriter(System.out);

S druge strane, ako želite da pišete u datoteku u Macintosh Symbol fontu, možete to učiniti ovako:

FileOutputStream fos = new FileOutputStream("symbol.txt"); OutputStreamWriter osw = new OutputStreamWriter(fos, "MacSymbol");

Metoda getEncoding()vraća string koji sadrži ime znakovnog sistema koji se trenutno koristi.

public String getEncoding()

Ostale metode predefinišu metode iz java.io.Writer.

public void write(int c) throws IOException public void write(char c[], int offset, int length) throws IOException public void write(String s, int offset, int length) throws IOException public void flush() throws IOException public void close() throws IOException

Klasa FileWriter

Klasa java.io.FileWriter služi za pisanje tekstualnih datoteka koristeći pretpostavljeni znakovni sistem i veličinu bafera s platforme. Ako želite da promenite te vrednosti, konstruišite OutputStreamWriter i priključite ga na FileOutputStream. Ova klasa nema sopstvenih metoda (samo nasleđene), a deklarisani su samo konstruktori.

public FileWriter(String fileName) throws IOException public FileWriter(String fileName, boolean append) throws IOException public FileWriter(File file) throws IOException public FileWriter(FileDescriptor fd)

Npr:

FileWriter fw = new FileWriter("izlaz.txt");

45

Page 46: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Klasa FileReader

The java.io.FileReader služi za čitanje tekstualnih datoteka koristeći pretpostavljeni znakovni sistem i veličinu bafera s platforme. Ako želite da promenite te vrednosti, konstruišite InputStreamReader i priključite ga na FileInputStream. Ova klasa nema sopstvenih metoda (samo nasleđene), a deklarisani su samo konstruktori.

public FileReader(String fileName) throws FileNotFoundException public FileReader(File file) throws FileNotFoundException public FileReader(FileDescriptor fd)

Npr:

FileReader fr = new FileReader("36.html");

Klasa BufferedReader

Klasa java.io.BufferedReader je potklasa od java.io.Reader koju možete da ulančate sa drugom Reader klasom zbog baferisanja znakova. To omogućuje efikasnije čitanje znakova i linija.

Klasa BufferedReader takođe je značajna i zbog svoje readLine() metode koja omogućuje čitanje teksta liniju po liniju.

Kod svakog čitanja sa nebaferisanog Readera, obavlja se i odgovarajuće čitanje s pridruženog ulaznog streama. Zato nije loša ideja priključiti BufferedReader na svaki Reader čije su operacije čitanja skupe, kao npr. za FileReader. Na primer,

BufferedReader br = new BufferedReader(new FileReader("ulaz.txt"));

Postoje dva konstruktora, jedan sa pretpostavljenom veličinom bafera od 8192 znaka, dok drugi dozvoljava specifikaciju veličine bafera:

public BufferedReader(Reader in, int sz) public BufferedReader(Reader in)

Jedina nova metoda u toj klasi je readLine():

public String readLine() throws IOException

Ona vraća String koji sadrži liniju teksta iz tekstualne datoteke. Nizovi \r, \n, i \r\n su defaultni znakovi za prelaz u novi red i nisu uključeni u vraćeni String.

Klasa BufferedReader dopušta markiranje i resetovanje, barem do dužine bafera.

public boolean markSupported()

46

Page 47: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

public void mark(int readAheadLimit) throws IOException public void reset() throws IOException

Konačno, BufferedReader redefiniše nekoliko metoda iz svoje natklase Reader, ali se način njihove upotrebe uopšte ne menja.

public int read() throws IOException public int read(char c[], int off, int length) throws IOException public long skip(long n) throws IOException public boolean ready() throws IOException public void close() throws IOException

Klasa BufferedWriter

Klasa java.io.BufferedWriter je potklasa od java.io.Writer koju možete da uparite sa drugom Writer klasom zbog baferisanja znakova. To omogućuje efikasnije ispisivanje teksta.

Svaki put kad pišete na nebaferisani Writer, obavlja se i pisanje na pridruženi izlazni stream. Zato nije loša ideja priključiti BufferedWriter na svaki Writer čije operacije pisanja su skupe, a ne traže trenutni odziv. Taj postupak npr. za FileWriter izgleda ovako:

BufferedWriter bw = new BufferedWriter(new FileWriter("izlaz.txt"));

Postoje dva konstruktora, jedan sa pretpostavljenom veličinom bafera od 8192 znaka, dok drugi dozvoljava specifikaciju veličine bafera:

public BufferedWriter(Writer out) public BufferedWriter(Writer out, int size)

U ovoj klasi nova je metoda newLine() koja ispisuje string za završetak linije. On zavisi od platforme pa tako imamo \n za Unix, \r za Mac, \r\n za Windows.

public String newLine() throws IOException

Konačno, BufferedWriter redefiniše nekoliko metoda iz svoje natklase Writer.

public void write(int c) throws IOException public void write(char c[], int off, int length) throws IOException public void write(String s, int offset, int length) throws IOException public void flush() throws IOException public void close() throws IOException

47

Page 48: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Baze podataka

Baza podataka je kolekcija podataka organizovanih za brzo pretraživanje i pristup, koja zajedno sa sistemom za administraciju, organizovanje i memorisanje tih podataka, čini sistem baze podataka. Iz ugla korisnika, podaci su na neki logički način povezani. Oni predstavljaju neke aspekte realnog sveta.

Korisnici pristupaju bazi podataka prvenstveno preko upitnika. Korišćenjem ključnih reči i svrstavanjem komandi korisnici mogu brzo da pronađu, preurede, grupišu i odaberu oblast u mnogim zapisima koje treba vratiti ili pomoću kojih treba sastaviti izveštaje o naročitoj skupini podataka u skladu s pravilima dotičnog sistema vođenja baze podataka.

Postoje različite vrste baza podataka, zavisno od toga, na koji način su podaci interno organizovani. Tako se razlikuju hijerarhijske, mrežne (CODASYL), relacionalne, objektno-orijentisane, objektno-relacione, prilagođene za WEB, XML i multimedijske baze podataka.

Podaci su predstavljeni na uniformni način (npr. u relacionim bazama podataka podaci su organizovani u tabelama), što olakšava pristup i korišćenje od strane eksternih programa. Tako jednu bazu podataka može koristiti niz različitih programa, pisanih u različitim programskim jezicima.

Obraćanje bazama podataka

Pristup podacima predstavlja postupak izvlačenja ili manipulisanja podacima, koji su preuzeti sa izvora podataka. Izvor podataka moze biti relaciona baza podataka, tekstualna datoteka na računaru, radna tabela i sl. Biblioteka JDBC (Java Database Connectivity) predstavlja interfejs za relacione baze podataka. Obezbeđuje načine za izvršavanje SQL (Structured Query Language) naredbi za pristup i rad na rel. bazi podatka. Implementirana je u java.sql paketu kao skup klasa i interfejsa koji obezbeđuju jedinstven API za pristup širokom spektru baza podataka.

Tabele

Relaciona baza podataka je sačinjena od tabela. Tabela kao što je dosije predstavlja osnovni sklop u bazi podataka sa kojom ćemo raditi. U relacionoj terminologiji, tabela predstavlja skup redova popunjenih u skladu sa specifikacijama u odgovarajućim kolonama. Kolona definiše

48

Page 49: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

sastavni deo svakog reda i nazivaju se poljima, a te stavke sa podacima u redu, atributima. Broj kolona za određenu tabelu je fiksan. Svaki red predstavlja skup elementarnih podataka koji sačinjavaju entitet poznat kao zapis(record). Izraz skup zapisa (recordset) koristi se za opis skupa redova koji nastaje pri izvršenju neke SQL komande.

Uvod u SQL

Struktuirani upitni jezik, SQL, je međunarodno prihvaćen oficijelni standrard za pristup relacionim bazama podataka. Svaki upit podseća na rečenicu engleskog jezika, sintaksa je laka za učenje a kontstrukcija i koncepti laki za shvatanje. Uvek se izdaju komande koje upućujemo bazi podataka, a ona vraća potrebne podatke ili sprovodi akciju. Potrebno je dodeliti tip podatka naslovu svake kolone, koja propisuje oblik podatka u koloni koja se skladišti u određenoj tabeli. Neki primeri SQL tipova podataka su:

CHAR Niz znakova fiksne dužine

VARCHAR Niz znakova promenljive dužine

BOOLEAN Logička vrednost true ili false

SMALLINT Mala celobrojna vrednost, od -127 do +127

INTEGER Veća celobrojna vrednost, od -32767 do +32767

FLOAT Vrednost sa promenljivom pozicijom decimalne tačke

DOUBLE Vrednost više preciznosti sa promenljivom pozicijom decimalne tačke

DATE Datum

TIME Vreme

DATETIME Datum i vreme

NULL predstavlja odsustvo vrednosti kod svih SQL podataka. Ne može se upoređivati jedan NULL sa drugim NULL podatkom, već samo možemo odrediti da li, ili ne, neki atribut ima vrednost NULL. Treba napomenuti da ne podržavaju sve baze podataka tip VARCHAR, tada moramo pretpostaviti i definisati maksimalnu dužinu polja.

49

Page 50: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

SQL naredbe

Data Definition Language (DDL) naredbe koje se koriste za opisivanje tabela i podataka koje one sadrže

Data Manipulation Language (DML) naredbe koje se koriste za rad sa podacima

SELECT naredbe – naredbe koje vraćaju skup rezultata

sve drugo – naredbe koje ne vraćaju skup rezultata

CREATE TABLE autor ( id INT NOT NULL PRIMARY KEY, ime CHAR(15) NOT NULL, prezime CHAR(25) NOT NULL, adresa CHAR(30), datum_rodjenja DATE); CREATE TABLE knjiga ( isbn CHAR(10) NOT NULL PRIMARY KEY naslov CHAR(50) NOT NULL, id_autora INT NOT NULL);

INSERT naredbe

Rezultat ovih naredbi je novi red umetnut u tabelu.

INSERT INTO autori (id, ime, prezime, datum_rodjenja) VALUES (56, ‘Ivo’, ‘Andric’, DATE(‘1982-10-09’)); Primetiti da ova komanda ne popunjava sve kolone, tj. kolona adresa se popunjava vrednošću NULL. INSERT INTO knjiga (isbn, naslov, id_autora) VALUES (‘1874416680’, ‘Na Drini cuprija’, 56); Što je ekvivalentno sledećoj naredbi: INSERT INTO knjiga VALUES (‘1234567890, ‘Na Drini cuprija’, 56);

50

Page 51: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

SELECT naredbe Služe za izvlačenje informacija iz baze podataka. Podatke koje dobijemo su u obliku skupa zapisa (recordset) što je tabela sa fiksnim brojem redova i kolona, koja je podskup neke tabele podataka. SELECT ime, prezime, id AS identifikator_autora FROM autor; SELECT a.ime, a.prezime, b.naslov FROM autori a, knjiga b WHERE a.id = b.id_autora; UPDATE naredbe Služe za ažuriranje, obezbeđuju način za modifikovanje postojećih podataka u tabeli. UPDATE autor SET ime = ‘Boris’ WHERE id = 56; DELETE naredbe Brišu pojedine redove iz tabele. DELETE FROM knjiga WHERE isbn = ‘1234567890’;

JDBC paket

JDBC (Java Database Connectivity) biblioteka projektovana je kao interfejs za izvršavanje SQL naredbi. Iako ne mapira automatski Java klase u redove baze podataka, ona dopušta da se veliki broj aplikacija piše za JDBC interfejs.

JDBC je dobro izolovana od karakteristika korišćenog sistema beze podataka, tako da ne mora da se projektuje za pojedine baze podataka.

Jedan od osnovnih principa projekta JDBC bio je da se u praksi omogući izrada JDBC upravljačkih programa na osnovu API interfejsa drugih baza podataka. Postoji veoma blisko mapiranje između JDBC arhitekture i API, kao i njihovih odgovarajućih ODBC replika.

(Open DataBase Connectivity (ODBC), je jedan standardni metod za povezivanje programa sa bazama podataka. Standard je razvila SQL Access grupa 1992 godine sa ciljem da se bilo kom podatku može pritupiti iz bilo koje aplikacije nezavisno od sistema za upravljanje bazama podataka (DBMS). To

51

Page 52: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

se postiže umetanjem drajvera za baze podataka kao interfejsa (srednjeg sloja) izmeu aplikacije i DBMS-a. Ovi drajveri mogu se naći u u Microsoft .NET Framework biblioteci.)

Važne zajedničke komponente:

DriverManager Učitava upravljačke programe (driver) baze podataka i upravlja vezama, konekcijama, između aplikacije i upravljačkog programa.

Driver Prevodi API pozive u operacije nad određenim izvorom podataka.

Connection Sesija između aplikacije i baze podataka.

Statement SQL naredba za izvršenje upita ili ažuriranje podataka.

Metadata Informacije o dobijenim podacima, bazi podataka i upravljačkom programu.

ResultSet Logički skup kolona i redova podataka, dobijenih po izvršenju naredbe.

Svaki JDBC program obuhvata sledeće korake:

• uvoz neophodnih klasa • učitavanje JDBC upravljačkog programa • identifikacija izvora podataka • izdvajanje objekta Connection • izdvajanje objekta Statement • izvršenje upita pomocu objekta Statement • izvlačenje podataka iz dobijenog objekta ResultSet • zatvaranje ResultSet • zatvaranje objekta Statement • zatvaranje objekta Connection

Podešavanje baze podataka

Koristićemo prethodno napravljenu MS Access bazu podataka. Pro treba da podesimo upravljački program za datu bazu u Accessu u okviru za dijalog ODBC Data Source Administrator. Dobijamo ga putem Start -> Settings -> Control Panel -> ODBC Data Sources. Izaberite jezičak kartice System DSN pri vrhu okvira i pritisnite dugme Add. U okviru sa listom odaberite Microsoft Access Driver (*.mdb) i pritisnite Finish. Zatim se pojavljuje sledeći okvir

52

Page 53: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

za dijalog, ODBC Microsoft Access Setup, u polju Data Saurce Name unesite autoriDb. U Database odeljku okvira pritisnite Select i pronađite datoteku autoriDb.mdb, zatim pritisnite OK, i još jednom OK u okviru ODBC Microsoft Access Setup. Odeljak System DSN bi trebalo da sadrži autoriDb u listi dostupnih sistemskih izvora podataka. Još jednom OK da bismo završili postupak.

Klasa DriverManager

Upravljački programi JDBC baza podataka definisani su prema klasama koje implementiraju Driver interfejs. Klasa DriverManager odgovorna je za uspostavljanje konekcija sa izvorima podataka, kojima se pristupa kroz JDBC upravljačke programe. Upravljački program koji želimo da koristimo učitavamo pozivanjem statičke metode forName() klase Class i prosleđivanjem objekta String kao argumenta koji sadrži ime klase upravljačkog programa, npr:

Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”); U slučaju povezivanja sa bazom MySQL, možete da koristite drajver mm. Tada kod može da izgleda ovako: Class.forName(“org.gjt.mm.mysql.Driver”); Ako koristite Microsoftov JDBC drajver za povezivanje sa Microsoft SQL Serverom, onda se drajver učitava na sledeći način: Class.forName(“com.microsoft.jdbc.sqlserver.SQLServerDriver”); Metoda forName() može baciti izuzetak tipa ClassNotFoundException ako klasa tog upravljačkog programa ne može da se pronađe. Zato je moramo obaviti odgovarajućim try-catch blokom. Kada nam je potrebna konekcija za neki JDBC upravljački program, ne pravimo novi objekat oblikujući konekciju sami, vec to tražimo od DriverManager-a da uradi za nas. Klasa DriverManager obezbeđuje nekoliko statičkih metoda za izradu objekata koji implementiraju Connection interfejs i koji oblikuju konekciju prema bazi podataka. To su preopterećene verzije metode getConnection(). Ovaj metod vraća objekat java.sql.Connection.

Interfejs Driver

Svaka klasa za JDBC drajver implementira ovaj interfejs. Klasa samog drajvera se učitava i registruje preko DriverManager klase. DriverManager može da rukuje sa više drajvera. U

53

Page 54: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

slučaju da postoji više registrovanih drajvera, DriverManager će svakom od njih poslati odgovarajući URL i pokušati da dobije vezu sa bazom.

Objekti Connection

Konekcija na određeni izvor podataka predstavljena je objektom klase koja implementira interfejs Connection. Ovaj objekat predstavlja uspostavljenu konekciju a koristimo ga da bi napravili Statement objekat, koji nam omogućava da definišemo i izvršavamo određene SQL naredbe. Pre bilo kakve SQL naredbe mora se obezbediti Connection objekat. Najjednostavniji oblik metode getConnecton(), klase DriverManager, je:

Connection con = DriverManager.getConnection(url); Dok je potpis metode getConnection(): public static Connection getConnection(String url, String user, String password); Argument url je String koji definiše URL, koji identifikuje lokaciju baze podataka, dok user i password nisu obavezni argumenti. Url je oblika: jdbc:potprotocol:podime Ako koristimo JDBC-ODBC most, onda je potprotokol odbc, a podime je DSN ime za tu bazu podataka. Na primer za DSN po imenu autoriDb, url je: jdbc:odbc:autoriDb i povezujemo se sa bazom preko komande Connection con = DriverManager.getConnection(“jdbc:odbc:autoriDb”); Ako želimo da se povežemo sa bazom MySQL, onda je deo potprotokol “mysql”, a podime je ime mašine i baze podataka. Na primer, u sledećem kodu je pokazano kako da dobijete objekat Connection za MySQL bazu podataka po imenu autoriDb, koja se nalazi na serveru po imenu knjizara. U primeru je zadat korisnik “admin” i lozinka “tajna”. Connection con = DriverManager.getConnection(“jdbc:mysql///knjizara/autoriDb”,“admin”, “tajna”);

54

Page 55: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Ako želite da se za istog korisnika i lozinku, povežete sa SQL server bazom podataka, konekciju ćete dobiti na sledeći način: Connection con = DriverManager.getConnection(“jdbc:microsoft:sqlserver:// knjizara:1433;”,”admin”,”tajna”);

Objekti Statement Predstavlja objekat klase koja implementira interfejs Statement. Obezbeđuje nam prostor da napravimo SQL upit, izvršimo ga i izvučemo bilo koji od dobijenih rezultata. Objekat pravimo pozivom metode createStatement() validnog objekta Connection. Kada napravimo objekat Statement mozemo izvršiti naš SQL upit pozivanjem metode executeQuery() tog objekta. Rezultat se vraća kao objekat tipa ResultSet. ResultSet rezultati = statement.executeQuery(“SELECT ime, prezime FROM autori”);

Objekti ResultSet Rezultati izvršenja SQL upita vraćaju se u obliku objekta, koji implementira ResultSet interfejs, i koji sadrži tabelu koju je proizveo SLQ upit. Objekat ResultSet sadrži kursor kojim možemo da manipulišemo i postavimo ga na bilo koji red u skupu rezultata. Inicijalno je postavljen da pokazuje na poziciju pre prvog reda. Metodama next(), previous(), first(), last(), beforeFirst(), afterLast() postavljamo kursor na sledeću poziciju, prethodnu, prvu, poslednju, pre prve, odmah iza poslenje, respektivno. Next i previous vraćaju true ako se pomere na validan red a false ako predjemo kraj tj. početak, tako da ih možemo koristiti u while petlji: while (resultSet.next()) { // ... radi nešto... } Takođe, možemo koristiti isLast() i isFirst() da proverimo da li smo dostigli kraj, odnosno početak skupa.

Pristupanje podacima u skupu rezultata

Pomoću ResultSet reference možemo da izvučemo vrednost bilo koje kolone u tekućem redu prema imenu ili poziciji. Takođe možemo dobiti informacije o tipovima podataka, broju kolona, itd. Interfens ResultSet definiše sledeće metode, naravno ovu su samo neke:

getBoolean() getDate() getDouble()

55

Page 56: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

getFloat() getInt() getLong()

getShort() getString getTime()

Kolona može biti izabrana prosleđivanjem SQL imena kolone kao String argument ili vrednosti indeksa za kolonu tipa int, pri čemu prva kolona ima indeks 1. Veličina slova u imenima kolona ne igra ulogu, pa je tako “Ime” i “ime” naziv iste kolone.

Kod svih metoda nepostojanje vrednosti (SQL NULL) vraća se kao ekvivalent, 0 u slučaju numeričkog polja, odnosno NULL u slučaju objekta i FALSE u slučaju logičkog polja. Ako dodje do greške u pristupu bazi, biće izbačen izuzetak tipa SQLException.

Primer testa sa bazom import java.sql.*; public class TestKonekcije { public static void main(String[] args) { // Ucitavamo upravljacki program try { // Ucitavamo klasu upravljackog programa Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); // Definisemo izvor podataka za upravljacki program String urlBaze = "jdbc:odbc:autoriDb"; // Pravimo konekciju Connection konekcija = DriverManager.getConnection(urlBaze); Statement upit = konekcija.createStatement(); ResultSet autori = upit .executeQuery("SELECT ime, prezime FROM autor"); // Ispisujemo podatke while (autori.next()) { System.out.println(autori.getString("ime") + " " + autori.getString("prezime") + "\n"); } } catch (ClassNotFoundException e) {

56

Page 57: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

System.out.println(e); } catch (SQLException e) { System.out.println(e); } } }

Preuzimanje metadata za skup rezultata Metodom getMetaDate() objekta ResultSet vraća referencu za objekat tipa ResultSetMetaData. Interfejs ResultSetMetaData deklariše metode kojima dobijamo informacije o skupu rezultata. getColumnCount() vraća broj kolona u skupu rezultata kao int getColumnName(int) – naziv kolone kao String getColumnType(int) – tip kolone kao int koji definiše SQL tipove kao što su CHAR, VARCHAR, DOUBLE, INT TIME, itd. iz klase Types u paketu java.sql. Primer metadata import java.sql.*; public class TestKonekcije { public static void main(String[] args) { // Ucitavamo upravljacki program try { // Ucitavamo klasu upravljackog programa Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); // Definisemo izvor podataka za upravljacki program String urlBaze = "jdbc:odbc:autoriDb"; // Pravimo konekciju Connection konekcija = DriverManager.getConnection(urlBaze); Statement upit = konekcija.createStatement(); ResultSet autori = upit .executeQuery("SELECT ime, prezime FROM autor"); // Formiramo skup informacija ResultSetMetaData metadata = autori.getMetaData();

57

Page 58: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

// Preuzimamo brojkolona int brKolona = metadata.getColumnCount(); int red = 0; // broj reda while (autori.next()) { // za svaki red // ispisi brojac i inkrementiraj System.out.print("\nRed " + (++red) + ": ");

// za svaku kolonu for (int i = 1; i <= brKolona; i++) {

// ako je VARCHAR ispisi ga if (metadata.getColumnType(i) == Types.VARCHAR) System.out.print(" " + autori.getString(i)); } } } catch (ClassNotFoundException e) { System.out.println(e); } catch (SQLException e) { e.printStackTrace(); } } } Još jedna korisna metod je getColumnDisplazSize(int) koja vraca normirani maksimalni broj znakova koji je potreban za prikazivanje podataka uskladištenih u toj koloni. Druge korisne metode su: getTableName(int) vraća ime tabele za određenu kolonu, kao tip String. getColumnLabel(int) vraća objekat String, koji predstavlja preporučenu oznaku za kolonu koja

treba da se koristi za štampanje (obično ono definisano sa SQL AS naredbom).

isNullable(int) vraća vrednost int koja može da bude: columnNoNulls -> nije dopušteno NULL; columnNullable -> dopušteno je NULL; columnNullableUnknown -> nije poznato da li je dopušteno NULL.

isWritable(int) vraća true ako je dozvoljen upis u određenu kolonu.

Korišćenje objekta PreparedStatement

Objekti PreparedStatement razlikuju se od objekata Statement po tome što je SQL naredba prethodno kompajlirana i može da ima čuvare mesta (placeholders) za vrednosti parametara rutine. Posebno su korisni kada je u pitanju naredba koja će se izvršatavi mnogo puta. Referencu PreparedStatement dobijamo pozivom metode prepareStatement() u interfejsu Connection.

58

Page 59: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Primer: import java.sql.*; public class StatementTest { Connection konekcija; // konekcija ka bazi String imeDrajvera; // Ime upravljackog programa baze String urlBaze; // lokacija baze public static void main(String args[]) { StatementTest primerSQL; try { primerSQL = new StatementTest(); primerSQL.doStatement(); primerSQL.doPreparedStatement(); } catch (SQLException e) { System.out.println("SQL Exception: " + e); } catch (ClassNotFoundException ce) { System.out.println(ce); } } public StatementTest() throws SQLException, ClassNotFoundException { imeDrajvera = "sun.jdbc.odbc.JdbcOdbcDriver"; urlBaze = "jdbc:odbc:autoriDb"; Class.forName(imeDrajvera); konekcija = DriverManager.getConnection(urlBaze); } void doStatement() throws SQLException { Statement upit = konekcija.createStatement(); ResultSet mojRezultat = upit .executeQuery("SELECT id, prezime, ime FROM autor"); prikazi(mojRezultat); } void doPreparedStatement() throws SQLException { PreparedStatement upitP = konekcija

59

Page 60: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

.prepareStatement("SELECT id, prezime, ime FROM autor"); ResultSet mojRezultat = upitP.executeQuery(); prikazi(mojRezultat); } public void prikazi(ResultSet rezultati) throws SQLException { // preuzimamo ResultSetMetaData objekat iz result seta ResultSetMetaData metadata = rezultati.getMetaData(); // koliko kolona je vraceno int brKolona = metadata.getColumnCount(); System.out.println("--------- REZULTAT UPITA ----------"); // u petlji prolazimo kroz result set i citamo podatke while (rezultati.next()) { for (int i = 1; i <= brKolona; i++) System.out.print(rezultati.getString(i) + "\t"); System.out.println(); } System.out.println("--------- REZULTAT METADATA ----------"); System.out.println("Broj kolona u ResultSet-u je " + brKolona + "."); for (int i = 1; i <= brKolona; i++) { System.out.println("Kolona: " + i); // stampamo naziv kolone System.out.println("\tKolona\t\t:" + metadata.getColumnName(i)); // stampamo naziv labele System.out.println("\tLabela\t\t:" + metadata.getColumnLabel(i)); // stamapmo sirinu prikaza kolone System.out.println("\tSirina prikaza\t:" + metadata.getColumnDisplaySize(i)); // stampamo tip kolone System.out.println("\tTip podatka\t:" + metadata.getColumnTypeName(i)); } } }

60

Page 61: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Korišćenje tabela JTable komponenta iz paketa javax.swing idealna je za prikaz pravougaonog niza podataka na ekranu. Stavke podataka u tabeli ne moraju da budu istog tipa – upravo je to situacija koju imamo kod skupa rezultata. Koristićemo konstruktor klase JTable koji za argument uzima referencu tipa TableModel. JTable table = new JTable(model); “model“ je ovde promenljiva tipa TableModel koja skladišti referencu na objekat koji oblikuje Result Set.

TableModel interfejs Definisan je u paketu javax.swing.table. Klase koje implementiraju ovaj interfejs moraju da predefinišu 9 metoda. Međutim, postoji sraćena klasa, AbstractTableModel, koja implementira 6 od ovih 9 metoda, tako da ako proširimo ovu klasu, potrebno je da definišemo preostale 3 metode. Potpun skup metoda deklarisanih u TableModel interfejsu je sledeći:

1. int getColumnCount() – vraća broj kolona u modelu tabele 2. int getRowCount() - vraća broj vrsta u modelu tabele 3. Object getValueAt(int row, int column) – vraća vrednost iz tabele na specificiranoj

poziciji 4. Class getColumnClass(int column) – vraća tip klase podataka u koloni 5. String getColumnName(int column) – vraća ime kolone 6. void setValueAt(Object obj, int row, int column) – postavlja vrednost value za stavku

podataka određenu celobrojnim argumentima 7. boolean isCellEditable(int row, int column) – vraća informaciju o tome da li možemo da

editujemo specificirano polje tabele 8. void addTableModelListener(TableModelListener tml) – dodaje listener koji se

obaveštava svaki put kada se model tabele promeni 9. void removeTableModelListener(TableModelListener tml) – uklanja listener

Tipovi podataka i JDBC

ResulSet nam obezbeđuje metode za izvlačenje različitih tipova podataka. Standard SQL-92 definiše skup tipova podataka koji se ne mapiraju 1 na 1 sa onima u Javi. Zbog toga moramo voditi računa o načinu na koji JDBC sprovodi to mapiranje. Klasa types u paketu java.sql definiše konstante tipa int, koje predstavljaju svaki od podržanih SQL tipova. Ime koje nosi određeni podatak član, koji čuva neku od ovih konstanti isto je kao ime odgovarajućeg SQL tipa. Kada, npr. izvlačimo SQL tip za kolonu tabele pozivanjem metode getColumnType() klase ResultSet, SQL tip se vraća kao jednaod konstati definisanih u klasi types. Kada izvlačimo podatke iz nekog JDBC izvora podataka, implementacija ResultSet mapiraće SQL podatke prema Java tipovima podataka. Sledeća tabela prikazuje mapiranja SQL u Javu:

61

Page 62: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

SQL tip podatka Java tip podatka CHAR String VARCHAR String LONGVARCHAR String NUMERIC java.math.BigDecimal DECIAL java.math.BigDecimal BIT boolean TINYINT byte SMALLINT short INTEGER int BIGINT long REAL float FLOAT double DOUBLE double BINARY byte[] VARBINARY byte[] LONGVARBINARY byte[] DATE java.sql.Date TIME java.sql.Time TIMESTAMP java.sql.Timestamp

62

Page 63: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Obrnuto, kada se radi o Java-u-SQL tipovima podataka, primenjuje se sledeće mapiranje: Java tip podataka SQL tip podataka String VARCHAR, LONGVARCHAR Java.math.BigDecimal NUMERIC boolean BIT byte TINYINT short SMALLINT int INTEGER long BIGINT float REAL double DOUBLE byte[] VARBINARY, LONGVARBINARY java.sql.Date DATE java.sql.Time TIME java.sql.Timestamp TIMESTAMP SQL tip za svaku kolonu u skupu rezultata možemo da odredimo pozivanjem metode getColumnType() za objekat ResultSetMetaData. Zatim dobijenu vrednost poredimo sa konstantama, koje su definisane u klasi Types, da bismo izabrali metod getXXX() klase ResultSet koji je prikladan za izvlačenje određenih podataka.

Mapiranje relacionih podataka na Java objekte Primer - pravimo klasu Autor koja odgovara tabeli iz baze. Klasa Autor: import java.sql.Date; public class Autor { int id; String ime; String prezime; String adresa; Date datum; public Autor(int id, String ime, String prezime, String adresa, Date datum) { this.id = id; this.ime = ime; this.prezime = prezime; this.adresa = adresa; this.datum = datum;

63

Page 64: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

} public int getId() { return id; } public String getIme() { return ime; } public String getPrezime() { return prezime; } public String getAdresa() { return adresa; } public Date getDatum() { return datum; } public String toString() { return new String("Autor Id: " + Integer.toBinaryString(id) + "\nIme: " + prezime + " " + ime + "\nAdresa: " + adresa + "\nDatum rodjenja: " + datum.toString()); } } Glavna klasa: import java.sql.*; public class JednostavnoMapiranje { Connection konekcija; String imeDrajvera = "sun.jdbc.odbc.JdbcOdbcDriver"; String urlBaze = "jdbc:odbc:autoriDb"; String user = "gost"; String password = "gost"; public JednostavnoMapiranje() throws SQLException, ClassNotFoundException { Class.forName(imeDrajvera); konekcija = DriverManager.getConnection(urlBaze, user, password); }

64

Page 65: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

public void listaAutora() throws SQLException { Autor autor; String upit = "SELECT id, ime, prezime, adresa, datum_rodjenja " + "FROM autor"; Statement izraz = konekcija.createStatement(); ResultSet autori = izraz.executeQuery(upit); while(autori.next()) { int id = autori.getInt(1); String ime = autori.getString(2); String prezime = autori.getString(3); String adresa = autori.getString(4); Date datum = autori.getDate(5); autor = new Autor(id, ime, prezime, adresa, datum); System.out.println("\n" + autor); } autori.close(); konekcija.close(); } public static void main(String args[]) { JednostavnoMapiranje primer; try { primer = new JednostavnoMapiranje(); primer.listaAutora(); } catch(SQLException se) { System.err.println(se); } catch(ClassNotFoundException ce) { System.err.println(ce); } } }

Poboljšana strategija mapiranja Kada napravimo klasu koja odgovara tabeli u bazi, bilo bi efikasnije da ta klasa rukuje ekstrahovanjem sopstvenih podataka iz objekta ResultSet. Zbog toga dodajemo metod toj klasi koji pravi objekte te klase koristeći podatke iz baze. Potrebno je osigurati da objekat ResultSet

65

Page 66: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

sadrži sve kolone koje su potrebne za popunjavanje objekta definisane klase. Ovaj pristup je bolji zato što je sama klasa odgovorna da osigura pravilno mapiranje izmedju baze podataka i Java objekta. Na taj način, aplikacije ne moraju da dupliraju ovu logiku i nemaju mogućnost da pokušaju pogrešno mapiranje. Takođe, mapiranje je nezavisno od sekvence kolona u skupu rezultata. Enkapsuliranje mapiranja podataka iz baze u objekat klase je važno jer osigurava da klase mogu lako ponovo da se koriste unutar i između aplikacija. U klasu autor dodati metodu: public static Autor izResultSeta(ResultSet autori) throws SQLException { return new Autor ( autori.getInt("id"), autori.getString("ime"), autori.getString("prezime"), autori.getString("adresa"), autori.getDate("datum_rodjenja") ); } I napraviti novu klasu: import java.sql.*; public class PoboljsanoMapiranje { Connection konekcija; String imeDrajvera = "sun.jdbc.odbc.JdbcOdbcDriver"; String urlBaze = "jdbc:odbc:autoriDb"; String user = "gost"; String password = "gost"; public PoboljsanoMapiranje() throws SQLException, ClassNotFoundException { Class.forName(imeDrajvera); konekcija = DriverManager.getConnection(urlBaze, user, password); } public void listaAutora() throws SQLException { Autor autor; String upit = "SELECT id, ime, prezime, adresa, datum_rodjenja " + "FROM autor"; Statement izraz = konekcija.createStatement(); ResultSet autori = izraz.executeQuery(upit); while(autori.next())

66

Page 67: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

{ System.out.println("\n" + Autor.izResultSeta(autori)); } autori.close(); konekcija.close(); } public static void main(String args[]) { PoboljsanoMapiranje primer; try { primer = new PoboljsanoMapiranje(); primer.listaAutora(); } catch(SQLException se) { System.err.println(se); } catch(ClassNotFoundException ce) { System.err.println(ce); } } }

Interfejsi Statement i PreparedStatement

U opštem slučaju, ne znamo koliko će podataka biti vraćeno posle izvršenja upita. Preuzimanje milion redova posle operacije SELECT može da bude neprijatno, posebno zbog toga što je u to uključena značajna količina memorije i vremena. Interfejs Statement nam omogućava da ograničimo broj redova u rezultatu, da navedemo maksimalnu veličinu polja i da ograničimo vremenski period za izvršavanje upita.

Metode getMaxRows() i setMaxRows dopuštaju da izvršimo upit i postavimo maksimalan broj redova koji se vraćaju u objektu ResultSet. Vrednost 0 definiše da nema ograničenja. Metodu getMaxRows() koristimo da bismo odredili efektivno ograničenje broja redova. Metodu setMaxRows() koristimo da ograničimo broj vraćenih redova.

Napomena: Ako ukupan broj redova prevazilazi maksimalnu vrednost, u skupu rezultata vraća se taj maksimalan broj redova, a svi preostali redovi koji ispunjavaju uslove upita neprimetno ostaju po strani i nećemo dobiti informaciju da su vraćeni podaci okrnjeni.

67

Page 68: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Za određivanje i postavljanje maksimalne veličine vraćenog polja koristimo metode getMaxFieldSize() i setMaxFieldSize().Vrednost 0 i ovde znači da nema ograničenja. Pri tome, metode setMaxFieldSize() se primenjuje jedino na kolone sa sledećim SQL tipovima:

BINARY, VARBINARY, LONGVARBINARY, CHAR, VARCHAR, LONGVARCHAR.

U zavisnosti od JDBC-a i baze podataka sa kojom se on povezuje, može da se pojavi time-out period izvršenja, posle kojeg će metod executeQuery() izbaciti izuzetak. Možemo proveriti vrednost ovog time-out perioda pomoću metode getTimeOut() za objekat Statement ili podesiti time-out period pomoću metoda setQueryTimeOut().

Primer testira podrazumevana ograničenja upita:

import java.sql.*; public class TestTimeOut { public static void main(String args[]) { Statement upit = null; try { Connection konekcija; String imeDrajvera = "sun.jdbc.odbc.JdbcOdbcDriver"; String urlBaze = "jdbc:odbc:autoriDb"; String user = "gost"; String password = "gost"; Class.forName(imeDrajvera); konekcija = DriverManager.getConnection(urlBaze); upit = konekcija.createStatement(); System.out.println("Drajver: " + imeDrajvera); } catch(SQLException se) { System.err.println(se); } catch(ClassNotFoundException ce) { System.err.println(ce); } //sve stavljam u poseban try/catch da bi se sve metode ozvrsile try { System.out.print("Maksimalan broj vrsta: "); int maxVrste = upit.getMaxRows(); System.out.print(maxVrste == 0 ? "Bez ogranicenja" : maxVrste);

68

Page 69: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

} catch(SQLException se) { System.err.println(se); } try { System.out.print("\nMaksimalna velicina polja: "); int maxPolje = upit.getMaxFieldSize(); System.out.print(maxPolje == 0 ? "Bez ogranicenja" : maxPolje); } catch(SQLException se) { System.err.println(se); } try { System.out.print("\nTimeout: "); int timeout = upit.getQueryTimeout(); System.out.print(timeout == 0 ? "Bez ogranicenja" : timeout); } catch(SQLException se) { System.err.println(se); } } } Izlaz oblika:

Drajver: sun.jdbc.odbc.JdbcOdbcDriver Maksimalan broj vrsta: Bez ogranicenja Maksimalna velicina polja: java.sql.SQLException: [Microsoft][ODBC Microsoft Access Driver]Optional feature not implemented Timeout: java.sql.SQLException: [Microsoft][ODBC Microsoft Access Driver]Optional feature not implemented

znači da navedeni ODBC upravljački program ne podržava ograničenja za time-out ni za veličine polja.

69

Page 70: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Izvršenje DDL i DML

Podsećanje – DDL naredbe su one koje menjaju strukturu baze podataka, kao što su CREATE TABLE i DROP TABLE, a DML su one koje menjaju sadržaj baze, kao što su INSERT, UPDATE i DELETE.

Primer kreiranja nove tabele knjiga iz našeg programa korišćenjem metode executeUpdate().

import java.sql.*; public class BuildTables { public static void main(String args[]) { try { Connection konekcija; String imeDrajvera = "sun.jdbc.odbc.JdbcOdbcDriver"; String urlBaze = "jdbc:odbc:autoriDb"; String SQLupiti[] = { "CREATE TABLE knjiga1 (isbn CHAR(10) NOT NULL PRIMARY KEY, " + "naslov CHAR(50) NOT NULL, " + "id_autora INT NOT NULL)", "INSERT INTO knjiga1 VALUES('12345', 'na drini cuprija' , 23)", "INSERT INTO knjiga1 VALUES('23456', 'koreni' , 22)" }; Class.forName(imeDrajvera); konekcija = DriverManager.getConnection(urlBaze); Statement upit = konekcija.createStatement(); for(int i = 0; i<SQLupiti.length; i++) { upit.executeUpdate(SQLupiti[i]); System.out.println(SQLupiti[i]); }

konekcija.close(); } catch(SQLException se) { System.err.println(se); } catch(ClassNotFoundException ce) { System.err.println(ce);

70

Page 71: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

} } }

Poređenje Statement i PreparedStatement

Interfejs PreparedStatement omogućava vam da definišete SQL naredbu sa čuvarima mesta (placeholders) za argumente. Oni predstavljaju tokene koji se pojavljuju u SQL naredbi, a koji se zamenjuju stvarnim vrednostima pre izvršenja SQL naredbe. To je mnogo lakše od izrade naredbi sa posebnim vrednostima nadovezivanjem preko povezanih stringova. import java.sql.*; public class Placeholders { public static void main(String[] args) { try { Connection konekcija; String imeDrajvera = "sun.jdbc.odbc.JdbcOdbcDriver"; String urlBaze = "jdbc:odbc:autoriDb"; Class.forName(imeDrajvera); konekcija = DriverManager.getConnection(urlBaze); String upitStr = "UPDATE autor SET prezime = ? WHERE id = ?"; PreparedStatement upit = konekcija.prepareStatement(upitStr); upit.setString(1, "Jovanovic"); upit.setInt(2, 33); int brPromenjenihRedova = upit.executeUpdate(); System.out.println("Promenjeno " + brPromenjenihRedova + " redova"); konekcija.close(); } catch (ClassNotFoundException e) { System.err.println(e); } catch (SQLException e) { e.printStackTrace(); } } }

71

Page 72: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Objekte PreparedStatement je preporučljivo koristiti kada: 1. Treba da izvršite istu naredbu više puta, a pri tome treba da promenite samo određene

vrednosti. 2. Radite sa velikim količinama podataka, što čini nadovezivanje nezgrapnim. 3. Radite sa velikim brojem parametara u SQL naredbi, što čini nadovezivanje stringova

nezgrapnim rešenjem. Objekti Statement rade dobro kada imate jednostavne naredbe. Primer selektovanja iz dve tabele: import java.sql.*; public class DveTabele { public static void main(String[] args) { try { Connection konekcija; String imeDrajvera = "sun.jdbc.odbc.JdbcOdbcDriver"; String urlBaze = "jdbc:odbc:autoriDb"; Class.forName(imeDrajvera); konekcija = DriverManager.getConnection(urlBaze); Statement upit = konekcija.createStatement(); ResultSet rezultat = upit .executeQuery("SELECT a.ime, a.prezime, k.naslov " + "FROM autor a, knjiga k " + "where a.id = k.id_autora"); int red = 0; // broj reda while (rezultat.next()) { System.out.println((++red) + ". " + rezultat.getString("ime") + " " + rezultat.getString("prezime") + " \"" + rezultat.getString("naslov") + "\""); } } catch (ClassNotFoundException e) { System.err.println(e); } catch (SQLException e) { e.printStackTrace(); } } }

Posebni tipovi podataka Pored standardnih tipova podataka, java.sql definiše i posebne tipove, karakteristične za pojedine SQL tipove.

72

Page 73: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Date java.sql.Date definiše objekat koji vraca ResultSet.getDate(), potklasu klase java.util.Date. Metodom valueOf dobijamo datum u format yyyy-mmm-dd objekat tipa Date. Time Kao i java.sql.Date, i klasa java.sql.Time je potklasa klase java.util.Date i takođe obezbeđuje metod valueOf koji vraća vreme u formatu hh:mm:ss. Timestamp java.sql.Timestamp ima podršku za zapis sa nanosekundama. yyyy-mm-dd hh:mm:ss.fffffffff. Takođe obezbeđuje metode za poređenje before() i after() koji podržavaju upotrebu nanosekundi. Veliki brojevi SQL tipovi NUMERIC i DECIMAL mapirani su u Java tip klase BigDecimal. Ova klasa je definisana u paketu java.math zajedno sa klasom BigInteger. One koriste posebne metode za sabiranje, oduzimanje, množenje i deljenje kao i poređenje (add(), substract(), multiply() i divide(), compareTo(), …). Vrednost im je nepromenljiva, tj. jednom napravljenom objektu se ne može promeniti vrednost.

73

Page 74: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Umrežavanje

Podrška za umrežavanje u Javi je obezbeđena kroz java.net paket. Klase definisane u ovom paketu kapsuliraju koncept „utičnice“ (engl. socket).

Mrežna utičnica (network socket) je liči na električnu utičnicu sa razlikom što ovde govorimo o TCP/IP paketima i IP adresama. Internet protokol (IP) je osnovni protokol za usmeravanje koji raspodeljuje podatke na male pakete i šalje ih na određenu adresu u mreži, što ne garantuje isporuku paketa na odredište. Protokol kontrole prenosa (TCP) je protokol višeg nivoa koji snažno povezuje ove pakete, uređuje ih i po potrebi ponovo prenosi da bi osigurao pouzdani rad. Protokol za razmeni korisničkih dijagrama (UDP) stoji rame uz rame sa TCP protokolom i može se koristii za brži, ali nepouzdaniji transport paketa bez kontrole veze.

Klijent/server

Server je svaki element koji raspolaže resurima koji se mogu deliti. Klijent je drugi entitet koji želi da obezbedi pristup određenom serveru. Server je trajno rapoloživi resurs, a klijenti mogu slobodno da se isključe pošto budu usluženi. Priroda utičnica omogućava da jedan računar istovremeno opslužuje mnoštvo različitih klijenata i da ih snabdeva različitim vrstama podataka. To se postiže uvođenjem priključa (engl. port) – numerisanih utičnica na određenom računaru. Za proces servera se kaže da „osluškuje“ priključak sve dok se na njega ne poveže klijent. Serveru je dozvoljeno da opslužuje više klijenata na istom priključku, iako je svaka sesija jedinstvena. Da bi upravljao višestrukim priključivanjem klijenata, proces servera mora da bude višenitni ili mora na neki drugi način da obrađuje više simultanih ulaznih i izlaznih funkcija.

Posrednički serveri

Posrednički server (eng. proxy server) prenosi klijentske zahteve nekom drugom serveru. Ovo je često potrebno kada je broj servera na koje klijenti mogu da se povežu ograničen. Zbog toga se klijenti povezuju sa posredničkim serverom koji nema takva ograničenja, a za uzvrat posrednički server komunicira umesto klijenta. Posrednički server ima posebnu sposobnost filtriranja određenih zahteva ili čuvanja rezultata takvih zahteva u kešu, za kasniji rad. Posrednički HTTP server sa kešom (caching proxy) može da smanji potreban propusni opseg lokalnih mrežnih veza sa internetom. Kada se na popularnu Web lokaciju priključe stotine korisnika, proxy server samo jednom preuzme njen sadržaj, smanjujući tako skup prenos (istih stranica) po internetu i obezbeđujući klijentima brži pristup tim popularnim stranicama.

Adresiranje na internetu

Svaki računar na internetu ima svoju adresu. Internet adresa je broj koji jednoznačno identifikuje svaki računar na mreži. Prvobitno su sve adrese imale 32 bita (4 osmobitna polja) – tu vrstu adrese definisao je IPv4 stantard. Međutim, na snagu je stupila nova šema adresiranja, IPv6 –

74

Page 75: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

adresa ima 128 bitova podeljnih na osam 16-bitnih delova. Kompatibilnost IPv6 sa IPv4 postignuta je time što najniža 32 bita IPv6 adrese moraju sadržati valjanu IPv4 adresu.

Imenovanje domena – DNS

Kretanje po internetu ne bi bilo baš zgodno kada bi svi morali da zadaju adrese u vidu brojeva. Srećom, postoji servis za imenovanje domena (engl. Domain Nameing Service – DNS). Ime internet adrese opisuje lokaciju računara u imenskom prostoru.

Java i mreža

Java podržava TCP/IP protokol i proširivanjem već uspostavljenog mehanizma ulazno/izlaznih tokova i dodavanjem funkcija potrebnih za izgradnju ulazno-izlaznih objekata u mreži. Java podržava porodice TCP i UDP protokola. TCP se koristi za pouzdani tok podataka u mreži. UDP podržava jednostavniji i brži datagramski orijentisan model protokola od tačke do tačke (engl. point-to-point protocol).

Klasa InetAddress

Ova klasa kapsulira numeričke IP adrese i imena domena za te adrese. Od verzije J2SE 1.4, klasa InetAddress može da obradi i IPv4 i IPv6 adrese.

Klasa InetAdress nema vidljivih konstrukotra. Da bismo napravili objekat tipa InetAddress, moramo da upotrebimo jednu od raspoloživih metoda za pravljenje objekata. Te metode su samo konvencija – pomoću njih statičke metode klase vraćaju instatncu klase. Izbegava se preklapanje kostruktora različitim listama parametara, kada jednoznačna imena metoda čine rezultate mnogo jasnijim. Tri najčešće korišćene metode klase InetAddress za pravljenje instance su:

static InetAddress getLocalHost() throws UnknownHostException – vraća objekat klase InetAddress koji predstavlja lokalni računar

static InetAddress getByName(String imeRacunara) throws UnknownHostException – vraća objekat klase InetAdress za prosleđeno imeRacunara

static InetAddress[] getAllByName(String imeRacunara) throws UnknownHostException – vraća niz objekata InetAddress koji sadrži sve adrese na koje se osnosi određeno ime.

Primer:

import java.net.*; public class InetAddressPrimer { public static void main(String agrs[]) throws UnknownHostException { InetAddress adresa = InetAddress.getLocalHost(); System.out.println(adresa);

75

Page 76: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

adresa = InetAddress.getByName("vincaskola.rs"); System.out.println(adresa); InetAddress sve[] = InetAddress.getAllByName("www.nba.com"); for(int i = 0; i < sve.length; i++) System.out.println(sve[i]); } }

Klasa InetAddress ima i nekoliko drugih metoda koje mogu da se koriste na objektima koje vraćaju gore opisane metode. Najčešće korišćene su:

boolean equals(Object drugi) – vraća true ako objekat ima istu IP adresu kao i drugi

byte[] getAdress() – vraća niz bajtova koji predstavlja internet adresu objekta

String getHostAdress() – vraća znakovni niz koji predstavlja adresu računara

String getHostName() – vraća znakovni niz koji predstavlja ime računara

String toString() – vraća znakovni niz koji predstavlja ime računara i IP adresu

Napomena: Internet adrese se traže u grupi hijerarhijski povezanih servera. To znači da bi lokalni računar automatski mogao da zna određene parove imena i IP adresa. IP adrese za druga imena mora da potraži na lokalnom DNS serveru. Ako taj server ne zna neku IP adresu, može da pređe na udaljenu lokaciju i tamo je zatraži. Ovo se može nastaviti sve do korenskog servera. Ovaj postupak može da potraje, pa je dobro projektovati program tako da čuva IP adrese umesto da ih stalno traži.

Klase Inet4Address i Inet6Address

Od verzije 1.4 Java podržava IPv6 adrese, pa su zato napravljene 2 potklase od InetAddress: Inet4Address i Inet6Address. Objekat tipa Inet4Address predstavlja klasični IPv4 adresu. Inet6Address kapsulira IPv6 adresu novog stila. U najvećem broju slučajeva, za rad sa IP adresama može se upotrebljavati InetAddress klasa, zato što ona radi sa adresama obe vrste.

76

Page 77: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Klijentski TCP/IP soket

TCP/IP soketi se koriste za pravljenje pouzdanih, dvosmernih, trajnih veza od tačke do tačke između računara na internetu. Soket može da se koristi za povezivanje Javinog I/O sistema sa drugim programima na istom računaru ili na bilo kom računaru na internetu.

Napomena: Apleti mogu da uspostavljaju klijentske veze samo sa računarima sa kojih su preuzeti. Ovo ograničenje je uvedeno zato što bi bilo opasno da apleti preuzeti kroz zaštitnu barijeru imaju pristup svim računarima lokalne mreže.

U Javi postoje 2 vrste TCP soketa. Jedna za servere, druga za klijente. Klasa ServerSocket je projektovana tako da „osluškuje“, tj. da čeka da se klijenti priključe pre nego što bilo šta počne da radi. Klasa Socket je projektovana tako da se poveže sa serverskim soketima i inicira razmenu podataka. Pravljenje objekta klase Socket implicitno uspostavlja vezu između klijenta i servera. Ne postoje metode niti konstruktori koji izričito daju detalje uspostavljanja ove veze. Za pravljenje klijentskih portova koriste se sledeći konstruktori:

Socket(String imeRacunara, int brojPortova) – pravi soket koji povezuje lokalni računar sa zadatim računarom i brojem porta; može da izazove izuzetak tipa UnknownHostException ili IOException

Socket(InetAddress ipAdresa, int brojPortova) – pravi soket kpomoću postojećeg objekta klase InetAddress i broja porta; može da izazove izuzetak tipa IOException

Adresu i broj porta pridruženog soketu možemo dobiti pomoću metoda:

InetAddress getInetAddress() – vraća objekat klase InetAdress pridružen objektu klase Socket

int getPort() – vraća udaljeni port s kojim je povezan pozivajući objekat klase Socket

int getLocalPort() – vraća lokalni port sa kojim je povezan pozivajući objekat klase Socket

Kada napravimo objekat klase Socket, možemo pristupati ulaznim i izlaznim tokovima koji su mu pridruženi. Sledeće metode mogu da izazovu izuzetak tipa IOException ako su soketi nevažeći zbog prekinute veze sa mrežom.

InputStream getInputStream() – vraća ulazni tok pridružen soketu

OutputStream getOutputStream() – vraća izlazni tok pridružen soketu

Klasa URL

URL adresa (Uniform Resource Locator) obezbeđuje prilično razumljiv način jednoznačne identifikacije ili adresiranja informacija na Internetu. URL adrese u svuda zastupljene; svaki čitač ih koristi za identifikovanje podataka na Webu. U okviru Javine mrežne biblioteke, klasa URL obezbeđuje jednostavno programersko okruženje u kome se za pristup podacima na

77

Page 78: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

internetu koriste URL adrese. Ova klasa ima nekoliko konstruktora, a svaki od njih može izazvati izuzetak tipa MalformedURLException.

URL(String urlOdrediste)

URL(String imeProtokola, String imeRacunara, int port, String putanja)

URL(String imeProtokola, String imeRacunara, String putanja)

URL(URL urlObjekat, String urlOdrediste)

Jednostavan primer:

import java.net.*; public class URLPrimer{ public static void main(String args[]) throws MalformedURLException { URL hp = new URL("http://www.vincaskola.rs"); System.out.println("Protokol: " + hp.getProtocol()); System.out.println("Prikljucak(port): " + hp.getPort()); System.out.println("Racunar: " + hp.getHost()); System.out.println("Datoteka: " + hp.getFile()); System.out.println("Zajedno: " + hp.toExternalForm()); } }

Klasa URLConnection

URLConnenction je klasa opšte namene pomoću koje se pristupa sadržaju udaljenih resursa. Kada se povežemo sa udaljenim serverom, URLConnection možemo da koristimo za proveru svojstava udaljenih objekata pre nego što ih prenesemo na lokalni računar. Ta svojstva se nalaze u specifikaciji protokola HTTP, pa kao takvi, imaju smisla samo za URL objekte koji koriste protokol HTTP. Neke najznačajnije metode klase URLConnection su:

int getContentLength() – vraća dužinu sadržaja (u bajtovima) dodeljenog resursa. Ako je dužina nedostupna, vraća -1

long getDate() – vraća vreme i datum odgovora, kao broj milisekundi proteklih od 1. januara 1970. po Griniču

long getExpiration() – vraća vreme i datum koji predstavljaju rok trajanja sadržaja resursa, kao broj milisekundi proteklih od 1. januara 1970. po Griniču. Vraća null ako je rok trajanja resursa nedostupan.

78

Page 79: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

long getLastModified() – vraća vreme i datum poslednje izmene resursa, kao broj milisekundi proteklih od 1. januara 1970. po Griniču. Vraća null ako je datum poslednje izmene resursa nedostupan.

InputStream getInputStream() throws IOException – vraća objekat tipa InputStream povezan sa resursom. Pomoću tog toka dobijamo sadržaj resursa.

Datagrami

Rad sa protokolom TCP/IP zadovoljava većinu potreba naših programa za internet. On nudi serijalizovan, predvidiv i pouzdan tok paketa podataka, ali ima i mana. TCP sadrži mnoštvo komplikovanih algoritama za kontrolu zagušenja komplikovanih mreža, kao i rešenja za pesimistička očekivanja u vezi sa gubitkom paketa. To dovodi do prilično neefikasnog načina prenosa podataka. Datagrami nude drugačiji pristup.

Datagrami su grupe podataka koje se prosleđuju između računara. Kada se datagram pusti prema svom cilju, nije sigurno da će tamo i stići, bez obzira na to da li ga tamo neko očekuje. Slično tome, kada primimo datagram, uopšte ne možemo biti sigurni d aon na svom putu nije oštečen niti da je onaj ko ga je poslao i dalje tamo kako bi primio odgovor.

Datagrami se u Javi obrađuju preko protokola UDP, pomoću dve klase: DatagramPacket sadrži podatke, dok je DatagramSocket mehanizam koji se koristi za slanje i prijem objekata klase DatagramPacket.

Klasa DatagramPacket

Ova klasa korisi četiri konstruktora:

DatagramPacket(byte podaci[], int velicina) – određuje smeštaj za podatke i veličinu paketa, koristi se za prijem podataka pomoću objekta klase DatagramSocket

DatagramPacket(byte podaci[], int pomak, int velicina) – omogućuje da zadamo i pomak u skladištu do mesta na kome će podaci biti smešteni

DatagramPacket(byte podaci[], int velicina, InetAddress ipAdresa, int port) – određuje ciljnu adresu i port koje objekat klase DatagramSocket koristi da bi odredio gde da šalje podatke iz paketa

DatagramPacket(byte podaci[], int pomak, int velicina, InetAddress ipAdresa, int port) – prebacuje početak paketa na zadato mesto za skladištenje

Metode za određivanje internog stanja objekta klase DatagramPacket omogućavaju pristup odredišnoj adresi i broju porta pridruženih paketu, kao i podacima i njihovoj dužini. Neke od njih su:

79

Page 80: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

InetAddress getAddress() – vraća objekat tipa InetAddress koji se obično koristi prilikom slanja

int getPort() – vraća broj porta

byte[] getData() – vraća niz bajtova podataka koji se nalaze u datagramu. Uglavnom se koristi za učitavanja podataka iz datagrama posle prijema.

int getLength() – vraća dužinu važećih podataka koji se nalaze u nizu bajtova koji bi trebalo da se dobije metodom getData(). Ova dužina obično nije jednaka dužini celog niza bajtova.

80

Page 81: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Java Web aplikacije

Servleti

Tehnologija servleta je osnova za razvoj web aplikacija u Javi. U pitanju je jedna od najvažnijih Java tehnologija, koja je istovremeno osnova i za drugu popularnu tehnologiju, koja se koristi kod razvoja Web aplikacija, a to su JSP strane.

Kada se prvi put pojavio Internet se sastojao samo od statičkih HTML strana.

CGI (Common Gateway Interface) je prva omogućila krieranje dinamičkog sadržaja. CGI omogućava da web server pozove neki spoljašnji program i da mu prosledi HTTP request. Taj program dalje obrađuje podatke iz tog zahteva i svoj odgovor šalje nazad na web server, koji ga prosleđuje do klijenta. CGI programi su mogli da se pišu u bilo kom jeziku koji je web server mogao da podrži. Najviše se koristio Perl.

Tokom vremena su se razvile i druge tehnologije koje su mogle da omoguće kreiranje dinamičkog sadržaja. Danas se puno koristi PHP, ASP (Active Server Pages), ASP.NET i naravno tehnologije vezane za Javu.

Prednosti servleta u odnosu na CGI programe

Servleti, u odnosu na CGI programe, imaju prednost u pogledu performansi. Ovde nema krieranja posebnog procesa za svaki zahtev klijenta. Umesto toga, svim zahtevima rukuje proces kontejnera koji sadrži servlet. Nakon što servlet završi obradu određenog zahteva, on ostaje u memoriji i čeka na drugi zahtev.

Servleti takođe imaju prednost u pogledu prenosivosti, pošto se relativno lako mogu prebacivati na druge platforme, kao i svi programi koji su pisani u Javi.

Serlveti mogu da koriste unapred pripremljene biblioteke klasa iz Jave čime se ubrzava proces razvoja aplikacije.

Servletima upravlja JVM, tako da ne morate da brinete o zauzimaju i oslobađanju memorije.

Arhitektura aplikacije sa servletima

Servlet je Java klasa koja može da se dinamički učita u specijalni web server. Web server koji je svestan postojanja servleta se naziva servlet kontejner.

Servlet sa klijentom komunicira putem modela zahtev-odgovor (request-response), koji je zasnovan na HTTP protokolu. Pošto servleti rade preko HTTP-a, to znači da servlet kontejner mora da podržava HTTP protokol, da bi primio zahteve koji dolaze od klijenta i poslao odgovor servleta.

81

Page 82: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

slika 1.1 Arhitektura aplikacije sa servletima

Kod JSP aplikacija se servlet kontejner zamenjuje JSP kontejnerom. I servlet kontejner i JSP kontejner se zajedničkim imenom mogu nazvati web kontejnerom.

Pošto u okviru aplikacije sa servletima može da se nađe i statički sadržaj, to znači da servlet kontejner mora da bude u stanju da rukuje i takvim sadržajem. Obično je to moguće, ali ne i preporučljivo. Bolje je da se za slanje statičkog sadržaja koristi pravi Web server, kao što je Apache Web server, ili Microsoftov IIS. Praksa je da se web server postavi ispred i da on prima sve zahteve klijenta. Statičkim sadržajem se rukuje preko web servera, a dinamički sadržaj se šalje do servlet kontejnera.

slika 1.2 arhitektura aplikacije sa servletima, koja sadrži i HTTP server

HTTP protokol

Hypertext transfer protocol (HTTP) omogućava da web serveri i browseri razmenjuju podatke preko Interneta. Klijent traži određenu datoteku, a server odgovara na taj zahtev. HTTP koristi TCP vezu.

Kod HTTP-a je uvek klijent taj koji inicira transakciju. On to radi putem uspostavljanja veze i slanja HTTP zahteva (request). Server ne može da kontaktira klijenta ili da uspostavi neku povratnu vezu sa njim. Sa druge strane i klijent i server mogu da prekinu vezu koja je uspostavljena. Ako na primer, želite da iz browsera prekinete vezu, možete da kliknete dugme Stop, čime se u suštini prekida HTTP veza sa web serverom.

82

Page 83: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

HTTP zahtevi

HTTP transakcija počinje zahtevom koji dolazi iz browsera kijenta i završava odgovorom servera. HTTP zahtev se sastoji iz tri dela:

Metod-URI-Protokol/Verzija

Zaglavlje zahteva

Telo

Primer za HTTP zahtev može biti:

GET /servlet/default.jsp HTTP/1.1 Accespt: text/plain; text/html Accept-Language: en-gb Connection: Keep-Alive Host: localhost Referer: http://localhost/ch8/SendDetails.htm User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows98) Content-Length: 33 Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate LastName=Franks&FirstName=Miki

Deo metod-URI-verzija protokola se pojavljuje u prvoj liniji zahteva:

GET /servlet/default.jsp HTTP/1.1

Metod je GET, /servlet/default.jsp je URI, a poslednji deo je verzija protokola.

URI definiše resurs na Internetu. URI se obično interpretira relativno u odnosu na root direktorijum servera. To znači da uvek počinje kosom crtom /. URL je u suštini jedan tip URI-ja. Verzija protokola predstavlja verziju HTTP protokola koji se koristi.

Zaglavlje zahteva sadrži korisne informacije o okruženju klijenta i telu poruke. Tu bi na primer, mogao da se nađe jezik na koji je browser podešen, dužina tela poruke i sl. Svako zaglavlje je odvojeno od sledećeg novim redom.

Između zaglavlja i tela poruke se nalazi jedna prazna linija, koja je važna kod interpretacije HTTP zahteva. Ta linija govori HTTP serveru gde počinje telo poruke. U nekim knjigama se ova prazna linija pominje kao četvrta komponenta HTTP zahteva.

U prethodnom HTTP zahtevu se cela poruka sastoji samo od jedne linije:

83

Page 84: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

LastName=Franks&FirstName=Michael

Metodi HTTP zahteva

Svaki HTTP zahtev može da koristi jedan od nekoliko metoda. Ovi metodi su definisani standardom. U tabeli koja sledi su dati ovi metodi i njihov opis.

Tabela: Metodi u HTTP standardu

Metod Opis

GET Ovo je najjednostavniji metod koji se verovatno najviše koristi. Ovaj metod vraća podatke koji se nalaze u okviru URL-a.

HEAD Ovaj metod omogućava da se radi isto što i sa metodom GET, ali se vraća samo zaglavlje HTTP zahteva, bez tela poruke.

POST Ovaj metod se takođe puno koristi. Metod POST se obično koristi u okviru HTML formi. POST se koristi za transfer bloka podataka na server. Ovaj blok se nalazi u okviru tela poruke.

OPTIONS Ovaj metod se korsiti da se od servera dobiju informacije o mogućnostima koje on pruža.

PUT Ovaj metod se dopunjuje sa metodom GET. Celo telo poruke se čuva na lokaciji koja je zadata u okviru URI-ja.

DELETE Ovaj metod se koristi za brisanje dokumenta sa servera. Dokument koji treba da se obriše se naznačava u okviru URI sekcije zahteva.

TRACE Metod TRACE se koristi za praćenje putanje zahteva kroz firewal i višestruke proksi servere. On je koristan kod dibagovanja problema koji se javljaju u mrežnom okruženju.

Od svih pomenutih metoda u Internet aplikacijama se najviše koriste metodi GET i POST.

HTTP odgovori

HTTP odgovor se sastoji od tri dela.

Protokol - kod za status - Opis

84

Page 85: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

zaglavlja odgovora

telo

Evo primera za HTTP zaglavlje:

HTTP/1.1 200 OK Server: Microsoft-IIS/4.0 Date: Mon, 3 Jan 1998 13:13:33 GMT Content-Type: text/html Last-Modified: Mon, 11 Jan 1998 13:23:43 GMT Content-Length: 112 <HTML> <HEAD> <TITLE> HTTP Primer</TITLE></HEAD><BODY> Dobro dosli </BODY> </HTML>

Prva linija odgovora je slična sa prvom linijom zaglavlja zahteva. Tu se zadaju protokol, zatim se saopštava da je zahtev uspešno prihvaćen (200=uspeh) i kaže se da je sve prošlo kako treba.

Zaglavlje odgovora sadrži korisne informacije slične zaglavljima u zahtevu. Telo odgovora je HTML sadržaj samog odgovora. Zaglavlja i telo su odvojeni praznim redom.

Kako radi servlet

Servlet kontejner učitava server prvi put kada se taj servlet zatraži. Nakon toga taj servlet prihvata zahtev koji je stigao od korisnika, obrađuje taj zahtev i šalje odgovor do kontejnera, koji ga šalje nazad do korisnika. Nakon toga servlet ostaje u memoriji i čeka sledeće zahteve. On se neće izbaciti iz memorije, osim ako kontejner ne zaključi da ima premalo memorije. Svaki put kada se zahteva da servlet nešto uradi, kontejner proverava da li su taj učitani servlet i class fajl koji se nalazi na disku istovetni. Ako je class fajl nastao posle učitavanja, onda se servlet ponovo učitava, jer to znači da je stigla novija verzija servleta (ovo bi trebalo da bude ovako, ali nije kod svih kontejnera).

Na slici koja sledi je pokazano kako radi servlet:

85

Page 86: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

slika: Način rada servleta

Tomcat kao servlet kontejner

Postoje različiti kontejneri servleta. Najpopularniji od njih je Tomcat. U pitanju je besplatan kontejner, koji se razvija na principima open source softera. Tomcat je deo projekta Jakarta, koji se razvija u okviru Apache softvera. Trenutno je aktuelna verzija Tomcata 6.0.

Tomcat je i servlet i JSP kontejner, ali je istovremeno i Web server. To znači da on može da služi za rad servleta i JSP strana, ali i za rad običnih HTML strana. Ipak se u praksi ne koristi kao Web server, već se spreže sa Apache serverom, koji je u pogledu opsluživanja statičkih web strana mnogo brži i bolji.

Šest koraka u izvršavanju prvog servleta

Nakon što je Tomcat instaliran i konfigurisan, vreme je da se počne sa radom. Prilikom pisanja i izvršavanja servleta, ceo posao se može podeliti u šest koraka:

1. Kreira se struktura direktorijuma ispod Tomcata. Ova struktura treba da odgovara Vašoj aplikaciji.

2. Piše se izvorni kod za servlet.

86

Page 87: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

3. Kompajlira se izvorni kod.

4. Kreira se deployment deskriptor.

5. Pokreće se Tomcat

6. Iz Web browsera se poziva servlet

Kreiranje strukture direktorijuma ispod Tomcata

U tekstu koji sledi će se direktorijum na kojem je Tomcat instaliran označavati sa %CATALINA_HOME%.

Prilikom instalacije Tomcata se ispod osnovnog direktorijuma (%CATALINA_HOME%) automatski kreira nekoliko direktorijuma. Jedan od poddirektorijuma je webapps. To je mesto gde će se nalaziti vaše web aplikacije. Web aplikacija je kolekcija servleta i drugog sadržaja koji postoji u okviru određenog domena servera (URL domena). Svaka aplikacija ima poseban direktorijum. To znači da prva stvar koju treba uraditi jeste kreiranje direktorijuma za web aplikaciju. Evo kako izgleda kreiranje direktorijuma za aplikaciju koja se zove myApp.

1. Kreira se direktorijum po imenu myApp, koji se nalazi ispod direktorijuma webapps. Ime direktorijuma je bitno, jer se i ono može pojaviti u URL adresi preko koje se pristupa servletu.

2. Ispod direktorijuma myApp se kreira direktorijum WEB-INF. Ispod ovog direktorijuma se pravi direktorijum po imenu classes. U direktorijum classes ispod direktorijuma WEB-INF se smeštaju class fajlovi za Java klase. Ako imate HTML datoteke, njih stavljate direktno ispod direktorijuma myApp. Možete i tu da imate neku dodatnu strukturu.

87

Page 88: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

slika: Struktura direktorijuma za Web aplikaciju u Tomcatu

Pisanje izvornog koda za servlet

Listing koji sledi prikazuje servlet po imenu TestingServlet. Ime datoteke je naravno, TestingServlet.java. Servlet do pretraživača šalje izvestan HTML tekst.

TestingServlet.java

import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class TestingServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>Servlet Testing</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); out.println("Welcome to the Servlet Testing Center"); out.println("</BODY>"); out.println("</HTML>"); }

88

Page 89: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

}

Ova datoteka može da se zapamti bilo gde na disku. Ako se koristi Jbuilder, onda se može staviti tamo gde se stavljaju datoteke projekta.

Kompilacija izvornog koda

Da bi mogla da se izvrši kompilacija, kompajleru mora biti dostupna datoteka servlet.jar. Ona se može ubaciti u projekat u Jbuilderu. Datoteka servlet.jar se kod instalacije Tomcata nalazi u direktorijumu %CATALINA_HOME%/common/lib.

Datoteka TestingServlet.class mora da se nalazi u direktorijumu WEB-INF/classes. Ako se servlet nalazi u nekom paketu, onda mora da se napravi odgovarajuća struktura direktorijuma, ispod direktorijuma classes.

Kreiranje deployment descriptora

Deployment descriptor je opcionalna komponenta servlet aplikacije. Ova datoteka bi ipak trebalo da postoji kod svake aplikacije. U pitanju je XML datoteka, koja se zove web.xml i koja mora da se nalazi na direktorijumu WEB-INF za tu aplikaciju. U ovoj datoteci mogu da se zadaju opcije za konfigurisanje te aplikacije.

Evo kako izgleda datoteka web.xml koja se nalazi u direktorijumu myApp/WEB-INF.

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"> <web-app> <servlet> <servlet-name>TestingServlet</servlet-name> <servlet-class>TestingServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>TestingServlet</servlet-name> <url-pattern>/servlet/TestingServlet</url-pattern> </servlet-mapping> </web-app>

Svi servleti u ovoj datoteci treba da se pišu u okviru elementa web-app. Za svaki servlet treba da postoji element <servlet>. U tom elementu treba da postoje elementi <servlet-name> i <servlet-class>. <servlet-name> je ime servleta, onako kako ga Tomcat vidi. <servlet-class> je kompajlirana datoteka za taj servlet, ali bez ekstenzije .class.

Sada možete da pokrenete Tomcat.

89

Page 90: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Poziv servleta iz Web browsera

Sada možete da iz Web browsera pozovete svoj servlet. Po default-u Tomcat radi na portu 8080. U njemu bi trebalo da postoji web aplikacija po imenu myApp. Servlet koji ste upravo napisali se zove Testing. URL adresa preko koje možete da ga pozovete je:

http://ime-domena/virtualni-direktorijum/servlet/servlet-name

Statičkoj datoteci (HTML) možete da pristupite preko adrese:

http://ime-domena/virtualni-direktorijum/statickaDatoteka.html.

Konkretno za naš servlet URL kojim se on poziva je:

http://localhost:8080/myApp/servlet/TestingServlet

U deployment descriptoru koji ste napisali ste vezali servlet TestingServlet sa imenom testing, tako da servlet možete da pozovete i preko imena Testing i preko imena cele klase TestingServlet. Da niste napisali web.xml koju smo dali u prethodnom tekstu, za poziv servleta biste morali da koristite sledeću URL adresu:

http://localhost:8080/myApp/servlet/TestingServlet

Životni ciklus servleta

Životni ciklus servleta je određen sa tri metoda. To su metodi init, service i destroy.

Metod init()

Servlet kontejner poziva metod init() nakon što se napravi instanca klase servleta. Servlet kontejner poziva ovaj metod samo jednom, da bi naznačio da je servlet stavljen u pogon. Pre nego što servlet bude u stanju da prima zahteve od strane klijenta, mora da se uspešno završi izvršenje metoda init.

Ako želite možete da preklopite ovaj metod i da u njemu napišete kod za inicijalizaciju, koji treba da se izvrši samo jednom, kao što je na primer, učitavanje drajvera za vezu sa bazom podataka, inicijalizacija određenih vrednosti i sl. U ostalim slučajevima ovaj metod može da ostane prazan.

Signatura za ovaj metod je:

public void init() throws ServletException

Metod može da proizvede i prosledi izuzetak tipa ServletException.

90

Page 91: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Metod service()

Nakon što se izvršio metod init() za određeni servlet poziva se metod service(). Ovaj metod omogućava servletu da odgovori na zahtev koji dolazi od klijenta.

Servlet kontejner prosleđuje objekte ServletRequest i ServletResponse. Ovaj prvi sadrži zahtev koji dolazi od klijenta, a drugi sadrži odgovor servleta. Ovo su dva najvažnija objekta jer omoguavaju da napišete svoj kod koji određuje kako servlet odgovara na zahtev korisnika.

Metod destroy()

Metod destroy() se poziva nakon što instanca servleta prestane da pruža usluge. Ovo se dešava kada se ugasi servlet kontejner, ili kada je tom kontejneru potrebo još memorije.

Ovaj metod se poziva nakon što se sve niti koje postoje u okviru metoda service za taj servlet završe, ili nakon što je prošao određeni period mirovanja.

U metodu destroy možete da napišete kod koji oslobađa resurse koji su zauzeti (na primer, memorija, niti i sl). Ako Vam ništa od toga nije potrebno, ne morate ni da pišete kod za metod.

ServletContext

Kod rada sa servletima servlet context predstavlja okruženje u kome servlet radi. Servlet kontejner kreira objekat ServletContext, koji možete da upotrebite za pristup do okruženja servleta. U kontekst možete da stavite i atribut, zajedno sa imenom preko kojeg se tom atributu pristupa. Na taj način svi objekti koji učestvuju u aplikaciji mogu da dele neke zajedničke elemente. Možete da u jednom servletu u ServletContext stavite atribut, i da ga kasnije u nekom drugom servletu pročitate i promenite. Atributi mogu da nose informacije, na primer, o stringu za vezu sa bazom podataka ili nešto slično.

U primeru koji sledi su prikazana dva servleta. Jedan servlet, AtributSetServlet zadaje vrednost atributa i smešta je u ServletContext, a drugi servlet, DisplayAtributServlet, prikazuje vrednost tog atributa. Radi se o atributu password, čija je vrednost proba.

import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class DisplayAtributServlet extends HttpServlet { //Initialize global variables public void init() throws ServletException { }

91

Page 92: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { ServletContext context = this.getServletConfig().getServletContext(); String pr = (String) context.getAttribute("password"); System.out.println(pr); } //Clean up resources public void destroy() { } } Datoteka AtributSetServlet.java

import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class AtributSetServlet extends HttpServlet { public void init() throws ServletException { } public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { ServletContext context =this.getServletConfig().getServletContext(); context.setAttribute("password","proba"); } //Clean up resources public void destroy() { } }

Objekat ServletContext ima metode setAttribute() i getAttribute(), koje služe za smeštanje i stavljanje atributa u kontekst aplikacije. Kada se atribut smešta, pored samog objekta koji je atribut, mora da se zada i string, koji predstavlja ključ za kasnije vađenje tog atributa-objekta.

context.setAttribute("password","proba");

U prethodnom iskazu ključ je string “password”, a objekat je drugi string “proba”.

Ovo se iz konteksta vadi preko metoda getAttribute() na sledeći način:

String pr = (String) context.getAttribute("password");

Kao što vidite, pošto se u kontekst aplikacije može da smesti bilo koji objekat, prilikom njegovog vađenja je potrebno izvršiti eksplicitnu kovenrziju (String), u ovom slučaju u string.

Objekat ServletConfig ima i metod removeAttribute(), koji briše objekat iz konteksta aplikacije. Ovaj metod prihvata argument koji predstavlja ime atributa koji treba da se izbaci.

92

Page 93: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

context.removeAttribute(“password”);

Interfejsi Request i Response

Zahtevi i odgovori koji dolaze od klijenta su ono sa čime barata Web aplikacija. Kod aplikacije koja koristi servlete, browser šalje zahtev do servlet kontejnera, a ovaj taj zahtev prosleđuje do servleta.

Kod rada sa servletima zahtev korisnika je predstavljen objektom ServletRequest, ili još bolje objektom HttpServletRequest, a odgovor servleta objektom ServletRequest, odnosno HttpServletRequest.

HttpServletRequest je interfejs koji je izveden iz interfejsa ServletRequest i nalazi se u paketu javax.servlet.http. Ovo je interfejs koji ima sve metode koje ima i ServletRequest, ali i dodatne metode koji olakšavaju rad.

HttpServletResponse je interfejs koji je izveden iz interfejsa ServletResponse i nalazi se takođe u paketu java.servlet.http.

Interfejs HttpServletRequest

U ovom interfejsu se nalaze inforrmacije o zahtevu korisnika, odnosno tu su vrednosti parametara koji dolaze u okviru zahteva, atributi i ulazni tok iz kojeg dolaze informacije.

Najvažniji metodi ovog interfejsa su oni koji omogućavaju da iz zahteva koji dolazi od korisnika izvadite vrednosti i imena parametara. Tu su i metodi tipa getRemoteHost i getRemoteAddress, koji omogućavaju da dobijete identitet računara korisnika. Metod getRemoteAddress() vraća string koji predstavlja IP adresu koju klijent korisi, a drugi metode vraća string koji predstavlja kvalifikovano ime hosta za taj računar.

U primeru koji sledi je prikazan objekat HttpServletRequest u akciji. U primeru postoji HTML forma, koja se nalazi u datoteci po imenu index.html. Ovu datoteku treba da postavite u direktorijum aplikacije, odnosno na direktorijum myApp. Tu je i servlet RequestDemoServlet.

Datoteka index.html

<HTML> <HEAD> <TITLE>Sending a request</TITLE> </HEAD> <BODY> <FORM ACTION=servlet/RequestDemoServlet METHOD="POST"> <BR><BR> Autor: <INPUT TYPE="TEXT" NAME="Autor"> <INPUT TYPE="SUBMIT" NAME="Posalji"> <INPUT TYPE="RESET" VALUE="Reset">

93

Page 94: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

</FORM> </BODY> </HTML>

Datoteka RequestDemoServlet.java

import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class RequestDemoServlet extends HttpServlet { //Initialize global variables public void init() throws ServletException { } //Clean up resources public void destroy() { } public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { System.out.println("Server Port: " + request.getServerPort()); System.out.println("Server Name: " + request.getServerName()); System.out.println("Protocol: " + request.getProtocol()); System.out.println("Character Encoding: " + request.getCharacterEncoding()); System.out.println("Content Type: " + request.getContentType()); System.out.println("Content Length: " + request.getContentLength()); System.out.println("Remote Address: " + request.getRemoteAddr()); System.out.println("Remote Host: " + request.getRemoteHost()); System.out.println("Scheme: " + request.getScheme()); Enumeration parameters = request.getParameterNames(); while (parameters.hasMoreElements()) { String parameterName = (String) parameters.nextElement(); System.out.println("Parameter Name: " + parameterName); System.out.println("Parameter Value: " + request.getParameter(parameterName)); } Enumeration attributes = request.getAttributeNames(); while (attributes.hasMoreElements()) { String attribute = (String) attributes.nextElement(); System.out.println("Ime atributa: " + attribute); System.out.println("Vrednst atributa: " + request.getAttribute(attribute)); } } }

94

Page 95: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Primer ćete pokrenuti, ako u u browseru unesete sledeći URL:

http://localhost:8080/myApp/index.html

Interfejs HttpServletResponse

U ovom odeljku su pomenuti samo metodi ovog interfejsa koji su nasleđeni iz interfejsa ServletResponse. Metodi koji su specifični za interfejs HTTPServletResponse će biti objašnjeni naknadno.

Ovaj interfejs predstavlja odgovor koji se šalje nazad korisniku. Najvažniji metod ovog interfejsa je getWriter, pomoću kojeg možete da dobijete objekat java.io.PrintWriter, koji koristite za pisanje HTML oznaka i drugog teksta, koji se šalje korisniku.

U primeru koji sledi su date HTML datoteka po imenu index2.html, kao i servlet ResponseDemoServlet, koji kod umesto na konzolu šalje do korisnika.

Kod je vrlo sličan sa prethodnim primerom.

Razlika je u atributu Action u datoteci index2.html i u tome da se izlaz iz servleta ne šalje na stadnardni izlaz, već u objekat out, koji je tipa PrintWriter, i koji predstavlja tok koji se šalje do pretraživača.

Datoteka index2.html

<HTML> <HEAD> <TITLE>Slanje zahteva</TITLE> </HEAD> <BODY> <FORM ACTION=servlet/ResponseDemoServlet METHOD="POST"> <BR><BR> Autor: <INPUT TYPE="TEXT" NAME="Author"> <INPUT TYPE="SUBMIT" NAME="Posalji"> <INPUT TYPE="RESET" VALUE="Reset"> </FORM> </BODY> </HTML>

Datoteka ResponseDemoServlet.java

import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class ResponseDemoServlet extends HttpServlet {

95

Page 96: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

private static final String CONTENT_TYPE = "text/html; charset=windows-1250"; //Initialize global variables public void init() throws ServletException { } //Clean up resources public void destroy() { } public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>"); out.println("ServletResponse"); out.println("</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); out.println("<B>Demonstrating the ServletResponse object</B>"); out.println("<BR>"); out.println("<BR>Server Port: " + request.getServerPort()); out.println("<BR>Server Name: " + request.getServerName()); out.println("<BR>Protocol: " + request.getProtocol()); out.println("<BR>Character Encoding: " + request.getCharacterEncoding()); out.println("<BR>Content Type: " + request.getContentType()); out.println("<BR>Content Length: " + request.getContentLength()); out.println("<BR>Remote Address: " + request.getRemoteAddr()); out.println("<BR>Remote Host: " + request.getRemoteHost()); out.println("<BR>Scheme: " + request.getScheme()); Enumeration parameters = request.getParameterNames(); while (parameters.hasMoreElements()) { String parameterName = (String) parameters.nextElement(); out.println("<br>Parameter Name: " + parameterName); out.println("<br>Parameter Value: " + request.getParameter(parameterName)); } Enumeration attributes = request.getAttributeNames(); while (attributes.hasMoreElements()) { String attribute = (String) attributes.nextElement(); out.println("<BR>Attribute name: " + attribute); out.println("<BR>Attribute value: " + request.getAttribute(attribute)); } out.println("</BODY>"); out.println("</HTML>"); }

96

Page 97: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

}

Klasa HttpServlet

Svi servleti koje smo do sada koristili su se izvodili iz klase HttpServlet. Ova klasa predstavlja servlet i ima puno metoda koji se mogu koristiti prilikom rada sa servletima. Klasa se nalazi u paketu javax.servlet.http.

Servleti koje smo do sada pisali su imali svoju verziju metoda service, u kojoj smo pisali kod koji je trebao da se izvrši. Tu smo i dodavali izlaz koji se šalje nazad do browsera.

Prilikom rada sa servletima se relativno retko radi direktno sa metodom service. Umesto toga se koristi jedan od metoda doXXX, koji postoje u ovoj klasi i koji su vezani za metode putem kojih je poslat HTTP zahtev. To su metodi doPost, doPut, doGet, doDelete, doOptions i doTrace. Najćešće se implementiraju i koriste metodu doGet i doPost.

Metod doGet se poziva kada je servlet primio HTTP zahtev koji je poslat preko metoda GET.

Metoda doPost se poziva kada je do servleta stigao HTTP zahtev preko metoda POST.

Kada se šalju metodi POST i GET? Pogledajmo sledeću HTML formu:

<FORM Action=”Register” METHOD=”POST”> <INPUT TYPE=TEXT Name=”ime”> <INPUT TYPE=TEXT Name=”prezime”> <INPUT TYPE=SUBMIT> </FORM>

Kada korisnik klikne dugme Submit na ovoj formi, browser do servera šalje HTTP zahtev i to preko metoda POST. Web server taj zahtev prosleđuje do servleta Register. U tom servletu se poziva metod doPost. U tom metodu može da se pristupi parametrima ime i prezime i to u obliku parova:

ime=pera

prezime=peric.

Ovo važi ako je korisnik na formi uneo vrednosti pera i peric u odgovarajućim poljima.

HTML forma može da koristi i metod GET, ali se POST koristi mnogo češće.

Metod doGet se poziva kada se HTTP zahtev pošalje preko metoda GET. U HTTP-u je podrazumevani metod GET. Kada unesete URL adresu, kao što je na primer www.yahoo.com, zahtev se šalje na sajt Yahoo! preko metoda GET. Ako metod GET koristite u okviru forme, onda se parametri, u obliku ime/vrednost, dodaju URL-u. Ako imate dva parametra po imenu ime i prezime, koji se nalaze u okviru forme i ako korisnik unese pera, za prvi, peric za drugi, onda URL ima sledeći oblik:

97

Page 98: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

http://domen/myApp/Register?ime=pera&prezime=peric

Nakon što primi ovakav zahtev servlet poziva metod doGet.

Ako se pitate kako servlet zna koji je metod bio u pitanju, odgovor je u metodu service, koji klasa HttpServlet nasleđuje iz klase Servlet. U ovom metodu postoje mogućnost da se proveri tip zahteva koji dolazi od klijenta, pa se u skladu sa tim poziva odgovarajući metod.

U primeru koji sledi je pokazano kako se koriste metodi doGet i doPost.

import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class RegisterServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>The GET method</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); out.println("The servlet has received a GET. " + "Now, click the button below."); out.println("<BR>"); out.println("<FORM METHOD=POST>"); out.println("<INPUT TYPE=SUBMIT VALUE=Submit>"); out.println("</FORM>"); out.println("</BODY>"); out.println("</HTML>"); } public void doPost( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>The POST method</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); out.println("The servlet has received a POST. Thank you."); out.println("</BODY>");

98

Page 99: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

out.println("</HTML>"); } }

Kada se servlet pozove iz web browsera (http://localhost:8080/myApp/servlet/RegisterServlet) kao HTTP metod se koristi metod GET. Na strani servera se poziva metod doGet. Servlet šalje string “Servlet has received a Get. Now click the button below”. Pored ovog šalje se i HTML forma.

Kada kliknete dugme Submit, browser šalje formu na server, ovog puta preko metoda POST (tako je zadato atributom ACTION za tu formu). Na strani servera se sada poziva metod doPost, koji kao odgovor prikazuje izlaz “The servlet has received a POST. Thank you,”.

Iz objekta HttpServletRequest, koji se prosleđuje kao ulazni argument i metodi doGet i metodi doPost mogu se pro~itati vrednosti parametara koji su poslati u okviru zahteva koji je stigao.

U primeru koji sledi je pokazano kako se u metodu doGet mogu da pročitaju imena parametara koji su stigli i njihove vrednosti. U praksi se često ne moraju da čitaju imena parametara, jer su ona obično poznata programeru unapred.

import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class HttpRequestDemoServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>Obtaining the Parameter</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); out.println("The request's parameters are:<BR>"); Enumeration enumeration = request.getParameterNames(); while (enumeration.hasMoreElements()){ String parameterName = (String) enumeration.nextElement(); out.println(parameterName + ": " + request.getParameter(parameterName) + "<BR>" ); } out.println("<FORM METHOD=GET>");

99

Page 100: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

out.println("<BR>First Name: <INPUT TYPE=TEXT NAME=FirstName>"); out.println("<BR>Last Name: <INPUT TYPE=TEXT NAME=LastName>"); out.println("<BR><INPUT TYPE=SUBMIT VALUE=Submit>"); out.println("</FORM>"); out.println("</BODY>"); out.println("</HTML>"); } }

Kada se servlet pozove po prvi put, u formi nema nijednog parametra, koji bi došao iz zaheva. Zbog toga se ne prikazuju parovi ime parametra/vrednost.

Kada se na strani koja se dobija kao izlaz iz servleta u polja First Name i Last Name unesu vrednosti, na server se šalju parametri FirstName i LastName. Vrednosti ovih parametara se prikazuju na narednoj strani.

Manipulisanje parametrima koji mogu imati više vrednosti

Često se dešava da na formi koristite parametre koji mogu da imaju nekoliko vrednosti. To se na primer, dešava kada imate kontrole tipa check box, koje mogu da prihvate više vrednosti, ili kada imate listu tipa select, kod koje možete da izaberete više vrednosti. U takvim situacijama metod getParameter ne zadovoljava, pošto biste dobili samo prvu vrednost. Umesto ovog metoda se tada koristi metod getParameterValues.

Ovaj metod prihvata jedan argument: to je ime parametra. Vraća se niz stringova sa svim vrednostima za taj parametar. Ako parametar sa tim imenom ne postoji, onda se vraća null.

U primeru koji sledi se ilustruje poziv ovog metoda. Korisnik treba da izabere tipove muzike koju voli. Može da izabere više vrednosti. Sve te vrednosti se uzimaju u servletu.

import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class VisetrukiParametri extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>Obtaining Multi-Value Parameters</TITLE>"); out.println("</HEAD>"); out.println("<BODY>");

100

Page 101: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

out.println("<BR>"); out.println("<BR>Select your favorite music:"); out.println("<BR><FORM METHOD=POST>"); out.println("<BR><INPUT TYPE=CHECKBOX " + "NAME=favoriteMusic VALUE=Rock>Rock"); out.println("<BR><INPUT TYPE=CHECKBOX " + "NAME=favoriteMusic VALUE=Jazz>Jazz"); out.println("<BR><INPUT TYPE=CHECKBOX " + "NAME=favoriteMusic VALUE=Classical>Classical"); out.println("<BR><INPUT TYPE=CHECKBOX " + "NAME=favoriteMusic VALUE=Country>Country"); out.println("<BR><INPUT TYPE=SUBMIT VALUE=Submit>"); out.println("</FORM>"); out.println("</BODY>"); out.println("</HTML>"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String[] values = request.getParameterValues("favoriteMusic"); response.setContentType("text/html"); PrintWriter out = response.getWriter(); if (values != null ) { int length = values.length; out.println("You have selected: "); for (int i=0; i<length; i++) { out.println("<BR>" + values[i]); } } } }

Kada se servlet pozove prvi put poziva se metod doGet i metod do browsera šalje HTML formu. Na formi postoje četiri kontrole tipa check box sa istim imenom: favoriteMusic. Vrednosti su međutim različite.

Kada korisnik potvrdi neka od ovih polja za potvrdu, browser sve izabrane vrednosti šalje do servera. Na strani servera se za dobijanje vrednosti koristi metod getParameterValues.

Obratite pažnju na to da smo za formu koristili metod POST, odnosno da su parametri pročitani u metodi doPost.

101

Page 102: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

Slanje odgovora klijentu

Već smo pomenuli interfejs HttpServletResponse i neke njegove metode. U primerima koje smo do sada radili smo uglavnom koristili dva metoda koji dolaze iz ovog interfejsa. To su metodi setContentType i getWriter.

response.setContentType("text/html"); PrintWriter out = response.getWriter();

Jedan od interesantnih metoda ovog objekta, koji se često koristi je metod sendRedirect. Ovaj metod se koristi da korisnika usmeri na neku drugu stranu. Kada pozovete ovaj metod, web server šalje pretraživaču specijalnu poruku, u kojoj mu nalaže da pozove (zahteva) drugu stranu. To znači da uvek postoji putovanje do klijenta, pre nego što se dobije strana koja se traži. U primeru koji sledi je ilustrovana upotreba ovog metoda.

Data je strana za prijavljivanje korisnika, na kojoj korisnik treba da unese svoje korisničko ime i lozinku. Nakon što se to pošalje na server, korisniku se prikazuje strana sa dobrodošlicom, ili se ponovo vraća na stranu za prijavljivanje, u zavisnosti od toga da li je prijavljivanje uspelo ili nije.

import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class LoginServlet extends HttpServlet { private void sendLoginForm(HttpServletResponse response, boolean withErrorMessage) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>Prijavljivanje</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); if (withErrorMessage) out.println("Prijvaljivanje nije uspelo. Probajte ponovo.<BR>"); out.println("<BR>"); out.println("<BR>Unesite korisnicko ime i lozinku."); out.println("<BR><FORM METHOD=POST>"); out.println("<BR>Korisnicko ime: <INPUT TYPE=TEXT NAME=userName>"); out.println("<BR>Lozinka: <INPUT TYPE=PASSWORD NAME=password>"); out.println("<BR><INPUT TYPE=SUBMIT VALUE=Submit>"); out.println("</FORM>");

102

Page 103: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

out.println("</BODY>"); out.println("</HTML>"); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { sendLoginForm(response, false); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String userName = request.getParameter("userName"); String password = request.getParameter("password"); if (userName!=null && password!=null && userName.equals("jamesb") && password.equals("007")) { response.sendRedirect("http://localhost:8080/myApp/DobroDosli.html"); } else { sendLoginForm(response, true); } } }

Kada se ovaj servlet pozove prvi put (http://localhost:8080/myApp/servlet/LoginServlet) poziva se njegov metod doGet. Ovaj metod šalje nazad u browser formu za prijavljivanje. Na toj formi korisnik treba da unese ime i lozinku. Kada se ta forma po{alje na server (preko metoda POST), poziva se metod doPost u servletu, koji proverava lozinku i korisničko ime i poredi ih sa nekim unapred definisanim vrednostima. Ako ime i lozinka odgovaraju korisnik se preusmerava na stranu za dobrodošlicu, a ako ne odgovaraju ponovo mu se šalje strana za prijavljivanje.

Kod metoda sendRedirect() se ne mora zadavati kompletna putanja do nove stranice, ako se radi o istoj aplikaciji. To znači da smo u prethodnom primeru umesto

response.sendRedirect("http://localhost:8080/myApp/DobroDosli.html");

mogli da napišemo i

response.sendRedirect("/myApp/DobroDosli.html");

pa čak i

response.sendRedirect("../DobroDosli.html");

Metod sendRedirect se obično ne koristi za preusmeravanje u okviru iste aplikacije, zato što postoji efikasniji metod, koji radi istu stvar.

103

Page 104: Java -   · PDF filejava.net paket, klijentski i serverski programi) Programiranje baza podataka (osnove programiranje baza podataka, konekcija sa bazama podataka pomo

104

U kodu primera koji smo dali se poziva privatni metod sendLoginForm. Kao što vidite ovaj metod prima dva argumenta. Drugi argument ukazuje na to da li treba da se štampa poruka o grešci ili ne. Ako se metod pozove iz metoda doGet, drugi argument ima vrednost false, pa se poruka o grešci ne štampa. Ako se međutim ovaj metod pozove iz metoda doPost, to znači da je došlo do greške (da ne postoji taj korisnik) i da treba poslati poruku o tome.