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の仕様書をご覧ください。