Il problema Vogliamo realizzare un applicativo web che consenta di inserire, modificare e cancellare i record della tabella libri_tbl (database MySQL biblio_db). In questi casi, parliamo di applicativo di tipo CRUD (C=create, R=retrieve, U=update e D=delete). Il modello dei dati Ipotizziamo la presenza nel database biblio_db di tre tabelle secondo lo schema ER seguente: Fig. 1 Diagramma ER (Entity-Relationship) Lo schema è lo stesso di altri esempi già presi in considerazione (in particolare si leggano gli articoli DAO, Database a oggetti: db4o nella sezione Web application del mio sito web http://www.mauriziocozzetto.it). Funzionalità dell'applicativo web Rappresentiamo nelle schermate seguenti le funzionalità del nostro applicativo. In particolare le pagine che prenderemo in considerazione sono: cancellalibro.jsp, effettuamodificalibro.jsp, gestioneerrori.jsp, index.jsp, inseriscilibro.jsp, modificalibro.jsp. Fig. 2 L'elenco dei libri crud_mysql.pdf Pag. 1/17 Cozzetto
Fig. 3 Inserimento di un libro A titolo di esempio, considereremo anche la gestione della chiave esterna relativa all'autore (nella figura rappresentata da alcuni valori contenuti in una combo-box). Fig. 4 Messaggio dell'avvenuto inserimento Durante la fase di inserimento, l'applicativo dovrà: verificare che i campi isbn e titolo non siano entrambi nulli (il campo idautore è comunque valorizzato per cui non è mai nullo è una scelta progettuale potevamo fare anche diversamente in base alle impostazioni della tabella); verificare che non venga inserito un record con lo stesso isbn: in tal caso, l'applicativo si limiterà a segnalare la cosa senza compiere alcuna operazione. crud_mysql.pdf Pag. 2/17 Cozzetto
Fig. 5 Modifica del record con nuovi dati Durante la fase di modifica, occorre: verificare ancora una volta che i due campi isbn e titolo non siano nulli (come nel caso dell'inserimento); inoltre sarà possibile modificare anche l'idautore in modo tale che sia possibile salvarne il nuovo valore. Inoltre, qualsiasi tentativo di modifica dell'isbn sulla barra degli indirizzi, ridirigerà verso la pagina index.jsp, come pure il mancato click sul link Modifica. Fig. 6 Il record con isbn=12-1234-567-8 è stato cancellato dalla lista Anche nel caso della cancellazione, occorre controllare che l'isbn non venga alterato e che l'utente abbia davvero deciso di eliminare un record cliccando sul link Cancella. Il modello a oggetti Il modello a oggetti adottato è simile a quello dell'esercitazione DAO. Cambieranno i metodi della classe DAO i quali soddisferanno ai nuovi requisiti posti dal problema. Non vengono riportate per brevità le 3 classi Autore, Libro, Editore. crud_mysql.pdf Pag. 3/17 Cozzetto
/* * DAO.java * * Created on 7 aprile 2008, 21.20 * */ package it.mauriziocozzetto.classipkg; import java.util.list; import java.sql.*; import java.util.arraylist; /** * * @author maurizio */ public class DAO { // reference al database static Connection conn; /** Creates a new instance of DAO */ public DAO() { // La classe DAO // restituisce la lista dei libri(int) v public List<Libro> getlibri() throws SQLException { Statement st = conn.createstatement(); List<Libro> libri = new ArrayList<Libro>(); ResultSet rs = st.executequery("select * FROM libri_tbl"); // ciclo di lettura su tutto il RecordSet while (rs.next()) { String isbn = rs.getstring("isbn"); String titolo = rs.getstring("titolo"); // caricamento del libro nella lista Libro l = new Libro(isbn, titolo); libri.add(l); rs.close(); st.close(); return libri; // fine metodo getlibri() // restituisce l'elenco degli id (distinti) degli autori public int[] getelencoidautore() throws SQLException { Statement st = conn.createstatement(); crud_mysql.pdf Pag. 4/17 Cozzetto
// prepariamo la struttura dati List<Integer> listaidautore = new ArrayList<Integer>(); ResultSet rs = st.executequery("select DISTINCT idautore FROM libri_tbl ORDER BY idautore"); // ciclo di lettura sui record while (rs.next()) { int idautore = rs.getint("idautore"); listaidautore.add(idautore); // chiusura del record-set e dello statement rs.close(); st.close(); // contiamo gli id int numidautore = listaidautore.size(); // prepariamo un vettore di interi correttamente dimensionato int[] v = new int[numidautore]; // spostiamo gli id autore nel vettore dal Vector for (int i=0; i<numidautore; i++) { v[i]=(integer) listaidautore.get(i); return v; // fine metodo getelencoidautore() // restituisce il libro con codice isbn assegnato public Libro trovalibro(string isbn) throws SQLException { Libro l = null; // creiamo lo statement che rappresenta l'istruzione SQL Statement st = conn.createstatement(); // troviamo il record con isbn assegnato ResultSet rs = st.executequery("select * FROM libri_tbl WHERE libri_tbl.isbn = '"+isbn+"'"); // se esiste il record if (rs.next()) { String ISBN = rs.getstring("isbn"); String titolo = rs.getstring("titolo"); int idautore = rs.getint("idautore"); // restituiamo l'autore con idautore assegnato Autore autore=trovaautore(idautore); // istanziamo un libro con isbn, titolo e autore l=new Libro(ISBN,titolo,autore); // chiudiamo il ResultSet e lo statement crud_mysql.pdf Pag. 5/17 Cozzetto
rs.close(); st.close(); return l; // fine metodo trovalibro // troviamo l'autore con idautore assegnato public Autore trovaautore(int idautore) throws SQLException { Autore a = null; // creiamo lo statement che rappresenta l'istruzione SQL Statement st = conn.createstatement(); // troviamo l'autore ResultSet rs = st.executequery("select * FROM autori_tbl WHERE autori_tbl.idautore = "+idautore); // se esiste il record if (rs.next()) { int idaut = rs.getint("idautore"); String cognome = rs.getstring("cognome"); String nome = rs.getstring("nome"); // istanziamo l'autore a = new Autore(idAut, cognome, nome); // fine if // chiudiamo il ResultSet e lo statement rs.close(); st.close(); return a; // registra nel database un libro public int salvalibro(libro l) throws SQLException { // lettura di isbn, titolo e idautore String isbn = l.getisbn(); String titolo = l.gettitolo(); int idautore = l.getautore().getidautore(); // preparazione dello statement Statement st = conn.createstatement(); String sql = "INSERT INTO libri_tbl(isbn,titolo,idautore) VALUES ('"+isbn+"','"+titolo+"',"+idautore+")"; int result = st.executeupdate(sql); st.close(); return result; // fine metodo salvalibro // cancella un libro public int cancellalibro(libro l) throws SQLException { String isbn = l.getisbn(); Statement st = conn.createstatement(); crud_mysql.pdf Pag. 6/17 Cozzetto
String sql = "DELETE FROM libri_tbl WHERE isbn = '"+isbn+"'"; int result = st.executeupdate(sql); st.close(); return result; // fine metodo cancellalibro // modifica del libro il cui isbn è assegnato public int modificalibro(libro l, String isbn) throws SQLException { String ISBN = l.getisbn(); String titolo = l.gettitolo(); int idautore = l.getautore().getidautore(); Statement st = conn.createstatement(); String sql = "UPDATE libri_tbl SET isbn = '"+ISBN+"', titolo = '"+titolo+"', idautore="+idautore+" WHERE isbn = '"+isbn+"'"; int result = st.executeupdate(sql); st.close(); return result; // fine metodo modificalibro // chiusura della connessione public void closeconn() throws SQLException { conn.close(); // fine metodo close() // caricamento dei driver e apertura della connessione al database public void openconn() throws ClassNotFoundException, SQLException { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/biblio_db? user=root&password="); // fine metodo open() // fine classe DAO Le pagine web Pagina index.jsp @page contenttype="text/html" @page pageencoding="utf-8" @page import="java.util.list" @page import="it.mauriziocozzetto.classipkg.*" @page errorpage = "gestioneerrori.jsp" <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/tr/html4/loose.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>database biblio_db</title> <style type="text/css"> body,td,th { font-family: Verdana; font-size: 16px; crud_mysql.pdf Pag. 7/17 Cozzetto
.testorosso { color: red; </style> </head> <body> <h3>tabella Libri</h3> // visualizziamo un messaggio nei casi previsti if (request.getparameter("msg")!=null) { String msg = request.getparameter("msg"); out.println("<p><span class='testorosso'>"+msg+"</span></p>"); // link per inserire un record out.println("<p><a href='inseriscilibro.jsp'>inserisci</a></p>"); <jsp:usebean id="dao" class="it.mauriziocozzetto.classipkg.dao"/> // apertura del database dao.openconn(); // elenco di tutti i libri List<Libro> listalibri = dao.getlibri(); // se la lista non contiene elementi if (listalibri.size()==0) out.println("non ci sono libri"); else { out.println("<table>"); // stampa dell'isbn e del titolo del libro, con i link necessari per la manutenzione dei record for (Libro l : listalibri) { out.println("<tr>"); out.println("<td>"+l.getisbn()+"</td><td>"+l.gettitolo()+"</td><td>"+"<a href='modificalibro.jsp?isbn="+l.getisbn()+"'>modifica</a></td><td><a href='cancellalibro.jsp?isbn="+l.getisbn()+"'>cancella</a></td>"); out.println("</tr>"); // fine for out.println("</table>"); // fine if // chiusura del database dao.closeconn(); </body> </html> crud_mysql.pdf Pag. 8/17 Cozzetto
Pagina inseriscilibro.jsp @page contenttype="text/html" @page pageencoding="utf-8" @page errorpage = "gestioneerrori.jsp" @page import = "it.mauriziocozzetto.classipkg.*" <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/tr/html4/loose.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html"> <title>inserimento</title> <style type="text/css"> body,td,th { font-family: Verdana; font-size: 16px; border: 0px;.testoRosso { color: red; </style> </head> <body> <h3>inserimento</h3> <jsp:usebean id="dao" class="it.mauriziocozzetto.classipkg.dao"/> // apertura della connessione dao.openconn(); // se l'utente non ha premuto il tasto inviabtn if (request.getparameter("inviabtn") == null) { <form id="provafrm" method="post" action="${request.requesturi" > Isbn <input type="text" name="isbntxt" value="" size="30"/> <span class="testorosso">*</span><br/> Titolo <input type="text" name="titolotxt" value="" size="30" /> <span class="testorosso">*</span> <br/> IdAutore <select name="idautoremnu"> // caricamento degli id degli autori int elencoidautore[]=dao.getelencoidautore(); // caricamento degli id in una combo-box for (int i = 0; i<elencoidautore.length; i++) { <option>=elencoidautore[i]</option> // fine for crud_mysql.pdf Pag. 9/17 Cozzetto
</select> <span class="testorosso">*</span><br/> <input type="submit" name="inviabtn" value="invia"/><br/> <p><span class="testorosso">* Dati obbligatori</span></p> </form> else { // lettura di isbn, titolo e idautore String isbn = request.getparameter("isbntxt"); String titolo = request.getparameter("titolotxt"); int idautore = Integer.parseInt(request.getParameter("idAutoreMnu")); // isbn e titolo non possono essere nulli if (isbn==null isbn.length()==0 titolo==null titolo.length()==0) { dao.closeconn(); response.sendredirect("index.jsp?msg=impossibile effettuare l'inserimento perche' uno dei due campi e' nullo o entrambi"); return; // noto l'isbn, troviamo il libro l Libro l = dao.trovalibro(isbn); // se non esiste il libro con chiave isbn possiamo inserirlo nel db if (l==null) { // troviamo l'autore del libro Autore a = dao.trovaautore(idautore); // creiamo il libro l = new Libro(isbn, titolo, a); // lo inseriamo nel db int result = dao.salvalibro(l); // se l'inserimento ha effetto result>0 if (result>0) { response.sendredirect("index.jsp?msg=inserimento effettuato record con isbn="+isbn); else { response.sendredirect("index.jsp?msg=impossibile registrare il record con isbn="+isbn); // fine if else { response.sendredirect("index.jsp?msg=record con isbn="+isbn+" gia' esistente"); // fine if // fine if // chiusura della connessione dao.closeconn(); </body> </html> crud_mysql.pdf Pag. 10/17 Cozzetto
Pagina modificalibro.jsp @page contenttype="text/html" @page pageencoding="utf-8" @page errorpage = "gestioneerrori.jsp" @page import = "it.mauriziocozzetto.classipkg.*" <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/tr/html4/loose.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>modifica</title> <style type="text/css"> body,td,th { font-family: Verdana; font-size: 16px; border: 0px;.testoRosso { color: red; </style> </head> <body> <h3>modifica</h3> // se l'utente ha selezionato un record if (request.getparameter("isbn")!= null) { <jsp:usebean id="dao" class="it.mauriziocozzetto.classipkg.dao"/> // apertura della connessione dao.openconn(); // recuperiamo l'isbn String isbn = request.getparameter("isbn"); // troviamo il libro con isbn selezionato Libro l = dao.trovalibro(isbn); // se il libro esiste if (l!= null) { // recuperiamo l'idautore int idautore = l.getautore().getidautore(); <form id="provafrm" method="get" action="effettuamodificalibro.jsp" > Isbn <input type="text" name="isbntxt" value="=l.getisbn()" size="30" /> <span class="testorosso">*</span><br/> Titolo <input type="text" name="titolotxt" value="=l.gettitolo()" size="30" /> <span class="testorosso">*</span><br/> IdAutore crud_mysql.pdf Pag. 11/17 Cozzetto
</body> </html> <select name="idautoremnu"> // memorizziamo in un vettore l'elenco degli idautore int elencoidautore[]=dao.getelencoidautore(); for (int i = 0; i<elencoidautore.length; i++) { // imposto come elemento selezionato quello relativo all'idautore if(idautore==elencoidautore[i]) { <option selected="true">=elencoidautore[i]</option> else { <option>=elencoidautore[i]</option> // fine if // fine for </select> <span class="testorosso">*</span><br/> <input type="hidden" name="isbnhdn" value="=l.getisbn()"/> <input type="submit" name="inviabtn" value="invia"/><br/> <p> <span class="testorosso">* Dati obbligatori</span></p> </form> else { response.sendredirect("index.jsp?msg=non esiste un libro con isbn="+isbn); // fine if (l!=null) // chiusura della connessione dao.closeconn(); else { // se tentiamo di accedere a questa pagina senza aver selezionato il link "Modifica" response.sendredirect("index.jsp"); // fine if request.getparameter() Pagina effettuamodifica.jsp @page contenttype="text/html" @page pageencoding="utf-8" @page errorpage = "gestioneerrori.jsp" @page import = "it.mauriziocozzetto.classipkg.*" <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/tr/html4/loose.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>modifica</title> crud_mysql.pdf Pag. 12/17 Cozzetto
<style type="text/css"> body,td,th { font-family: Verdana; font-size: 16px; border: 0px; </style> </head> <body> <h3>modifica</h3> // se l'utente ha premuto il pulsante inviabtn if (request.getparameter("inviabtn")!= null) { <jsp:usebean id="dao" class="it.mauriziocozzetto.classipkg.dao"/> // apriamo la connessione dao.openconn(); // recuperiamo isbn, titolo, idautore e l'isbn "nascosto" String isbn = request.getparameter("isbntxt"); String titolo = request.getparameter("titolotxt"); int idautore = Integer.parseInt(request.getParameter("idAutoreMnu")); String isbnhdn = request.getparameter("isbnhdn"); // verifichiamo che isbn e titolo non siano nulli if ((isbn==null isbn.length()==0) (titolo==null titolo.length()==0)) { dao.closeconn(); response.sendredirect("index.jsp?msg=impossibile effettuare la modifica perche' uno dei due campi e' nullo o entrambi"); return; // noto l'idautore troviamo l'autore Autore a = dao.trovaautore(idautore); // creiamo un libro con isbn, titolo e autore a Libro l = new Libro(isbn, titolo, a); // modifichiamo il libro l (il vecchio isbn è stato conservato in isbnhdn) int result = dao.modificalibro(l,isbnhdn); // se la modifica ha avuto successo result > 0 if (result>0) { response.sendredirect("index.jsp?msg=modificato record con isbn="+l.getisbn()); else { response.sendredirect("index.jsp?msg=impossibile aggiornare il record con isbn="+isbn); // chiudiamo la connessione dao.closeconn(); else { crud_mysql.pdf Pag. 13/17 Cozzetto
// se tentiamo di accedere a questa pagina senza aver premuto il //pulsante inviabtn vieniamo rediretti alla pagina index.jsp response.sendredirect("index.jsp"); // fine if request </body> </html> Pagina cancellalibro.jsp @page contenttype="text/html" @page pageencoding="utf-8" @page errorpage = "gestioneerrori.jsp" @page import = "it.mauriziocozzetto.classipkg.*" <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/tr/html4/loose.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>cancellazione</title> <style type="text/css"> body,td,th { font-family: Verdana; font-size: 16px; border: 0px; </style> </head> <body> <h3>cancellazione</h3> // se l'utente ha cliccato sul link "Cancella" if (request.getparameter("isbn")!= null) { <jsp:usebean id="dao" class="it.mauriziocozzetto.classipkg.dao"/> // apriamo la connessione dao.openconn(); // recuperiamo l'isbn del libro da cancellare String isbn = request.getparameter("isbn"); // carichiamo in memoria il libro Libro l = dao.trovalibro(isbn); // se il libro esiste if (l!= null) { // cancelliamo il record int result = dao.cancellalibro(l); crud_mysql.pdf Pag. 14/17 Cozzetto
if (result>0) { response.sendredirect("index.jsp?msg=cancellazione effettuata del record con isbn="+l.getisbn()); else response.sendredirect("index.jsp?msg=impossibile cancellare record con isbn="+l.getisbn()); else { response.sendredirect("index.jsp?msg=non esiste un libro con isbn="+isbn); // fine if numlibri // chiudiamo la connessione dao.closeconn(); else { // se tentiamo di accedere a questa pagina senza aver selezionato il link "Cancella" response.sendredirect("index.jsp"); // fine if request </body> </html> Pagina gestioneerrori.jsp @page contenttype="text/html" @page pageencoding="utf-8" @page iserrorpage = "true" <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/tr/html4/loose.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>gestione errori</title> <style type="text/css"> body,td,th { font-family: Trebuchet MS; font-size: 16px; </style> </head> <body> <h3>gestione errori</h3> Siamo spiacenti, si è verificato un errore durante l'esecuzione:<br/> = exception.getmessage() </body> </html> crud_mysql.pdf Pag. 15/17 Cozzetto
Note conclusive Nelle pagine di inserimento (inseriscilibro.jsp) e di variazione dei dati (modificalibro.jsp), compare sempre la combo-box idautore. Potrebbe essere più comodo per l'utente lavorare con il campo Anagrafica in luogo dell'idautore, come nella figura seguente. Fig. 7 L'anagrafica autore in luogo dell'idautore Tuttavia l'informazione memorizzata nella tabella è sempre l'idautore (essendo una chiave esterna). Per implementare questa funzionalità, dobbiamo aggiungere alla classe DAO, un nuovo metodo public String[] getelencoanagraficheautore() throws SQLException { // prepariamo le strutture dati List<String> listaanagraficheautore = new ArrayList<String>(); int[] v = this.getelencoidautore(); String[] listaanagrafiche=new String[v.length]; for (int i=0; i<v.length; i++) { listaanagraficheautore.add(trovaautore(v[i]).getanagrafica()); listaanagrafiche[i]=listaanagraficheautore.get(i); return listaanagrafiche; // fine metodo getelencoanagraficheautore() Fig. 8 Metodo getelencoanagraficheautore() poi modificare le due pagine inseriscilibro.jsp e modificalibro.jsp nella maniera seguente (riportiamo solo i frammenti che ci interessano): crud_mysql.pdf Pag. 16/17 Cozzetto
Anagrafica Autore <select name="idautoremnu"> // caricamento delle anagrafiche e degli id degli autori int elencoidautore[]=dao.getelencoidautore(); String[] elencoanagraficheautore=dao.getelencoanagraficheautore(); // caricamento delle anagrafiche in una combo-box for (int i = 0; i<elencoidautore.length; i++) { <option value="=elencoidautore[i]"> =elencoanagraficheautore[i] </option> // fine for </select> Fig. 9 Frammento di codice della pagina inseriscilibro.jsp Anagrafica Autore <select name="idautoremnu"> // memorizziamo in un vettore l'elenco degli idautore e in un // altro le anagrafiche degli autori int elencoidautore[]=dao.getelencoidautore(); String[] elencoanagraficheautore=dao.getelencoanagraficheautore(); for (int i = 0; i<elencoidautore.length; i++) { // imposto come elemento selezionato quello // relativo all'idautore if(idautore==elencoidautore[i]) { <option selected="true" value="=elencoidautore[i]"> =elencoanagraficheautore[i]</option> else { <option value="=elencoidautore[i]"> =elencoanagraficheautore[i]</option> // fine if // fine for </select> Fig. 10 Frammento della pagina modificalibro.jsp crud_mysql.pdf Pag. 17/17 Cozzetto