n aceasta lucrare se va proiecta o aplicatie complexa Web care va contine un applet, un servlet, mai multe pagini JSP si mai multe componente JavaBeans, folosind serverul Tomcat si un server de baze de date. Aplicatia va permite obtinerea online a unor informatii de calatorie din baza de date: lista zborurilor, lista firmelor de nchiriat masini, lista hotelurilor n care se pot rezerva camere, etc. La accesarea primei pagini a aplicatiei se va obtine o imagine asemanatoare celei din figura de mai jos:
Pagina initiala a aplicatiei (TravelPlan.html) contine referinta applet-ului care afiseaza data si ora curenta (DigitalClock) si un formular (form) n care se pot introduce diferite date (de exemplu, orasul de plecare si de destinatie a calatoriei), precum si 3 butoane de tip SUBMIT, la actionarea carora se adreseaza resursa din serverul Web, care va raspunde cererii clientului. Resursa adresata este un servlet (definit n clasa Travel.class), care dispecerizeaza cererile n functie de parametrii primiti (butoanul din formular care a fost actionat), si pentru fiecare buton se nainteaza cererea catre pagina JSP corespunzatoare: pagina Flights.jsp, pentru butonul Lista Zboruri, pagina Cars.jsp pentru butonul Inchiriere masini, pagina Hotels.jsp pentru butonul Rezervare hoteluri. n fiecare din paginile JSP adresate se acceseaza baza de date a aplicatiei (travel) folosind interfata JDBC, se extrag informatiile selectate si se transmit clientului. Pentru accesarea bazei de date se folosesc componente JavaBeans, care pot fi accesate din paginile JSP. Pentru construirea aplicatiei se efectueaza mai multi pasi, care vor fi descrisi n continuare.
(1) Crearea bazei de date si a sursei JDBC. Baza de date se poate crea pentru orice sistem de gestiune a bazelor de date pentru care dispunem de un driver JDBC sau de un driver ODBC, plus driverul JdbcOdbc. n acest exemplu se va folosi sistemul Microsoft Access, cu ajutorul caruia se creeaza baza de date travel.mdb, n care se definesc mai multe tabele, dintre care, pentru nceput, se defineste o forma simpla a tabelului flights, n care se memoreaza cteva zboruri, asa cum se vede n figura alaturata. Sursa de date JDBC se defineste prin intermediul unei surse de date ODBC. Pentru aceasta se foloseste comanda Data Source (ODBC), si se seteaza sursa de date de tip System DSN, pentru driverul Microsoft Access Driver (.mdb), cu numele Travel, asociata cu baza de date travel.mdb.
48 (2) Pregatirea directorului aplicatiei Travel. Aplicatia Web se va dezvolta ntr-un director separat (numit travel), care trebuie sa fie un subdirector al directorului webapps din instalarea serverului Tomcat (asa cum se vede n figura alaturata). n directorul travel se memoreaza pagina de start a aplicatiei (TravelPlan.html), paginile JSP si baza de date travel.mdb. De asemenea se creeaza un subdirector pentru applet (clock) si un subdirector WEB-INF. n directorul WEB-INF se memoreaza fisierul web.xml si se creeaza subdirectoarele classes si lib. Fisierul web.xml se poate copia dintr-unul din celelalte directoare de aplicatii (de exemplu, din directorul servlets-examples) si n el se adauga informatiile despre servlet-ul care va fi definit: <servlet> <servlet-name>Travel</servlet-name> <servlet-class>Travel</servlet-class> </servlet> <servlet-mapping> <servlet-name>Travel</servlet-name> <url-pattern>/Travel</url-pattern> </servlet-mapping> Restul datelor din fisierul web.xml pot fi lasate nemodificate, desi multe dintre ele nu sunt necesare. n subdirectorul lib al directorului WEB-INF se vor copia arhivele jstl.jar si stabdard.jar din subdirectorul corespunzator din directorul jsp-examples. Aceste biblioteci permit utilizarea bibliotecii de tag- uri n paginile JSP. n directorul ..\travel\WEB-INF\classes se copiaza subdirectoarele compressionFilters, filters, util si listeners din directorul ..\jsp-examples\WEB-INF\classes; n aceste directoare se gasesc mai multe clase necesare functionarii aplicatiei. n directorul ..\travel\WEB-INF\classes se vor mai memora: fisierele sursa si compilate ale servletului (Travel.java, Travel.class) si fisierele sursa ale bean-urilor (Flight.java, FlightDB.java, Car.java, CarDB.java, Hotel.java, HotelDB.java). Clasele bean-urilor sunt grupate n package-ul database, iar la compilare clasele beanurilor (Flight.class, FlightDB.class, etc.) vor fi depuse n directorul ..\classes\database.
(3) Crearea paginii HTML de start si a applet-ului. Pagina TravelPlan.html va avea, pentru nceput urmatorul continut: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> <TITLE>Plan de calatorie online</TITLE> </HEAD> <BODY> <BR> <CENTER> <H1>Plan de calatorie online</H1> <APPLET CODE = "clock/DigitalClock.class" codebase="/travel" align="center" bgcolor = "FFFF00" height = 25 width = 200> </APPLET> <P> <FORM ACTION="/travel/Travel" METHOD="POST"> Origine: <INPUT TYPE="TEXT" NAME="origin"><BR> Destinatie: <INPUT TYPE="TEXT" NAME="destination"><BR> <P> <TABLE CELLSPACING=1> <TR> <TH> <INPUT TYPE="SUBMIT" NAME="flights" VALUE="Lista zboruri"> <TH> <INPUT TYPE="SUBMIT" NAME="cars" VALUE="Inchiriere masini"> <TH> <INPUT TYPE="SUBMIT" NAME="hotels" VALUE="Rezervare hoteluri"> </TABLE> </CENTER> </FORM> </BODY> </HTML> 49
n aceasta pagina se poate remarca atributul ACTION al formularului: <FORM ACTION="/travel/Travel" METHOD="POST"> care adreseaza servlet-ul Travel, care este mapat cu clasa Travel.class n fisierul web.xml din directorul travel. Applet-ul este definit n fisierul DigitalClock.java si acesta se memoreaza n subdirectorul ..\travel\clock, unde se poate si compila, pentru a obtine clasa DigitalClock.class, definita n package-ul clock.
//Fisier DigitalClock.java package clock; import java.util.*; import java.awt.*; import java.applet.*; import java.text.*; public class DigitalClock extends Applet implements Runnable { Thread timer; // The thread that displays clock DateFormat formatter; // Formats the date displayed String lastdate; // String to hold date displayed Date currentDate; // Used to get date to display Color numberColor; // Color of numbers Font clockFaceFont; Locale locale; String language; String country; public void init() {numberColor = Color.black; try {language = getParameter("language"); } catch (Exception E) { } try {country = getParameter("country"); } catch (Exception E) { } if (country == null) {country = ""; } else {System.err.println(country);} if (language == null) {locale = Locale.getDefault(); } else { System.err.println(language); locale = new Locale(language, country); } System.err.println(locale.getDisplayName()); try { setBackground(new Color(Integer.parseInt(getParameter("bgcolor"), 16))); } catch (Exception E) { } try { numberColor = new Color(Integer.parseInt(getParameter("fgcolor"), 16)); } catch (Exception E) {} formatter = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.MEDIUM,locale); currentDate = new Date(); lastdate = formatter.format(currentDate); clockFaceFont = new Font("Sans-Serif", Font.PLAIN, 14); resize(275, 25); // Set clock window size } // Paint is the main part of the program public void paint(Graphics g) { String today; currentDate = new Date(); formatter = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.MEDIUM,locale); today = formatter.format(currentDate); g.setFont(clockFaceFont); g.setColor(getBackground()); g.drawString(lastdate, 0, 12); g.setColor(numberColor); g.drawString(today, 0, 12); 50 lastdate = today; currentDate = null; } public void start() { timer = new Thread(this); timer.start(); } public void stop() { timer = null;} public void run() { Thread me = Thread.currentThread(); while (timer == me) { try {Thread.currentThread().sleep(100); } catch (InterruptedException e) {} repaint(); } } public void update(Graphics g) {paint(g);} public String getAppletInfo() { return "Digital Clock."; } }
Dupa aceste pregatiri se poate porni serverul Tomcat (cu comanda startup), si se poate accesa aplicatia Travel dintr-un browser Web, cu adresa http://localhost:8080/travel/TravelPlan.html. Daca totul este corect, se va obtine imaginea din prima figura din aceasta lucrare.
(4) Crearea servlet-ului Travel. Servlet-ul de dispecerizare a cererilor clientilor este definit n fisierul Travel.java de mai jos.
public class Travel extends HttpServlet { public void init() {} public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (request.getParameter("flights") != null) { gotoPage("/Flights.jsp", request, response); } else if (request.getParameter("cars") != null) { gotoPage("/Cars.jsp", request, response); } else if (request.getParameter("hotels") != null) { gotoPage("/Hotels.jsp", request, response); } else { PrintWriter out = response.getWriter(); out.print("<HTML><BODY>\r\n"); out.println("Illegal Request"); out.print("</HTML></BODY>\r\n"); } } private void gotoPage(String address,HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(address); dispatcher.forward(request, response); } } Mecanismul prin care un servlet poate sa nainteze cererile primite (catre pagini JSP, de exemplu) foloseste un obiect RequestDespatcher, care se obtine apelnd metoda getRequestDipatcher() a obiectului ServletContext asociat, careia i se da ca argument adresa URL catre care se va face naintarea cererii. 51 naintarea cererii propriu-zis se face cu metoda forward(), care are ca argumente de apel obiectele HTTPServletRequest si HTTPServletResponse, asa cum se poate urmari n codul de mai sus. La dezvoltarea aplicatiei se compileaza acest fisier (Travel.java) si se obtine fisierul Travel.class, care trebuie sa fie memorat n directorul ..\travel\WEB-INF\classes; fisierul sursa (Travel.java) poate fi pus n acelasi director sau n alta parte. Se reaminteste ca un servlet este instalat numai la pornirea serverului Tomcat; deci, pentru fiecare modificare si compilare a servletului se opreste si se reporneste serverul Tomcat.
(5) Crearea bean-urilor JavaBeans. Accesul la fiecare tabel al bazei de date se poate controla prin intermediul unui bean care creeaza conexiunea la sursa de date JDBC si executa comenzi de scriere sau citire date n baza de date. Toate clasele bean-urilor de lucru cu baza de date sunt grupate n package-ul database. Pentru tabelul flights se defineste bean-ul FlightDB.java, care are proprietatea flights, care reprezinta lista zborurilor memorate n tabel (de clasa ArrayList). Bean-ul FlightDB foloseste o clasa (Flight.class) care ncapsuleaza datele unei linii din tabelul flights si care, de asemenea este dezvoltata sub forma unui bean. Se compileaza mai nti fisierul Flight.java (cu comanda javac Flight.java -d . din directorul ..\WEB- INF\classes), apoi n mod asemanator fisierul FlightDB.java. Daca totul decurge corect, fisierele Flight.class si FlightDB.class se vor gasi n directorul \WEB-INF\classes\database.
// Fisier Flight.java package database; public class Flight { private String flightId = null; private String origin = null; private String destination = null; public Flight () {} public Flight (String flightId, String origin, String destination) { this.flightId = flightId; this.origin = origin; this.destination = destination; } public String getFlightId() {return this.flightId; } public String getOrigin() {return this.origin;} public String getDestination() {return this.destination;} public void setFlightId(String id) {this.flightId = id;} public void setOrigin(String origin) {this.origin = origin;} public void setDestination(String dest) {destination = dest; } } // Fisier FlightDB.java package database; import java.sql.*; import javax.sql.*; import java.util.*; public class FlightDB { ArrayList flights; Connection con; public FlightDB() { String dbUrl = "jdbc:odbc:Travel"; try {//Incarcarea driverului si crearea conexiunii Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection(dbUrl); } catch (Exception ex) { System.out.println(ex.getMessage());} } public List getFlights(String orig) { flights = new ArrayList(); try { String select = "select * " + "from flights where origin = ?"; PreparedStatement prepStmt = con.prepareStatement(select); prepStmt.setString(1, orig); ResultSet rs = prepStmt.executeQuery(); while (rs.next()) { Flight row = new Flight(rs.getString(1), 52 rs.getString(2), rs.getString(3)); flights.add(row); } prepStmt.close(); } catch (SQLException ex){System.out.println(ex.getMessage());} return flights; } public void remove() { try { con.close(); } catch (SQLException ex) {System.out.println(ex.getMessage());} } }
(6) Crearea paginilor JSP. Se dezvolta mai nti pagina Flights.jsp, memorata n directorul ..\travel , cu urmatorul continut:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> <TITLE>Lista Zboruri</TITLE> </HEAD> <BODY> <CENTER> <H1>Lista Zboruri</H1> <jsp:useBean id="flightDB" class="database.FlightDB" scope="page" > </jsp:useBean> <BR> <TABLE border=1><tr ALIGN=LEFT> <% String orig = request.getParameter("origin"); java.util.ArrayList al; if (orig.length() > 1) al = (java.util.ArrayList)flightDB.getFlights(orig); else al = (java.util.ArrayList)flightDB.getFlights(); java.util.Iterator i = al.iterator(); while (i.hasNext()){ database.Flight fd1 = (database.Flight)i.next(); %> <td> <%= fd1.getFlightId() %> </td> <td> <%= fd1.getOrigin() %> </td> <td> <%= fd1.getDestination() %> </td></tr> <% } %> </TABLE> <% flightDB.remove(); %> </BODY> </HTML>
La actionarea butonului Lista Zboruri din pagina HTML de start a aplicatiei se va obtine lista tuturor zborurilor cu plecare din orasul (aeroportul) introdus n caseta de text Origine, asa cum se vede n figura de mai jos. n pagina Flights.jsp, prin constructia <jsp:useBean> se creeaza un obiect bean de tipul FlightDB.class; la instantierea acestuia (n constructor) se realizeaza conexiunea la sursa de date Travel, folosind driverul (clasa) sun.jdbc.odbc.JdbcOdbcDriver. Acest bean este folosit apoi ntr-un scriptlet pentru a citi datele din baza de date. Rezultatul returnat este un ArrayList de obiecte Flight, fiecare astfel de obiect ncapsulnd datele unei linii a tabelului SQL flights. Aceasta lista este parcursa folosind un iterator, si la fiecare linie se creeaza o linie ntr-un tabel HTML, n celulele careia se nscriu datele zborului respectiv (flightId, origin, destination).
53
Exercitii
6.1 Realizati si executati aplicatia Travel asa cum a fost descrisa n lucrare.
6.2 Completati functiile aplicatiei astfel nct aceasta sa permita memorarea si afisarea si a altor date privind zborurile (de exemplu, memorarea datelor calendaristice ale zborurilor, afisarea numai a zborurilor ntre un anumit oras de plecare si un anumit oras de destinatie, afisarea zborurilor ntre anumite date calendaristice, etc).
6.3 Completati aplicatia proiectata astfel nct sa se poata face rezervarea online a locurilor la zborurile dorite.
6.4 Completati aplicatia pentru celelalte functii prevazute (Inchiriere masina si Rezervare Hotel). Pentru aceasta se va completa baza de date cu tabelele necesare, se vor defini beanurile de citire/modificare a acestor tabele si se vor scrie paginile JSP corespunzatoare.