Malmö högskola
Teknik och samhälle
2007/2008
Laboration 24 – Databasen MySQL och java
Avsikten med denna laboration är att du ska hämta information ur en eller flera tabeller och visa resultatet i
en JTable-komponent. Du ska ändra innehållet i tabellen och se till att kolumn-bredderna är bra.
För att kunna göra detta måste du ha tillgång till en databas och kunna kontakta databasen. På Malmö
högskola står en MySQL-server som du kan koppla upp dig från en nätansluten dator. För att detta ska vara
möjligt måste du:
1. Hämta en databas-driver från www.mysql.com.
2. Använda samma inloggningsuppgifter som på laboration 23.
1. Hämta databas-driver till MySQL
På mysql:s hemsida kan du hämta en driver till en MySQL-databas. Drivern innehåller alla klasser som
behövs för att du på ett ganska enkelt sätt ska kunna jobba mot en databas. Adressen till hemsidan är
www.mysql.com och du ska sedan klicka på Developer Zone - Downloads - Connectors - Connector/J.
Du ska nu vara på sidan http://dev.mysql.com/downloads/connector/j/5.1.html.
Hämta hem lämplig arkiv-fil och packa upp den på din dator. Filen
mysql-connector-java-5.1.5-bin.jar
placerar du t.ex. i C:\java (M:\java på MAH). Sedan måste NetBeans hittar jar-filen. Du ska högerklicka på
projektet, välja Properties och sedan klicka på Libraries. Sedan klickar du på knappen Add JAR/Folder och
letar upp mysql-...-bin.jar. Markera filen och klicka sedan på OK.
2. Inloggningsuppgifter
När du kopplar upp dig mot databasen så måste du ange inloggningsuppgifter. Du använder samma som på
laboration 23.
Testa databas-drivern
Med programmet MysqlDB i F24 kan du testa om du kan koppla upp mot databasen. Om uppkoppliongen
går som tänkt så kommer du se innehållet i tabellen Person i databasen test. Testa även att du kan koppla upp
mot din egen databas.
Uppgift 1 – Hämta kolumnnamnen i en resultatmängd
När du ska visa resultatet av en databas-sökning är det trevligt att presentera namn på kolumnerna överst.
Om du vill använda kolumnnamnen som kommer från databasen så går dessa bra att hämta.
Du ska i klassen DBMethods skriva metoden
public static String[] getHeaders(ResultSet rs) throws SQLException
Följande har du till din hjälp:
•
Du kan erhålla ett objekt av typen ResultSetMetaData med metoden rs.getMetaData().
•
I ResultSetMetaData-objektet finns följande metoder:
* getColumnCount() – returnerar antalet kolumner i resultatmängden. Denna uppgift är nödvändig
om du ska skapa en String-array med korrekt antal element.
* getColumnLabel(int columnIndex) – returnerar namnet på kolumnen med angivet index.
Kolumnerna numreras från 1 upp till getColumnCount().
Samtliga metoder ovan kan kasta SQLException. Du kan även titta hur utskriften sker i MysqlDB.java.
Testa din metod genom att koppla upp mot test-databasen, hämta alla kolumner i person-tabellen och skriv ut
kolumn-namnen. Du ska då få en utskrift som innehåller:
pnr, namn, alder, langd
DA129A, Programmering 1
1
Malmö högskola
Teknik och samhälle
2007/2008
Uppgift 2 – Hämta datainnehållet i en resultatmängd
Det väsentligaste när man ska visa resultatet av en databassökning är ju naturligtvis att visa den data som
sökningen givit. Denna information kan lagras i en två-dimensionell array. Men vilken typ av array ska man
välja? Det är ju oftast olika typer av data i resultatmängden. Metoden getObject i objektet ResultSet löser
detta problem. Till varje typ av datainnehåll returneras ett objekt, t.ex..
Datatyp
INT
DECIMAL
DOUBLE
BOOLEAN
DATE
STRING
Objecttyp
Integer
BigDecimal
Double
Boolean
Date
String
Sedan kan man skriva ut dessa på ett snyggt sätt med hjälp av deras toString-metod.
Du ska i klassen DBMethods skriva metoden
public static Object[][] getContent(ResultSet rs) throws SQLException
vilken ska lagra innehållet i resultatmängden i en två-dimensionell array av typen Obejct[ ][ ].
I denna metod kan du använda dig av följande
•
Du kan erhålla ett objekt av typen ResultSetMetaData med metoden rs.getMetaData(). Och sedan
ta reda på antalet kolumner på samma sätt som i uppgift 1.
•
Ta reda på antalet rader på följande sätt:
Flytta rad-pekaren till sista raden: rs.last();
Lagra sista radnumret i rows:
rows = rs.getRow();
•
Skapa en tvådimensionell array:
•
Du kan föra över data från resultatmängden till arrayen i en nästlad loop där du hämtar
informationen i en speciell rad och kolumn så här:
Object[][] data = new Obejct[rows][cols];
for(int row = 0; row<rows; row++) {
rs.absolute(row + 1); // Flytta till rätt rad i resultatmängden
for(int col = 0; col<cols; col++) {
data[row][col] = rs.getObject(col + 1);
}
}
Samtliga metoder ovan kan kasta SQLException. Du kan även titta hur utskriften sker i MysqlDB.java.
Testa din metod genom att koppla upp mot test-databasen, hämta alla kolumner i person-tabellen och skriv ut
kolumn-namnen. Du ska då få en utskrift som innehåller:
631008-1111,
600807-2222,
620101-3333,
731201-4444,
Oskar AL, 41, 182
Eva Ask, 44, 163
Bo Ek, 42, 174
Gudrun Bok, 31, 172
DA129A, Programmering 1
2
Malmö högskola
Teknik och samhälle
2007/2008
Uppgift 3 – Visa i tabell, version 1
Nu kan du visa informationen i en JTabel-komponent. Det finns en konstruktor i JTable som ser ut så här:
public JTable(Object[][] rowData, Object[] columnNames)
Den passar perfekt för att visa en av våra tabeller. Men man måste placera JTable-komponenten i en
JScrollPane för att tabellhuvudet ska synas.
private JTable table;
private JScrollPane scrollPane;
:
Container c = getContentPane();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(400,300);
try {
MysqlDB.kopplaUpp();
ResultSet rs = MysqlDB.statement.executeQuery("SELECT * FROM Person");
String[] headers = DBMethods.getHeaders(rs);
Object[][] content = DBMethods.getContent(rs);
table = new JTable(content, headers);
scrollPane = new JScrollPane(table);
c.add(scrollPane, BorderLayout.CENTER);
} catch(SQLException e) {}
setVisible(true);
Testa genom att placera en tabell i ett fönster.
Uppgift 4 – Sätta kolumnbredder i tabell
Ett problem med tabellen är att alla kolumner får samma bredd. Och detta är oftast inte önskavärt. Det går
bra att sätta bredden på kolumner i en tabell. Man gör så här:
För varje tabell finns objektet TableColumnModel. Med hjälp av detta objekt kan man bl.a. ange bredden
på kolumnerna. Tabellens TableColumnModel-objekt erhåller man genom anrop till getColumnModel:
TableColumnModel columnModel = table.getColumnModel();
Sedan kan man sätta bredden på önskad kolumn genom anropet
columnModel.getColumn(index).setPreferredWidth(bredd);
Naturligtvis måste index vara i intervallet [1 , antalKolumnerITabellen]. Kolumnbredden är relativ om man
inte anger något annat. Med detta menas att hela tabellens bredd fylls ut och kolumnbredderna anpassas till
utrymmet.
Vill man ange absoluta kolumnbredder måste man ändra tabellens beteende med anropet
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
Du ska i klassen DBMethods skriva metoden
public static void setColumnWidth(JTable table, int[] colWidth)
vilken tar en JTable-komponent och en int-array som input och som använder värdena i int-arrayen för att
sätta kolumnbredderna i tabellen. Första elementet i colWidth ger bredden på första kolumnen osv. När du
skriver metoden är det bäst att kontrollera att antalet element i colWidth = = antalet kolumner i tabellen,
annars blir det kanske körfel.
DA129A, Programmering 1
3
Malmö högskola
Teknik och samhälle
2007/2008
Uppgift 5 – Avläsa markerade rader i tabellen
När en tabell visar sig så kan användaren markera en eller flera rader i tabellen. Om du vill ta reda på vilka
rader som är markerade i en tabell kan du anropa metoden getSelectedRows i tabellen:
int[] valdaRader = table.getSelectedRows();
Efter anropet innehåller valdaRader numret på de rader som var markerade när anropet gjordes.
Radnumreringen börjar med 0 och detta passar bra om man ska hämta information ur tabellen med metoden
getValueAt(int rad, int kol). Värdet i rad 1, kolumn 1 hämtas med anropet
Object data = table.getValueAt(0, 0);
Utöka programmet i uppgift 3 med en knapp. När användaren klickar på knappen ska numret på markerade
rader i tabellen skrivas ut i output-fönstret.
Uppgift 6 – Ändra datan i befintlig tabell
Tyvärr går det inte att ändra innehållet i en tabell när man använder konstruktorn i Uppgift 3. För att detta
ska gå bra måste man använda konstruktorn
public JTable(TableModel tm)
TableModel-objektet som levereras vid konstruktionen måste implementera gränssnittet TableModel. En
klass som gör detta skulle vi kunna konstruera (9 metoder att implementera korrekt). Men det finns en färdig
klass i java som tillfredsställer våra behov, nämligen DefaultTableModel (i paketet javax.swing.table).
Denna klass innehåller bl.a. konstruktorn:
public DefaultTableModel(Object[][] data, Object[] columnNames)
Den innehåller också en metod för att ändra befintliga data. Ändrar vi tabelldata med denna metod så ändras
tabellinnehållet automatiskt:
public void setDataVector(Object[][] dataVector, Object[] columnIdentifiers)
Nu ska du modifiera programmet i uppgift 3 så att ett objekt av typen DefaultTableModel används för att ge
tabellen innehåll.
private JTable table;
private JScrollPane scrollPane;
private DefaultTableModel tableModel
:
Container c = getContentPane();
String[] headers = DBMethods.getHeaders(rs);
Object[][] content = DBMethods.getContent(rs);
tableModel = new DefaultTableModel(content, headers);
table = new JTable(tableModel);
scrollPane = new JScrollPane(table);
c.add(scrollPane, BorderLayout.CENTER);
Passa på att skriva metoden setTableContent i fönsterklassen:
public void setTableContent(Object[][] content, Object[] headers) {
tableModel.setDataVector(content, headers);
}
Lägg in en knapp i fönsterklassen som vid klick
1. Hämtar en ny resultatmängd från databasen, t.ex. innehållet i Telefon.
2. Hämtar resultatmängdens kolumnnamn till en String-array
3. Hämtar resultatmängdens data till en Object[ ][ ].
4. Anropar metoden setTableContent (se ovan).
5. Anropar metoden DBMethods.setColumnWidth för att ge kolumnerna vettiga bredder.
DA129A, Programmering 1
4
Malmö högskola
Teknik och samhälle
2007/2008
DBMethods.java
import java.sql.*;
import javax.swing.*;
import javax.swing.table.*;
public class DBMethods {
public static String[] getHeaders(ResultSet rs) throws SQLException {
ResultSetMetaData meta;
String[] headers;
meta = rs.getMetaData();
headers = new String[meta.getColumnCount()];
for(int i=0; i<headers.length; i++) {
headers[i] = meta.getColumnLabel(i+1);
}
return headers;
}
public static Object[][] getContent(ResultSet rs) throws SQLException {
ResultSetMetaData rsmt;
Object[][] content;
int rows, cols;
rsmt = rs.getMetaData();
rs.last();
rows = rs.getRow();
cols = rsmt.getColumnCount();
content = new Object[rows][cols];
for(int row = 0; row<rows; row++) {
rs.absolute(row + 1); // Flytta till rätt rad i resultatmängden
for(int col = 0; col<cols; col++) {
content [row][col] = rs.getObject(col + 1);
}
}
return content;
}
public static void setColumnWidth(JTable table, int[] colWidth) {
TableColumnModel columnModel = table.getColumnModel();
int count = Math.min(table.getColumnCount(),colWidth.length);
for(int i=0; i<count; i++) {
columnModel.getColumn(i).setPreferredWidth(colWidth[i]);
}
}
}
DA129A, Programmering 1
5
Malmö högskola
Teknik och samhälle
2007/2008
Uppgift 3 + Uppgift 5 + Uppgift 6
import
import
import
import
import
javax.swing.*;
javax.swing.table.*;
java.awt.*;
java.awt.event.*;
java.sql.*;
public class Uppgift3 extends JFrame {
private JTable table;
private JScrollPane scrollPane;
private DefaultTableModel tableModel;
//
//
//
//
// Uppg 6
public Uppgift3() {
Container c = getContentPane();
JButton bytData = new JButton("Byt data");
JButton valdaRader = new JButton("Valda rader");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(400,300);
try {
MysqlDB.kopplaUpp();
ResultSet rs = MysqlDB.statement.executeQuery("SELECT * FROM Person");
String[] headers = DBMethods.getHeaders(rs);
Object[][] content = DBMethods.getContent(rs);
tableModel = new DefaultTableModel(content, headers); // Uppg 6
table = new JTable(tableModel);
// Uppg 6
table = new JTable(content, headers);
// Uppg 3
valdaRader.addActionListener(new VL()); // Uppg 5
bytData.addActionListener(new AL());
// Uppg 6
scrollPane = new JScrollPane(table);
c.add(scrollPane, BorderLayout.CENTER);
c.add(valdaRader, BorderLayout.NORTH);
c.add(bytData, BorderLayout.SOUTH);
} catch(SQLException e) {
System.out.println(e);
}
DBMethods.setColumnWidth(table, new int[]{120,120,40,40}); // Relativa bredder
setVisible(true);
}
public void setTableContent(Object[][] content, Object[] headers) {
tableModel.setDataVector(content, headers);
}
// Uppg 5
private class VL implements ActionListener {
public void actionPerformed(ActionEvent e) {
int[] selectedRows = table.getSelectedRows();
String res="";
for(int i=0; i<selectedRows.length; i++) {
res += ""+selectedRows[i]+". "+table.getValueAt(selectedRows[i],0)+"\n";
}
System.out.println(res);
}
}
// Uppg 6
private class AL implements ActionListener {
public void actionPerformed(ActionEvent e) {
try {
ResultSet rs = MysqlDB.statement.executeQuery("SELECT * FROM Telefon");
tableModel.setDataVector(DBMethods.getContent(rs),
DBMethods.getHeaders(rs));
} catch (SQLException e1) {}
}
}
public static void main(String[] args) {
new Uppgift3();
}
}
DA129A, Programmering 1
6