carrello.jsp

Transcript

carrello.jsp
JSP – Caso di studio 2: myShop
• Costruiamo un’applicazione web di una certa
complessità.
• Vogliamo realizzare un front-end (interfaccia verso gli
utenti) di un sito che vende dei prodotti online.
• Quindi le pagine principali saranno:
–
–
–
–
–
home page,
catalogo dei prodotti disponibili,
pagina per aggiungere un prodotto nel carrello,
pagina per gestire il carrello (modifica quantità, ecc.),
pagina per effettuare un ordine.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 1
Caratteristiche chiave e
configurazione
• Utilizziamo un database per generare
dinamicamente le pagine dei prodotti.
• Sfruttiamo il supporto per le sessioni in JSP
per tener traccia del carrello (i.e., i prodotti
selezionati) del cliente.
• Cerchiamo di non ripetere lo stesso codice
(XHTML e/o Java) in più pagine, utilizzando
la direttiva include.
include
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 2
Deployment su latoserver
• Il codice è scaricabile da: mitel.dimi.uniud.it/med
• Su latoserver.dimi.uniud.it scaricare il file .zip e
decomprimerlo all'interno della directory servlets
(che si trova dentro la propria home directory),
spostando myShop.jar da /home/<nomeutente>/servlets/myShop/WEB-INF/lib in
/home/<nome-utente>/servlets/WEB-INF/lib (dove
risiede anche il file pwlsGallery.jar).
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 3
Configurare sql.jsp
• Controllare la stringa di connessione in modo che
punti al database corretto:
String stringaConnessione=
"jdbc:mysql://localhost/myShop";
• Editare i valori delle variabili utenteSQL e
passwordSQL impostandoli alla stringa vuota "".
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 4
Il flusso logico dell'applicazione
index.jsp
prodotti.jsp
aggiorna.jsp
carrello.jsp
elimina.jsp
svuota.jsp
invia.jsp
ordina.jsp
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 5
Architettura di myShop:
pagine principali
• index.jsp: home page del sito (punto di
partenza);
• prodotti.jsp: pagina con l’elenco dei prodotti
ordinabili;
• carrello.jsp: pagina per l’inserimento e la
visualizzazione dei prodotti nel carrello;
• ordina.jsp: pagina con il modulo d’ordine.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 6
Architettura di myShop:
pagine ausiliarie
• aggiorna.jsp: aggiorna le quantità dei
prodotti presenti nel carrello;
• elimina.jsp: elimina un singolo prodotto
dal carrello;
• svuota.jsp: svuota interamente il carrello.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 7
Architettura di myShop:
file include
• I file seguenti sono inclusi nelle pagine del sito per
mezzo di opportune direttive include:
– banner.jsp: contiene il banner del sito (con logo e data
corrente);
– footer.jsp: piè di pagina;
– heading.jsp: intestazione (tag <head>);
– menu.jsp: menu di navigazione nel sito.
– sql.jsp: stringa di connessione, nome utente e password per
accedere a MySQL, funzioni utili, caricamento del driver.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 8
Osservazioni sui file include
• E’ possibile includere con la direttiva include
sia file dinamici (.jsp) che statici (.html).
• Anche se un file da includere contiene solo risorse
statiche, risulta comunque preferibile utilizzare
l’estensione dinamica jsp; infatti se in futuro si
renderà necessario includere del codice in tale file,
non sarà necessario modificare tutte le direttive
che lo utilizzano per aggiornarne l’estensione.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 9
La base di dati (I)
• Su latoserver.dimi.uniud.it è possibile utilizzare il
database myshop di cui fanno parte le seguenti tabelle:
–
–
–
–
prodotti,
intestazioni_ordini,
righe_ordini,
utenti_backoffice.
• Lo script per creare e “popolare” le tabelle (tramite il
client a linea di comando mysql) è scaricabile da
mitel.dimi.uniud.it/med.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 10
La base di dati (II)
•
•
La tabella prodotti contiene 3 elementi visibili tramite la query
seguente:
[scagnetto@latoserver scagnetto]$ > mysql -u anonymous
mysql> use myshop
mysql> select * from prodotti;
+----+-------------------+----------------------------------------------+-------+
| ID | Prodotto
| Descrizione
| Prezzo
|
+----+-------------------+----------------------------------------------+-------+
| 1 | Hard Disk 400 GB | 7200 giri, 16MB cache, Controller Serial Ata |
230
|
| 2 | Monitor CRT
| 17''
|
130
|
| 3 | Modulo RAM 512 MB | Modulo SDRAM 512 MB PC-133
|
70
|
+----+-------------------+----------------------------------------------+-------+
3 rows in set (0.00 sec)
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 11
Il diagramma E-R
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 12
Le classi dell'applicazione
• Gli oggetti fondamentali gestiti dall'applicazione web coincidono
con le entità del modello E-R.
• In più c'è una classe apposita per la gestione dei carrelli virtuali.
virtuali
• Il package formato da queste classi si chiama myShop.
• Le classi contenute nel package sono le seguenti:
–
–
–
–
–
Prodotto,
ProdottoSelezionato,
Carrello,
Ordine,
Utente.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 13
Le classi Prodotto e
ProdottoSelezionato
• La classe Prodotto modella un prodotto del negozio virtuale.
• Le sue proprietà sono:
– id: un intero che identifica il prodotto in modo univoco (int);
– nome: il nome del prodotto (String);
– descrizione: una breve descrizione del prodotto (String);
– prezzo: il prezzo unitario (double).
• La classe ProdottoSelezionato modella un prodotto del
negozio virtuale selezionato da un cliente ed inserito nel carrello.
• Estende la classe Prodotto aggiungendo la proprietà
quantitaSelezionata.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 14
La classe Carrello
• Modella un “carrello” di un cliente del negozio virtuale.
• Un oggetto di tipo Vector contiene tutti i prodotti selezionati.
• I metodi forniti dalla classe sono i seguenti:
– AggiungiProdotto: aggiunge un prodotto al carrello.
– EliminaProdotto: elimina un prodotto dal carrello.
– ModificaQuantita: modifica la quantità di un prodotto nel carrello.
– Svuota: elimina tutti i prodotti nel carrello.
– TrovaIndiceProdotto: restituisce l'indice del prodotto di cui si fornisce l'identificatore
numerico.
– TrovaProdotto: restituisce il prodotto di cui si fornisce l'indice (posizione nel carrello).
– Vuoto: restituisce true se il carrello è vuoto, false altrimenti.
– NumeroProdotti: restituisce il numero di prodotti contenuti nel carrello.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 15
La classe Ordine
• Modella un ordine effettuato da un cliente del negozio virtuale.
• Le sue proprietà sono: numero dell'ordine, data, nome, cognome ed
indirizzo del cliente, modalità di pagamento e di consegna, spese di
spedizione ed un oggetto di tipo Vector che contiene i singoli
prodotti ordinati.
• I metodi della classe sono i seguenti:
– AggiungiRiga: aggiunge una nuova riga (prodotto ordinato)
all'ordine.
– TrovaRiga: restituisce il prodotto selezionato di cui si fornisce la
posizione (numero di riga).
– NumeroRighe: restituisce il numero di righe (prodotti ordinati)
dell'ordine.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 16
La classe Utente
• Modella un utente dell'area riservata (backoffice)
del negozio virtuale.
• Le sue proprietà sono:
– username: il nome utente necessario per effettuare il
login nell'area riservata (String);
– password: la password necessaria per effettuare il
login (String);
– descrizione: una breve descrizione dell'utente
(String).
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 17
Il package myShop.jar
• Per maggiore “pulizia” del codice inseriamo in un
package apposito le classi utili a modellare gli
oggetti maggiormente utilizzati nell’applicazione.
• Tutte le pagine JSP che avranno bisogno di tali
classi potranno utilizzarle utilizzando l’attributo
import della direttiva page nel modo seguente:
<%@ page import="myShop.*" %>
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 18
Compilazione del package
• Compilazione delle singole classi:
javac Carrello.java Ordine.java Prodotto.java
ProdottoSelezionato.java Utente.java
• Creazione dell'archivio jar:
jar cvf myShop.jar myShop/*.class
• myShop.jar
va copiato in WEB-INF/lib.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 19
Il problema degli apici (I)
• Supponiamo di voler inserire un nuovo record nella tabella
anagrafica (composta da tre campi: Nome, Cognome,
DataNascita):
INSERT INTO anagrafica (Nome, Cognome,
DataNascita) VALUES ('Mario', 'Rossi', '1987-1005')
• Le stringhe di caratteri (come Mario) devono essere racchiuse fra
apici.
• Quindi per inserire una stringa, al cui interno compaiono degli apici
come valore di un campo, bisogna “codificarli”
codificarli per evitare che
l’interprete SQL “spezzi”
spezzi la stringa in più parti con gli errori di
sintassi che ne conseguirebbero.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 20
Il problema degli apici (II)
• Gli apici in SQL vengono codificati
raddoppiandoli:
– es.: la stringa
l'articolo
viene codificata in
l''articolo
• In questo modo è possibile delimitare la stringa
con gli apici senza problemi nella sintassi SQL:
'l''articolo'
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 21
Il problema degli apici (III)
• In Java è sufficiente scrivere la funzione seguente
per la codifica:
String CodificaApici(String s) {
String codifica="";
for(int i=0; i<s.length(); i++)
if(s.charAt(i)=='\'')
codifica+="''";
else
codifica+=s.charAt(i);
return codifica;
}
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 22
Il problema degli apici:
form di login (I)
• In generale si chiede all'utente di inserire username e
password.
• Poi si costruisce una query del genere:
"SELECT COUNT(*) FROM utenti WHERE
username="+"'"+username+"' AND
password='"+password+"'"
dove username e password sono variabili che contengono
quanto inserito dall'utente nei campi omonimi del form.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 23
Il problema degli apici:
form di login (II)
• Se il controllo per abilitare il login viene fatto discriminando
sul conteggio (0=accesso negato, <>0 accesso consentito), è
sufficiente digitare quanto segue nel campo username:
' OR TRUE OR '1=1
• Infatti la query diventa:
SELECT COUNT(*) FROM utenti WHERE
username='' OR TRUE OR '1=1' AND
password='non importa'
• La clausola WHERE a questo punto è banalmente verificata
falsando il conteggio.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 24
index.jsp (I)
La struttura di index.jsp è la stessa delle altre pagine principali:
<%@ page import="java.util.Date" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3c.org/TR/xhtml1/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/XHTML" xml:lang="it"
lang="it">
<%@ include file="heading.jsp" %>
<body>
<table width="100%">
<tr>
<td colspan="2" class="blubg">
<%@ include file="banner.jsp" %>
</td>
</tr>
...
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 25
index.jsp (II)
<tr>
<td width="10%" class="blubg">
<%@ include file="menu.jsp" %>
</td>
<td align="center" width="90%">
<div class="intestazione">Benvenuti su myShop!</div>
</td>
</tr>
<tr>
<td colspan="2">
<%@ include file="footer.jsp" %>
</td>
</tr>
</table>
</body>
</html>
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 26
Il file prodotti.jsp (I)
...
<%try {
Connection c = DriverManager.getConnection(stringaConnessione,
utenteSQL, passwordSQL);
Statement s = c.createStatement();
ResultSet r = s.executeQuery("SELECT * FROM prodotti");
%>
...
<table align="center">
<tr>
Parametri definiti in sql.jsp
<td class="intestazione_tabella">
Prodotto
</td>
...
<td class="intestazione_tabella">
Inserisci nel carrello
</td>
</tr>
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 27
Il file prodotti.jsp (II)
<%
NumberFormat fmt=NumberFormat.getInstance(Locale.ITALIAN);
fmt.setMinimumFractionDigits(2);
fmt.setMaximumFractionDigits(2);
int riga=0;
while(r.next()) {
riga++;
String stile=riga%2==0 ? "riga2_tabella" : "riga1_tabella";%>
<tr>
<form method="post" action="carrello.jsp">
<td class='<%= stile%>'><%= r.getString(2)%></td>
<td class='<%= stile%>'><%= r.getString(3)%></td>
<td class='<%= stile%>'><%= fmt.format(r.getFloat(4))%></td>
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 28
Il file prodotti.jsp (III)
<td class='<%= stile%>'>
<input type="text" name="qt" value="1" size="2" />
</td>
<td class='<%= stile%>'>
<input type="submit" name="ordina" value="&gt;&gt;" />
<input type="hidden" name="pid" value="<%= r.getInt(1)%>" />
</td>
</form>
</tr>
<%}%>
</table>
<%r.close(); s.close(); c.close();
} catch (SQLException e) {
response.sendRedirect("errore.jsp");
return;
}%>
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 29
Il file carrello.jsp (I)
• La pagina carrello.jsp ha una duplice
funzionalità:
– aggiungere un prodotto al carrello,
– visualizzare il carrello.
• Se richiamata con il parametro stampa impostato
a 1, visualizza soltanto il carrello:
carrello.jsp?stampa=1
• Altrimenti ricerca nei parametri passati attraverso
la richiesta il prodotto da aggiungere.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 30
Il file carrello.jsp (II)
• Il codice della pagina risulta semplice, grazie allo sforzo fatto
in fase di modellazione delle entità fondamentali
dell'applicazione.
• Controllo del carrello vuoto:
Carrello carrello=null;
if(session.getAttribute("myShop.carrello")==null) {
carrello=new Carrello();
session.setAttribute("myShop.carrello",carrello);
} else
carrello=(Carrello)session.getAttribute("myShop.carrello");
…
boolean carrelloVuoto=carrello.Vuoto();
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 31
Il file carrello.jsp (III)
• Controllo della presenza di un prodotto nel carrello:
Connection c=DriverManager.getConnection(stringaConnessione,
utenteSQL,
passwordSQL);
Statement s=c.createStatement();
ResultSet r=s.executeQuery("SELECT Prodotto, Descrizione, Prezzo"
+"FROM prodotti WHERE ID="+idProdotto);
ID="+idProdotto
if(r.next()) {
Prodotto p=new Prodotto(Integer.parseInt(idProdotto),
r.getString(1), r.getString(2), r.getFloat(3));
}
if(carrello.TrovaIndiceProdotto(Integer.parseInt(idProdotto))
==-1)
carrello.AggiungiProdotto(p, qtProdotto);
else
carrello.ModificaQuantita(Integer.parseInt(idProdotto),
qtProdotto);
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 32
Il file carrello.jsp (IV)
...
for(; i<carrello.NumeroProdotti(); i++) {
String stile=(i+1)%2==0 ? "riga2_tabella" : "riga1_tabella";
ProdottoSelezionato ps=carrello.TrovaProdotto(i);
%>
<tr>
<td class='<%= stile%>'><%= ps.nome%></td>
<td class='<%= stile%>'><%= ps.descrizione%></td>
<td class='<%= stile%>'><%= fmt.format(ps.prezzo)%></td>
<td class='<%= stile%>'>
<input type="hidden" name="id<%= i%>" value="<%= ps.id%>"/>
<input type="text" name="qt<%= i%>"
value="<%= ps.quantitaSelezionata%>" size="2" />
</td>
<td class='<%= stile%>'>
<%= fmt.format(ps.prezzo*ps.quantitaSelezionata)%></td>
<td class='<%= stile%>'>
<a href="elimina.jsp?id=<%= ps.id%>">
<img src="images/cestino.gif" border="0" /></a></td>
</tr>
<% } %>
...
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 33
Localizzazione della valuta (I)
• Per stampare le valute nel formato più appropriato per la
località corrente (separatore decimale corretto ecc.), si
può utilizzare il codice seguente:
NumberFormat fmt = NumberFormat.
getInstance(Locale.ITALIAN);
fmt.setMinimumFractionDigits(2);
fmt.setMaximumFractionDigits(2);
• In questo modo gli importi in Euro verranno stampati
con due cifre dopo il separatore decimale (la virgola).
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 34
Localizzazione della valuta (II)
• Grazie alle classi NumberFormat e Locale,
utilizzate come esposto nel lucido precedente,
è poi possibile formattare valori che
rappresentano valuta nel modo seguente:
output.write("Totale: "+
fmt.format(new Double(totale))+
" Euro\n\n\n\n");
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 35
La pagina aggiorna.jsp (I)
<%@ page import="myShop.*" %>
<%
int numeroRighe=0;
try {
numeroRighe = Integer.parseInt(request.getParameter("righe"));
} catch (NullPointerException e) {
numeroRighe=0;
} catch (NumberFormatException e) {
numeroRighe=0;
}
Carrello carrello=null;
if(session.getAttribute("myShop.carrello")==null)
carrello=new Carrello();
else
carrello=(Carrello)session.getAttribute("myShop.carrello");
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 36
La pagina aggiorna.jsp (II)
try {
for(int i=0;i<numeroRighe;i++) {
String idProdotto=
request.getParameter("id"+(new Integer(i)).toString());
int qtProdotto=0;
try {
qtProdotto = Integer.parseInt(
request.getParameter("qt"+(new Integer(i)).toString()));
} catch (NullPointerException e) {
qtProdotto=0;
} catch (NumberFormatException e) {
qtProdotto=0;
}
carrello.ModificaQuantita(Integer.parseInt(idProdotto),
qtProdotto);
}
} catch (Exception e) {
response.sendRedirect("errore.jsp");
return;
}
response.sendRedirect("carrello.jsp?stampa=1");
%>
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 37
La pagina elimina.jsp
<%@ page import="myShop.*" %>
<%
String idProdotto=request.getParameter("id");
Carrello carrello=null;
if(session.getAttribute("myShop.carrello")==null)
carrello=new Carrello();
else
carrello=(Carrello)session.getAttribute("myShop.carrello");
try {
carrello.EliminaProdotto(Integer.parseInt(idProdotto));
} catch (Exception e) {
response.sendRedirect("errore.jsp");
return;
}
response.sendRedirect("carrello.jsp?stampa=1");
%>
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 38
La pagina svuota.jsp
<%@ page import="myShop.*" %>
<%
Carrello carrello=null;
if(session.getAttribute("myShop.carrello")==null)
carrello=new Carrello();
else
carrello=(Carrello)session.getAttribute("myShop.carrello");
carrello.Svuota();
response.sendRedirect("carrello.jsp?stampa=1");
%>
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 39
Controllare i campi di un form (I)
String
String
String
String
String
nome = request.getParameter("nome");
cognome = request.getParameter("cognome");
indirizzo = request.getParameter("indirizzo");
pagamento = request.getParameter("pagamento");
consegna = request.getParameter("consegna");
// variabile booleana: true -> valori corretti,
//
false -> errore di compilazione.
boolean formValido=!nome.trim().equals("") &&
!cognome.trim().equals("") &&
!indirizzo.trim().equals("") &&
!pagamento.trim().equals("-") &&
Controllo delle
!consegna.trim().equals("-");
combo box
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 40
Controllare i campi di un form (II)
<%
if(formValido) {
%>
messaggio e/o codice per gestire i valori
inviati (ad esempio registrando l’ordine)
<%
}
else {
%>
messaggio d’errore
<%
}
%>
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 41
La pagina d'errore
•
Siccome gli errori che avvengono a tempo di esecuzione nelle pagine JSP
sollevano delle eccezioni che possono essere gestite con dei blocchi try−catch,
è opportuno realizzare una pagina che presenti un messaggio d’errore
comprensibile anche per l’utente del Web meno esperto e fare in modo che, in
caso di errori, quest’ultimo venga rediretto a tale pagina.
•
Praticamente tutto il codice potenzialmente “pericoloso” della nostra
applicazione è racchiuso in opportuni blocchi try ed il relativo blocco catch
provvede a reindirizzare l’utente alla pagina errore.jsp.
•
Nel caso di un’applicazione reale in questo tipo di pagine è opportuno inserire
anche un recapito di posta elettronica a cui rivolgersi in caso l’errore si ripeta
frequentemente.
•
Un altro accorgimento utile è utilizzare le pagine di gestione degli errori per
memorizzare in un file di log (oppure in una tabella di un db)
db i dati tecnici
dell’errore.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 42
Parte II:
Transazioni ed Area Riservata
• Consistenza dei dati: le transazioni
• Area riservata:
– Autenticazione degli utenti tramite form e
database
– Protezione dell'accesso per mezzo delle
sessioni
– Visualizzazione degli ordini
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 43
La memorizzazione degli ordini (I)
•
Il form della pagina ordina.jsp invia le informazioni alla pagina invia.jsp che
si occupa di controllare la validità dei dati inseriti dall'utente e di registrare
l'ordine nel database.
•
Viene recuperato un riferimento al carrello virtuale dalla sessione corrente per
inserire l'ordine in tre fasi:
– si recupera il numero d'ordine più alto presente nella tabella intestazioni_ordini,
– si memorizza l'intestazione del nuovo ordine, usando come numero il valore estratto
al passo precedente più uno,
uno
– tramite un ciclo for, per ogni elemento presente nel carrello virtuale si esegue una
query che inserisce un nuovo record nella tabella righe_ordini usando lo stesso
numero d'ordine dell'intestazione del passo precedente.
•
Alla fine si svuota il carrello e si procede a visualizzare un messaggio per l'utente
che segnali la corretta terminazione dell'operazione.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 44
La memorizzazione degli ordini (II)
• La procedura appena descritta appare lineare e intuitiva, ma bisogna
tenere conto della concorrenza degli accessi.
• Cosa succederebbe se due clienti effettuassero un ordine allo stesso
istante?
istante
– Entrambe le richieste, accedendo alla tabella delle intestazioni degli ordini in
istanti ravvicinati, ricaverebbero lo stesso valore come numero d'ordine più
alto.
– Entrambe le richieste così imposterebbero lo stesso numero d'ordine
generando un errore al momento di inserire nel database le relative
intestazioni.
• Infatti, essendo il numero d'ordine (attributo ID) chiave primaria della
tabella intestazioni_ordini, non possono esserci due record con lo
stesso valore di ID.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 45
Possibili soluzioni
• Per evitare questa situazione, si può operare in due modi:
– impostare isThreadSafe=false nella direttiva page,
– utilizzare il meccanismo delle transazioni.
transazioni
• La prima alternativa non dà garanzie assolute (Tomcat
potrebbe decidere di creare più istanze in memoria della
servlet corrispondente alla pagina JSP).
• L'utilizzo delle transazioni invece è la soluzione ideale
perché si appoggia su una tecnologia consolidata ed
ampiamente utilizzata nell'ambito dei database.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 46
Transazioni
•
Il concetto di transazione è molto importante nell’utilizzo delle basi di dati.
•
Si deve pensare ad una transazione come ad un’ operazione atomica,
atomica ovvero, ad
un’operazione che viene eseguita senza interruzioni.
•
In ogni dato istante soltanto un processo/thread può accedere agli oggetti del
database manipolati da una transazione (realizzando così una sorta di sezione
critica).
•
La transazione è composta da diverse query:
– se si verifica un errore durante l’esecuzione di una qualunque di tali query, viene
effettuato un rollback,
rollback annullando l’effetto di tutte le query precedenti che
compongono la transazione;
– se tutte le query vengono eseguite senza errori, allora viene effettuato un commit,
commit
scrivendo le modifiche nella base di dati.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 47
Utilizzo delle transazioni
• Sequenza di operazioni per implementare una transazione:
– Dopo aver aperto la connessione e creato uno statement c come al
solito, si disabilita la modalità di funzionamento standard di JDBC
(auto-commit mode)
mode che considera ogni singola query SQL come
una transazione che provoca l’immediato aggiornamento (commit)
del database: c.setAutoCommit(false);
– Si inizia la transazione:
• Si eseguono le varie query che compongono la transazione.
• Se non si verificano errori, si procede ad eseguire il commit,
aggiornando il database: c.commit();
• In caso di errori si effettua il rollback, annullando l’effetto di
tutte le query della transazione: c.rollback();
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 48
Il codice per la memorizzazione
dell’ordine (I)
...
Connection c = DriverManager.getConnection(
stringaConnessione, utenteSQL, passwordSQL);
Statement s = c.createStatement();
try {
c.setAutoCommit(false);
ResultSet r = s.executeQuery("SELECT MAX(ID) FROM intestazioni_ordini");
int idOrdine=0;
if(r.next()) { idOrdine=r.getInt(1); }
r.close();
idOrdine++;
s.executeUpdate("INSERT INTO intestazioni_ordini (ID, Data, "+
"Nome, Cognome, Indirizzo, Pagamento, Consegna, "+
"SpeseSpedizione) VALUES ("+idOrdine+", '"+
formatoData.format(new Date())+"','"+CodificaApici(nome)+
"','"+CodificaApici(cognome)+"','"+CodificaApici(indirizzo)+
"','"+CodificaApici(pagamento)+"','"+CodificaApici(consegna)+
"',"+contributoSpeseSpedizione+")");
...
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 49
Il codice per la memorizzazione
dell’ordine (II)
...
for(int i=0; i<carrello.NumeroProdotti(); i++) {
ProdottoSelezionato ps=carrello.TrovaProdotto(i);
s.executeUpdate("INSERT INTO righe_ordini (IDOrdine, "+
"IDProdotto, Prezzo, Quantita) VALUES ("+idOrdine+","+
ps.id+","+ps.prezzo+","+ps.quantitaSelezionata+")");
}
c.commit();
}
catch(SQLException e) {
c.rollback();
response.sendRedirect("errore.jsp");
return;
}
...
Nota: in MySQL il tipo delle tabelle che supportano le
transazioni è InnoDB (non MyISAM).
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 50
L’area riservata
• Spesso vi è la necessità di proteggere delle pagine di un sito o
applicazione dall’accesso indiscriminato (anonimo).
• Tale obiettivo può essere raggiunto in almeno due modi:
– configurando direttamente il server (e.g.: file .htaccess di Apache);
– realizzando un meccanismo di autenticazione tramite codice lato
server ed il supporto di cookie/sessioni e di un database (per
memorizzare gli utenti).
• Il secondo metodo citato è più flessibile, ma richiede un certo sforzo da
parte del programmatore.
• Ovviamente se non viene progettato ed implementato con cura, il
meccanismo di autenticazione può diventare una seria backdoor per le
pagine che si intende proteggere.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 51
Il form di autenticazione:
backoffice.jsp
• L’idea alla base di ogni meccanismo di autenticazione basato su
tecnologie lato server è di discriminare fra utenti autorizzati e
non,
non controllando nella sessione (o in un cookie) la presenza di un
determinato oggetto.
• Memorizzeremo quindi nella sessione di un utente che specifichi
correttamente le proprie credenziali d’accesso un oggetto
myShop.backofficeUser di tipo Utente.
• Il controllo delle suddette credenziali (nome utente e password)
avverrà mediante la ricerca di una corrispondenza di valori nella
tabella utenti_backoffice.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 52
Controllo iniziale e recupero dei
parametri
• Se l’oggetto myShop.backofficeUser è presente nella sessione,
redirezioniamo il browser verso la pagina protetta ordini.jsp:
if(session.getAttribute("myShop.backofficeUser")!=null) {
response.sendRedirect("ordini.jsp");
return;
}
• Se invece l'utente non si è ancora autenticato, recuperiamo i parametri
del form:
String username=request.getParameter("user");
if(username==null)
username="";
String password=request.getParameter("pwd");
if(password==null)
password="";
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 53
Controllo dei parametri del form
di login
boolean autenticato=false;
try {
Connection c = DriverManager.getConnection(
stringaConnessione, utenteSQL, passwordSQL);
Statement s = c.createStatement();
ResultSet r = s.executeQuery("SELECT COUNT(*) FROM "+
"utenti_backoffice WHERE Username='"+
CodificaApici(username)+
"' AND Password='"+
CodificaApici(password)+"'");
if(r.next()) {
autenticato=r.getInt(1)==1;
}
Si noti l'utilizzo
del metodo
CodificaApici()
s.close();
c.close();
} catch (SQLException e) {
response.sendRedirect("errore.jsp");
return;
}
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 54
Prepared Statement
• Una soluzione più professionale al problema della
codifica degli apici (e quindi all'iniezione di codice SQL
potenzialmente pericoloso) è costituita dall'uso dei
Prepared Statement.
• Essenzialmente sono degli oggetti che rappresentano dei
comandi SQL precompilati.
• In tal modo possono essere eseguiti in modo ripetuto con
efficienza.
• http://java.sun.com/j2se/1.4.2/docs/api/java/sql/
PreparedStatement.html
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 55
Prepared Statement
• Esempio d'uso:
String username=request.getParameter("username");
String password=request.getParameter("password");
PreparedStatement pstmt = con.prepareStatement("SELECT
COUNT(*) FROM utenti_backoffice WHERE username = ? AND
password=?");
sostituisce la stringa
contenuta nella
pstmt.setString(1, username);
variabile username al
posto del primo ‘?’
pstmt.setString(2, password);
ResultSet r=pstmt.executeQuery();
sostituisce la stringa contenuta
nella variabile username al posto
del secondo ‘?’
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 56
Memorizzazione delle password
• Nell'esempio relativo a MyShop le password degli utenti
sono memorizzate “in chiaro” nella tabella
utenti_backoffice.
• Ciò è comodo nel caso le si dimentichi (basta una query
per recuperarle).
• Tuttavia tale comodità rappresenta anche un problema di
sicurezza.
• Le password andrebbero sempre memorizzate in forma
codificata con una one-way function (MD5, SHA-1 ecc.).
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 57
Funzioni One-Way
• Sono delle funzioni f tali che:
– il calcolo di y=f(x) (codifica) è molto efficiente;
– Il calcolo inverso, ovvero, ricavare x da f(x)
(decodifica) è computazionalmente proibitivo o
impossibile;
– è altamente improbabile che due valori x e x' diversi fra
loro, abbiano gli stessi valori secondo f (ovvero,
f(x)=f(x')).
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 58
Modus operandi
• Volendo sfruttare una one-way function, si opera come
segue:
– le password sono salvate in forma codificata nel database;
– l'utente inserisce la propria password in chiaro nel form di
autenticazione;
– la password fornita dall'utente viene codificata ed il
risultato della codifica viene confrontato con il valore
memorizzato nel database;
– se le due codifiche coincidono, l'utente è autenticato,
altrimenti no.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 59
MD5 in Java
import java.security.MessageDigest;
import java.math.BigInteger;
public class MD5Test {
public static void main(String args[]) throws Exception {
String password = "test";
MessageDigest m = MessageDigest.getInstance("MD5");
m.update(password.getBytes("UTF8"));
byte s[] = m.digest();
BigInteger bigInt = new BigInteger(1, s);
String result = bigInt.toString(16);
System.out.println("Password: "+password);
System.out.println("Password digest (MD5): "+result);
}
}
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 60
Impostazione dell’oggetto
myShop.backofficeUser
• Se le credenziali dell’utente hanno trovato riscontro positivo nella tabella
utenti backoffice, allora si provvede ad impostare l’oggetto
myShop.backofficeUser nella sessione corrente ed a redirigere il
browser verso la pagina protetta:
if(autenticato) {
Utente u=new Utente(username, password,
"Amministratore");
session.setAttribute("myShop.backofficeUser", u);
response.sendRedirect("ordini.jsp");
return;
}
• Il flag autenticato viene utilizzato anche per determinare cosa inviare
come risposta al browser (messaggio d’errore oppure form di login).
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 61
La pagina protetta: ordini.jsp
• La pagina ordini.jsp permette agli utenti autenticati di
visualizzare una tabella con tutti gli ordini effettuati.
• Inoltre, per ogni ordine, è possibile visualizzare il dettaglio dei
prodotti ordinati.
• Tale operazione si svolge richiamando, tramite un link, la stessa
pagina con un parametro che specifica il numero d’ordine di cui
visualizzare le righe.
• Inizialmente si controlla se l’utente è autorizzato a visualizzare la
pagina; in caso contrario lo si reindirizza al form di login:
if(session.getAttribute("myShop.backofficeUser")==null) {
response.sendRedirect("backoffice.jsp");
return;
}
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 62
Proteggere le pagine riservate
• Nel caso siano presenti più pagine riservate, il controllo
visto precedentemente va effettuato in ognuna di esse.
• Infatti non è possibile imporre un ordine di visita delle
pagine ed un client potrebbe cercare di indirizzarla
direttamente saltando il form di login.
• Quindi sarebbe meglio includere il codice in un file con
estensione jsp da includere in ogni pagina in cui ce ne sia
bisogno.
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 63
ordini.jsp: recupero del
parametro
Si procede a recuperare l'eventuale numero d'ordine di cui bisogna visualizzare il
dettaglio delle singole righe che lo compongono:
String idOrdine=request.getParameter("id");
try {
Integer.parseInt(idOrdine);
} catch (NullPointerException e) {
idOrdine="0";
} catch (NumberFormatException e) {
idOrdine="0";
}
Si noti che in caso di parametro assente (NullPointerException) o di errore di
formato (NumberFormatException), la variabile idOrdine viene inizializzata alla
stringa "0" (numero d'ordine non esistente).
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 64
ordini.jsp: recupero dei dati (I)
Recupero dell'intestazione degli ordini:
Vector ordini=new Vector();
boolean nessunOrdine=true;
...
Connection c = DriverManager.getConnection(
stringaConnessione, utenteSQL, passwordSQL);
Statement s = c.createStatement();
ResultSet r = s.executeQuery("SELECT ID, Data, Nome, Cognome, "+
"Indirizzo, Pagamento, Consegna, SpeseSpedizione FROM "+
"intestazioni_ordini ORDER BY Data DESC");
while(r.next()) {
Ordine o=new Ordine(r.getInt(1), r.getDate(2), r.getString(3),
r.getString(4), r.getString(5), r.getString(6),
r.getString(7), r.getFloat(8));
...
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 65
ordini.jsp: recupero dei dati (II)
Recupero delle righe relative all'ordine corrente:
...
Statement s2 = c.createStatement();
ResultSet r2=s2.executeQuery("SELECT P.ID, P.Prodotto, "+
"P.Descrizione, R.Prezzo, R.Quantita FROM prodotti AS P, "+
"righe_ordini AS R WHERE P.ID=R.IDProdotto AND R.IDOrdine="+
o.numero);
while(r2.next()) {
Prodotto p=new Prodotto(r2.getInt(1), r2.getString(2),
r2.getString(3), r2.getFloat(4));
o.AggiungiRiga(p, r2.getInt(5));
}
...
ordini.add(o);
}
Si noti come l'ordine corrente venga aggiunto alla collezione ordini soltanto quando
siano state recuperate tutte le informazioni su di esso (righe comprese).
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 66
La pagina ordini.jsp
Complementi di Tecnologie Web – M. Franceschet, V.Della Mea e I.Scagnetto, a.a. 2011/12 - 67