Revised: 9th/Sep./2002
以下で利用するためのテーブルを作成しましょう。
C:\mysql\bin>mysql test Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 4 to server version: 3.23.49-nt Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> create table addr -> (name char(20), -> access char(30)); Query OK, 0 rows affected (0.01 sec) mysql> insert into addr values ('菅井', 'sugai@fides.dti.ne.jp'); Query OK, 1 row affected (0.04 sec) mysql> select * from addr; +------+-----------------------+ | name | access | +------+-----------------------+ | 菅井 | sugai@fides.dti.ne.jp | +------+-----------------------+ 1 row in set (0.00 sec) mysql> \q Bye C:\mysql\bin>
testデータベースにaddrテーブルが作成されました。
出力結果をGUIのテーブルに表示させて見ましょう。
ResultSet
のデータはテーブル形式なので、SwingではJTableを使って表示することになります。JTableではjavax.swing.table.TableModelインタフェース型オブジェクトとしてデータを取得します。実際には、TableModelインタフェースのデフォルトの実装がjavax.swing.table.AbstractTableModelで提供されているので、これを継承したサブクラスを作ることになります。この抽象クラスから具象TableModelオブジェクトを作成するには、次の三つのメソッドを実装する必要があります。
public int getRowCount(); // モデルの列数を返します。 public int getColumnCount(); // モデルの行数を返します。 public Object getValueAt(int row, int column); // row と column にあるセルの値を返します。
例えば、10行5列のJTableを作るには、次のコードが必要になります。
// TableModel オブジェクトの作成 TableModel dataModel = new AbstractTableModel() { public int getRowCount() { return 10; // 行数 } public int getColumnCount() { return 5; // 列数 } public Object getValueAt(int row, int col) { return 指定されたセルの戻り値; } }; // JTable のデータをモデルから取得 JTable table = new JTable(dataModel); // Jtable を JScrollPane を通して見る JScrollPane scrollpane = new JScrollPane(table);
ResultSet
からJTale
を作る場合もTableModel
を利用します。次の断片は、ResultSetオブジェクトから列数や型などのメタデータを取得し、AbstractTableModelを実装するものです。java.util.Vector
オブジェクトを用いていることにも注目してください。Vectorオブジェクトは、配列と似ていますが、要素をjava.lang.Object
オブジェクトとして扱い、各行の要素数の追加が可能です。
resultSet = statement.executeQuery(query); metaData = resultSet.getMetaData(); // ResultSetのメタデータの取得 int numberOfColumns = metaData.getColumnCount(); // 列数を取得 columnNames = new String[numberOfColumns]; // 列名を保持する配列の作成 for(int column = 0; column < numberOfColumns; column++) { columnNames[column] = metaData.getColumnLabel(column + 1); // 列名を取得 } rows = new Vector(); // ResultSet全体のデータを保持するベクトル while (resultSet.next()) { Vector newRow = new Vector(); // ResultSetの一行分のデータを保持するベクトル for (int i = 1; i <= getColumnCount(); i++) { newRow.addElement(resultSet.getObject(i)); // 各データを取得し追加 } rows.addElement(newRow); // 各行を追加 }
上記の断片で型宣言されていない変数は、このクラスのメンバー変数として宣言しておきます。ResultSetのテーブルはVectorオブジェクトのrowに保持されました。テーブルの各行はVectorオブジェクトのnewRowに保持され、各列名がString型配列columnNamesに保持されています。以上三つのオブジェクトを使って、AbstractTableModel
の実装メソッドは次のように書けます。
public int getColumnCount() { return columnNames.length; } public int getRowCount() { return rows.size(); } public Object getValueAt(int aRow, int aColumn) { Vector row = (Vector)rows.elementAt(aRow); return row.elementAt(aColumn); }
このように作ったTableModelをmodelオブジェクトとしてインスタンス化すると、JTableは次のように書けます。
JTable table = new JTable(model); JScrollPane scrollpane = new JScrollPane(table);
以上を踏まえて、Swingアプレットは次のように書けます。ここでは、AbstractTableModelのサブクラスをDataModel、DBMS接続/SQL文発行オブジェクトをPersistentManager、アプレットをDBCSwingAppletとします。
JDBCSwingApplet.java
:
import java.awt.*; import javax.swing.*; import javax.swing.table.*; import java.sql.*; import java.util.*; public class JDBCSwingApplet extends JApplet { TableModel model; public void init() { // DBMS への接続 PersistenceManager persistMgr = new PersistenceManager(); // SQL 文の発行とモデルの取得 try { ResultSet rs = persistMgr.executeSQL("SELECT * FROM addr;"); model = new DataModel(rs); } catch (SQLException e) { e.printStackTrace(); return; } // JTable の作成 JTable table = new JTable(model); JScrollPane scrollpane = new JScrollPane(table); // コンテント・ペインの取得 Container cont = getContentPane(); cont.add(scrollpane); } } class PersistenceManager { Statement stmt; // DBMS への接続 PersistenceManager() { try { // JDBC Driver の登録 Class.forName("com.mysql.jdbc.Driver").newInstance(); // データベースへの接続 Connection con = DriverManager.getConnection( "jdbc:mysql://localhost/test", "root", "passwd"); // SQL ステートメント・オブジェクトの作成 stmt = con.createStatement(); } catch (Exception e) { e.printStackTrace(); } } // SQL 文の発行 ResultSet executeSQL(String str) throws SQLException { return stmt.executeQuery(str); } } class DataModel extends AbstractTableModel { String[] columnNames; Vector rows = new Vector(); // モデルの作成 DataModel(ResultSet rs) throws SQLException { ResultSetMetaData metaData = rs.getMetaData(); // ResultSetのメタデータの取得 int numberOfColumns = metaData.getColumnCount(); // 列数を取得 columnNames = new String[numberOfColumns]; // 列名を保持する配列の作成 for(int column = 0; column < numberOfColumns; column++) { columnNames[column] = metaData.getColumnLabel(column + 1); // 列名を取得 } rows = new Vector(); // ResultSet全体のデータを保持するベクトル while (rs.next()) { Vector newRow = new Vector(); // ResultSetの一行分のデータを保持するベクトル for (int i = 1; i <= getColumnCount(); i++) { newRow.addElement(rs.getObject(i)); // 各データを取得し追加 } rows.addElement(newRow); // 各行を追加 } } // 以下 AbstractTableModel の実装 public String getColumnName(int column) { if (columnNames[column] != null) { return columnNames[column]; } else { return ""; } } public int getColumnCount() { return columnNames.length; } public int getRowCount() { return rows.size(); } public Object getValueAt(int aRow, int aColumn) { Vector row = (Vector)rows.elementAt(aRow); return row.elementAt(aColumn); } }
このアプレットも、実行するためにはJDBCドライバが必要ですが、アプレットは一般に自分がダウンロードされたサーバ・マシンとしか通信できず、自分をダウンロードしたクライアント・マシンのローカル・ファイルに触ることができません。従って、ローカル・マシンのCLASSPATHで切ってあるMySQL Connector/JドライバのJARファイルを使うことができません。この問題を解決するためには、JARファイルもこのアプレットと共にサーバ・マシンからダウンロードし、それを使う必要があります。そのためには、HTMLのapplet要素にarchive属性を与えてサーバ・マシン上のJARファイルを指定します。
JDBCSwingApplet.html
:
<p><applet code="JDBCSwingApplet" archive="mysql-connector-java-2.0.14-bin.jar" width="200" height="100"> アプレットが実行できない場合の代替内容 </applet></p>
"JDBCSwingApplet.java
"をjavacでコンパイルして生成した"JDBCSwingApplet.class
"と、"JDBCSwingApplet.html
"と、"mysql-connector-java-2.0.14-bin.jar
"を同じディレクトリに置いてください。別のディレクトリに置くときは、applet要素にcodebase属性を指定します。詳細はW3CによるHTML 4.01の仕様書をご覧ください。