Introduzione
Nel
mese precedente abbiamo introdotto il componente swing
JTable, un potente strumento per la visualizzazione
dei dati. Questo mese prenderemo spunto da una piccola
applicazione realizzata "ad hoc", che usa
JTable per visualizzare dati provenienti da tabelle
e query di database.
L'applicazione "TableOnJava"
Questa
piccola applicazione di esempio mostra come si possa,
e come sia semplice farlo, visualizzare tabelle o query
di database attraverso il componente swing JTable.
Proseguendo logicamente con quanto detto la volta scorsa
si è usato un modello che si occupa di caricare
i dati nella JTable, e per il momento non ci è
preoccupati di come questi dati vengono visualizzati.
Il risultato è una serie di pannelli che contengono
oggetti JTable che visualizzano, così come viene
prelevato dalla query SQL, i dati relativi alle tre
tabelle ed alla query presenti nella base dati:
Figura
1 - la base dati
La
base dati di partenza è abbastanza semplice e
generica. La situazione ricreata è molto simile
ad una semplice gestione di un videonoleggio in cui
ogni persona riceve dal gestore un abbonamento (fisicamente
una tessera), ricarica ogni volta che è esaurito
il suo saldo, e quest'ultimo viene decrementato ogni
qualvolta il cliente preleva un film a noleggio.
Le tabelle usate per descrivere questa situazione sono:
Figura
2
Quello
che vogliamo mostrare di questo database è, oltre
al contenuto delle tre tabelle Anagrafica, Ricariche
e Prelievi, anche il saldo di ogni abbonamento, ovvero
il totale delle ricariche, il totale dei prelievi e
la loro differenza. Per far questo utilizziamo la query:
SELECT
A.CodiceAbbonamento, (
Select Sum(ricariche.Importo) from ricariche where ricariche.CodiceAbbonamento
= A.CodiceAbbonamento ) AS Ricariche, (
Select Sum(prelievi.Importo) from prelievi where prelievi.CodiceAbbonamento
= A.CodiceAbbonamento ) AS Prelievi, ([Ricariche]-[Prelievi])
AS Totale
FROM anagrafica AS A;
Adesso
siamo pronti per scrivere il codice di TableOnJava.
Accesso al database
Per
accedere al database di esempio (realizzato con MSAccess
2000) viene utilizzato il bridge jdbc/odbc fornito dalla
Sun. Sicuramente l'uso di un driver nativo per il database
con cui si deve sviluppare la propria applicazione rende
le operazioni di accesso al database molto più
performanti.
La classe SimpleConnection è una classe molto
semplice, priva di controlli approfonditi e di metodi
complessi, che sarebbero, per questo esempio, superflui.
Consente comunque di gestire una connessione statica,
verso un DSN passato come parametro in ingresso al metodo
openConnection:
private
static Connection cn; // La connessione al DB private
static Statement stm; // statement usato per l'esecuzione
di query
I
cinque metodi statici contenuti consentono di:
Aprire
la connessione al database:
public
static void openConnection(String aDSN) { … Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
cn = DriverManager.getConnection("jdbc:odbc:"
+ aDSN,"","");
stm = cn.createStatement();
…
}
Chiudere la connessione al database:
public
static void closeConnection() {
…
stm = null;
cn.close();
…
}
Eseguire
una query SQl di selezione:
public
static ResultSet execute(String anSQLString) {
…
rs = stm.executeQuery(anSQLString);
…
return rs;
…
}
Ottenere il numero di record presenti in una tabella:
public
static int getRecordCount(String aTableName) {
…
query = "SELECT COUNT(*) FROM " + aTableName;
rs = stm.executeQuery(query);
rs.next();
result = rs.getInt(1);
… return result; …
}
Ottenere
la lista dei nomi delle colonne di una determinata tabella:
public
static String[] getColumnsName(String aTableName){
String[] columnsName = null;
ResultSet rs = stm.executeQuery(
"SELECT
* FROM " + aTableName);
ResultSetMetaData rsmd = rs.getMetaData();
int columnsNumber = rsmd.getColumnCount();
columnsName = new String[columnsNumber];
for (int i=0; i< columnsNumber; i++){
columnsName[i] = rsmd.getColumnName(i+1);
}
}
Il modello
Come
abbiamo detto l'altra volta, non è la JTable
ad andare a cercare i dati da caricare, ma tutta questa
parte è delegata ad un modello. Il GenericTableModel
(da non confondere con il DefaultTableModel fornito
dalla Sun) quindi si occupa esattamente di questo.
Graficamente questa applicazione può essere rappresentata
nel seguente modo.
GenericTableModel estende, come previsto, l'AbstractTableModel,
e ne ridefinisce i metodi astratti e quelli necessari
per la corretta visualizzazione.
La base dati in cui vengono memorizzati i dati della
tabella è la seguente:
//
Array di stringhe contente i nome delle colonne
String[] columnsName;
// Matrice contenente i dati della tabella
String[][] cells;
A
questo punto i metodi è abbastanza semplice scrivere
i metodi:
public
int getRowCount() {
return cells.length;
}
public int getColumnCount() {
return columnsName.length;
}
public Object getValueAt(int r, int c)
{
return (String)cells[r][c];
}
public String getColumnName(int c)
{
return columnsName[c];
}
Il costruttore del modello riceve in ingresso il nome
della tabella o query da caricare ed inizializza cells
e columnsName:
public
GenericTableModel(String aTableName){
int rowCount; // Il numero di recod presenti
nella tabella
String
query; // La query creata per accedere al database
//
Apre la connesione al database
SimpleConnection.openConnection("tableonjava");
//
Imposta la query
query
= "SELECT * FROM " + aTableName;
try{
//
Recupero il numero di record nella tabella
rowCount
= SimpleConnection.getRecordCount(aTableName);
//
Recupero le intestazioni delle colonne
columnsName
= SimpleConnection.getColumnsName(aTableName);
//
Creo la matrice dei dati
cells
= new String[rowCount][columnsName.length];
//
eseguo la query
ResultSet
rs = SimpleConnection.execute(query);
int
counter = 0; // Contatore usato per l'iterazione su
cells
//
questo while viene caricata, riga per riga, la matrice
//
dei dati
while
(rs.next()){
for
(int i=0; i <columnsName.length; i++)
cells[counter][i]
= rs.getString(i+1);
counter++;
}
}
catch(Exception
ex){
System.out.println(ex);
}
finally{
//
In ogni caso chiude la connesione al database
SimpleConnection.closeConnection();
}
}
Conclusioni
Ora siamo in grado di crearci un modello che recupera
i dati da una database, cosa molto importante, dato
che il naturale scopo delle JTable è appunto
quello di visualizzare dati organizzati secondo un modello
relazionale.
Si può fare molto di più, ed una volta
che abbiamo i dati possiamo decidere come visualizzarli,
ovvero il loro particolare layout (si pensi alla colonna
dei totali evidenziata in rosso, oppure, all'interno
della stessa colonna ai valori positivi in blu ed a
quelli negativi in rosso). Oppure prendere in considerazione
l'ordinamento di colonne, considerando, a seconda del
tipo di dati presente in una colonna un tipo di ordinamento
diverso.
|