命令列工具雖適合簡單查詢,但面對大量欄位與記錄時極難閱讀。若能將資料庫表格內容直接映射到 Swing 的 JTable,配合圖形介面將大幅提升資料瀏覽與操作效率。本文示範如何利用 JDBC 中繼資料,實作一個通用的 AbstractTableModel 實作類別 JDBCTableModel,自動將任意資料庫表格轉換為 Swing 表格模型。
建立資料庫連線後,僅需兩次查詢即可取得完整表格資訊:
DatabaseMetaData.getColumns() 取得欄位名稱、資料類型,建立 columnNames 與 columnClasses 陣列SELECT * FROM tableName,將每列資料依欄位類型轉換為對應 Java 物件,存入二維陣列 contents實作 AbstractTableModel 三個抽象方法:
getRowCount() → contents.lengthgetColumnCount() → contents[0].length(空表時為 0)getValueAt(row, col) → contents[row][col]並覆寫 getColumnClass() 與 getColumnName(),分別回傳對應的 Java 類別與欄位名稱,讓 JTable 自動套用適當的 Cell Renderer 與 Editor。
import javax.swing.*;
import javax.swing.table.*;
import java.sql.*;
import java.util.*;
public class JDBCTableModel extends AbstractTableModel {
Object[][] contents;
String[] columnNames;
Class[] columnClasses;
public JDBCTableModel(Connection conn, String tableName) throws SQLException {
super();
getTableContents(conn, tableName);
}
protected void getTableContents(Connection conn, String tableName) throws SQLException {
// 1. 取得欄位中繼資料
DatabaseMetaData meta = conn.getMetaData();
ResultSet results = meta.getColumns(null, null, tableName, null);
ArrayList colNamesList = new ArrayList();
ArrayList colClassesList = new ArrayList();
while (results.next()) {
colNamesList.add(results.getString("COLUMN_NAME"));
int dbType = results.getInt("DATA_TYPE");
switch (dbType) {
case Types.INTEGER: colClassesList.add(Integer.class); break;
case Types.FLOAT: colClassesList.add(Float.class); break;
case Types.DOUBLE:
case Types.REAL: colClassesList.add(Double.class); break;
case Types.DATE:
case Types.TIME:
case Types.TIMESTAMP: colClassesList.add(java.sql.Date.class); break;
default: colClassesList.add(String.class); break;
}
}
columnNames = (String[]) colNamesList.toArray(new String[0]);
columnClasses = (Class[]) colClassesList.toArray(new Class[0]);
// 2. 取得所有資料列
Statement stmt = conn.createStatement();
results = stmt.executeQuery("SELECT * FROM " + tableName);
ArrayList rowList = new ArrayList();
while (results.next()) {
ArrayList cellList = new ArrayList();
for (int i = 0; i < columnClasses.length; i++) {
Object cellValue = null;
if (columnClasses[i] == String.class)
cellValue = results.getString(columnNames[i]);
else if (columnClasses[i] == Integer.class)
cellValue = new Integer(results.getInt(columnNames[i]));
else if (columnClasses[i] == Float.class)
cellValue = new Float(results.getFloat(columnNames[i]));
else if (columnClasses[i] == Double.class)
cellValue = new Double(results.getDouble(columnNames[i]));
else if (columnClasses[i] == java.sql.Date.class)
cellValue = results.getDate(columnNames[i]);
else
System.out.println("Can't assign " + columnNames[i]);
cellList.add(cellValue);
}
rowList.add(cellList.toArray());
}
contents = new Object[rowList.size()][];
for (int i = 0; i < contents.length; i++)
contents[i] = (Object[]) rowList.get(i);
results.close();
stmt.close();
}
public int getRowCount() { return contents.length; }
public int getColumnCount() { return (contents.length == 0) ? 0 : contents[0].length; }
public Object getValueAt(int row, int col) { return contents[row][col]; }
public Class getColumnClass(int col) { return columnClasses[col]; }
public String getColumnName(int col) { return columnNames[col]; }
}
使用 HSQLDB(輕量級 Java 關聯式資料庫)作為測試環境:
org.hsqldb.jdbcDriverjdbc:hsqldb:file:testdbsa,密碼:空測試程式 TestJDBCTable 會自動建立 EMPLOYEES 範例表(姓名、職稱、薪資),插入 5 筆資料,再利用 JDBCTableModel 包裝成 JTable 並置於 JFrame 顯示。執行結果如圖:

圖 3-9. 將資料庫中的資料填充到 JTable 中
TableCellRenderer,將數值格式化(如貨幣、百分比)、日期轉為相對時間("2小時前")等ArrayList 轉陣列雖利於隨機存取,但大量資料時可考慮直接使用陣列或分批處理此模型提供一個快速原型開發的基礎,讓開發者以最少程式碼即可將任意資料庫表格視覺化,適合管理工具、報表預覽等場景。