首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JDBC TableModel 實作:將資料庫表格快速映射至 Swing JTable

     編輯:Java 相關知識

命令列工具雖適合簡單查詢,但面對大量欄位與記錄時極難閱讀。若能將資料庫表格內容直接映射到 Swing 的 JTable,配合圖形介面將大幅提升資料瀏覽與操作效率。本文示範如何利用 JDBC 中繼資料,實作一個通用的 AbstractTableModel 實作類別 JDBCTableModel,自動將任意資料庫表格轉換為 Swing 表格模型。

核心思路:兩次查詢完成映射

建立資料庫連線後,僅需兩次查詢即可取得完整表格資訊:

  1. 查詢中繼資料:透過 DatabaseMetaData.getColumns() 取得欄位名稱、資料類型,建立 columnNames 與 columnClasses 陣列
  2. 查詢實際資料:執行 SELECT * FROM tableName,將每列資料依欄位類型轉換為對應 Java 物件,存入二維陣列 contents

實作 AbstractTableModel 三個抽象方法:

  • getRowCount() → contents.length
  • getColumnCount() → 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.jdbcDriver
  • URL:jdbc:hsqldb:file:testdb
  • 用戶名:sa,密碼:空

測試程式 TestJDBCTable 會自動建立 EMPLOYEES 範例表(姓名、職稱、薪資),插入 5 筆資料,再利用 JDBCTableModel 包裝成 JTable 並置於 JFrame 顯示。執行結果如圖:

資料庫資料填充至 JTable

圖 3-9. 將資料庫中的資料填充到 JTable 中

注意事項與擴展建議

  • 大量資料警示:若表格擁有百萬列資料,全載入記憶體會導致 OOM,實務上應分頁載入或實作虛擬模型
  • 格式化顯示:可自訂 TableCellRenderer,將數值格式化(如貨幣、百分比)、日期轉為相對時間("2小時前")等
  • 效能優化:ArrayList 轉陣列雖利於隨機存取,但大量資料時可考慮直接使用陣列或分批處理

此模型提供一個快速原型開發的基礎,讓開發者以最少程式碼即可將任意資料庫表格視覺化,適合管理工具、報表預覽等場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved