Показывает содержимое базы данных books.

advertisement
Создание и обработка базы данных books в DBDerby.
Используя Eclipse, выполните следующие действия:
1. Создайте проект (произвольное имя)
2. Подключите к проекту окружение БД Derby и запустите сервер БД. (В случае успешного
запуска сервера БД в консоли (представление Concole) появляется следующее сообщение:
3. DRDA_SecurityInstalled.I
Сетевой сервер Apache Derby Network Server - 10.3.2.1 - (599110) запущен и
готов принимать соединения на порту 1527
4. Создайте базу данных в DBDerby, с помощью следующего скрипта.
DROP TABLE authorISBN;
DROP TABLE titles;
DROP TABLE authors;
connect
'jdbc:derby://localhost:1527/books;create=true;user=me;password=mine';
DROP TABLE authorISBN;
DROP TABLE titles;
DROP TABLE authors;
CREATE TABLE authors (
authorID INT NOT NULL GENERATED ALWAYS AS IDENTITY,
firstName varchar (20) NOT NULL,
lastName varchar (30) NOT NULL,
PRIMARY KEY (authorID)
);
CREATE TABLE titles (
isbn varchar (20) NOT NULL,
title varchar (100) NOT NULL,
editionNumber INT NOT NULL,
copyright varchar (4) NOT NULL,
PRIMARY KEY (isbn)
);
CREATE TABLE authorISBN (
authorID INT NOT NULL,
isbn varchar (20) NOT NULL,
FOREIGN KEY (authorID) REFERENCES authors (authorID),
FOREIGN KEY (isbn) REFERENCES titles (isbn)
);
INSERT INTO authors (firstName, lastName)
VALUES
('Harvey','Deitel'),
('Paul','Deitel'),
('Andrew','Goldberg'),
('David','Choffnes');
SELECT * FROM authors;
INSERT INTO titles (isbn,title,editionNumber,copyright)
VALUES
('0131869000','Visual Basic 2005 How to Program',3,'2006'),
('0131525239','Visual C# 2005 How to Program',2,'2006'),
1
('0132222205','Java How to Program',7,'2007'),
('0131857576','C++ How to Program',5,'2005'),
('0132404168','C How to Program',5,'2007'),
('0131450913','Internet & World Wide Web How to Program',3,'2004'),
('0131828274','Operating Systems',3,'2004');
INSERT INTO authorISBN (authorID,isbn)
VALUES
(1,'0131869000'),
(2,'0131869000'),
(1,'0131525239'),
(2,'0131525239'),
(1,'0132222205'),
(2,'0132222205'),
(1,'0131857576'),
(2,'0131857576'),
(1,'0132404168'),
(2,'0132404168'),
(1,'0131450913'),
(2,'0131450913'),
(3,'0131450913'),
(1,'0131828274'),
(2,'0131828274'),
(4,'0131828274');
disconnect;
exit;
5. Выполните два ниже прокомментированных примера.
Задание: необходимо реализовать представление recordset из вашей
предметной области в таблице JTable.
Обработка базы данных с помощью JDBC
В этом упражнении рассматривается 2 примера. В первом примере будет рассмотрено
установление соединения с базой данных и выполнение запросов к ней. Второй пример
показывает, как представляются результаты запроса в JTable.
Установление соединения с базой данных и запросы к ней
Пример, представленный ниже, выполняет простой запрос к базе данных базе данных
books, который выводит все записи из таблицы authors и показывает их данные.
Программа иллюстрирует соединение с базой данных, выполнение запроса и обработку
результатов запроса. Затем обсуждаются основные аспекты работы программы, связанные
с применением JDBC.
Вывод содержимого таблицы authors.
1
2
3
// DisplayAuthors.java
// Displaying the contents of the authors table.
import java.sql.Connection;
2
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import
import
import
import
import
java.sql.Statement;
java.sql.DriverManager;
java.sql.ResultSet;
java.sql.ResultSetMetaData;
java.sql.SQLException;
public class DisplayAuthors
{
// database URL
static final String DATABASE_URL = "jdbc:mysql://localhost/books";
// launch the application
public static void main( String args[] )
{
Connection connection = null; // manages connection
Statement statement = null; // query statement
ResultSet resultSet = null; // manages results
// connect to database books and query database
try
{
// establish connection to database
connection = DriverManager.getConnection(
DATABASE_URL, "javafp", "javafp" );
// create Statement for querying database
statement = connection.createStatement();
// query database
resultSet = statement.executeQuery(
"SELECT authorID, firstName, lastName FROM authors" );
// process query results
ResultSetMetaData metaData = resultSet.getMetaData();
int numberOfColumns = metaData.getColumnCount();
System.out.println( "Authors Table of Books Database:\n" );
for ( int i = 1; i <= numberOfColumns; i++ )
System.out.printf( "%-8s\t", metaData.getColumnName( i ) );
System.out.println();
while ( resultSet.next() )
{
for ( int i = 1; i <= numberOfColumns; i++ )
System.out.printf( "%-8s\t", resultSet.getObject( i ) );
System.out.println();
} // end while
} // end try
catch ( SQLException sqlException )
{
sqlException.printStackTrace();
} // end catch
finally // ensure resultSet, statement and connection are closed
{
try
{
resultSet.close();
statement.close();
connection.close();
} // end try
catch ( Exception exception )
3
65
66
67
68
69
70
{
exception.printStackTrace();
} // end catch
} // end finally
} // end main
} // end class DisplayAuthors
Authors Table of Books Database:
authorID
1
2
3
4
firstName
Harvey
Paul
Andrew
David
lastName
Deitel
Deitel
Goldberg
Choffnes
Строки 3–8 импортирую интерфейсы и классы JDBC из пакета java.sql , используемого
в программе. Строка 13 объявляет константу string для URL базы данных. При этом
идентифицируется имя базы данных для соединения, и информацию о протоколе,
используемую драйвером JDBC. Метод main (строки 16–69) соединяют с базой данных
books, выполняет запрос к базе данных, выводит результат запроса и закрывает
соединение с базой данных.
После кодирования программы вы можете выполнить приложение, используя Eclipse.
Строки 26–27 создают объект Connection (java.sql) с именем connection. Объект,
который реализует интерфейс Connection управляет соединением между программой
Java и базой данных. Объект Connection позволяет программам создавать утверждения
SQL, которые обрабатывают базу данных. Программа инициализирует connection в
результате вызова static метода getConnection класса DriverManager (java.sql),
который пытается соединиться с базой данных, специфицированной URL. Метод
getConnection принимает три аогумента—String , которая специфицирует URL базы
данных, String , которая специфицирует имя пользователя и String , которая
специфицирует пароль. URL указывает размещение базы данных (возможно в сети или в
локальной файловой системе компьютера). Варианты кодирования URL для нескольких
популярных СУБД показаны в таблице ниже. Если DriverManager не может соединиться с
базой данных, то метод getConnection вызывает SQLException (java.sql).
форматы URL для популярных СУБД для JDBC
RDBMS
Database URL format
MySQL
jdbc:mysql://hostname:portNumber/databaseName
4
форматы URL для популярных СУБД для JDBC
RDBMS
Database URL format
ORACLE
jdbc:oracle:thin:@hostname:portNumber:databaseName
DB2
jdbc:db2:hostname:portNumber/databaseName
Java DB/Apache
jdbc:derby:dataBaseName (встроенный)
Derby
jdbc:derby://hostname:portNumber/databaseName (сетевой)
Microsoft SQL Server jdbc:sqlserver://hostname:portNumber;databaseName=dataBaseName
Sybase
jdbc:sybase:Tds:hostname:portNumber/databaseName
Строка 30 вызывает метод createStatement объекта Connection для получения объекта,
который реализует интерфейс Statement (package java.sql). Программа использует
объект Statement для того, чтобы представлять SQL в базу данных.
Строки 33–34 используют метод executeQuery объекта Statement object's для
предъявления запроса, который выбирает информацию обо всех авторах из таблицы
authors. Этот метод возвращает объект, который реализует интерфейс ResultSet и
содержит результаты запроса. Метод ResultSet позволяет программе обрабатывать
результаты запроса.
Строки 37–50 обрабатывают ResultSet. Строка 37 получает метаданные ResultSet как
объект ResultSetMetaData (java.sql). Метаданные описывают содержимое ResultSet.
Программа можетможет использовать метаданные программно для получения
информации об именах столбцов и типах ResultSet. Строка 38 использует метод
getColumnCount объекта ResultSetMetaData для получения количества столбцов в
ResultSet. Строки 41–42 показывают имена столбцов.
Строки 45–50 выводит данные из каждой строке ResultSet. Во-первых, программа
помещает курсор ResultSet (который указывает на обрабатываемую строку) на первую
строку ResultSet с помощью метода next (строка 45). Метод next возвращает значение
boolean равным true если имеется возможность установиться на следующую строку, в
противном случае, возвращается false. (Дело в том, что первоначально курсор ResultSet
устанавливается перед первой строкой.)
Если строки в ResultSet существуют, строка 48 выводит содержимое столбца (поля) в
текущей строке. Когда обрабатывается ResultSet, представляется возможным вывести
каждый столбец в соответствии с его типом. Фактически, метод getColumnType объекта
ResultSetMetaData возвращает целочисленную константу класса Types (java.sql),
5
показывающую тип определенного столбца. Программы могут использовать это значение
в утверждении switch, чтобы вызвать метод ResultSet , возвращающий значение
соответствующего типа. Если тип столбца Types.INTEGER, метод getInt объекта
ResultSet возвращает значение как int. Методы ResultSet обычно принимают качестве
аргумента либо номер столбца (как int) либо имя столбца (как String), показывающие
какое значение столбца получать.
Для простоты этот пример рассматривает каждое значение как Object. Программа
получает значение каждого столбца с помощью метода getObject объекта ResultSet
(строка 48) и выводит представление String для Object. Отметим, что в отличие от
индексов массива, которые начинаются с 0, столбцы ResultSet нумеруются с 1. Блок
finally (строки 56–68) закрывает ResultSet (строка 60), Statement (строка 61) и
Connection с базой данных (строка 62). [Замечание: Строки 60–62 будут выдавать
исключительную ситуацию NullPointerExceptions если объекты ResultSet, Statement
или Connection не были созданы корректно. В коде вам следует проверять переменные,
которые относятся к этим объектам, чтобы убедиться, что они являются null перед
выполнением close.]. Также имейте в виду, что указание столбца с номером 0 для
ResultSet вызывает SQLException.
Выполнение запросовбазы данных books
Следующий пример позволяет вводить любой запрос в в программу. Пример показывает
результаты запроса в a JTable, используя объект TableModel для обеспечения вывода
данных ResultSet в формате JTable. Как вам хорошо известно, JTable является
компонентом swing GUI, который может быть связан с базой данных для представления
результатов запроса. Класс ResultSetTableModel выполняет соединение с базой данных
через TableModel и поддерживает ResultSet. Класс DisplayQueryResults создает GUI и
определяет экземпляр класса ResultSetTableModel для обеспечения данных JTable.
TableModel , которая поставляет данные ResultSet для JTable.
1. ResultSetTableModel.java
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// A TableModel that supplies ResultSet data to a JTable.
import java.sql.Connection;
import java.sql.Statement;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import javax.swing.table.AbstractTableModel;
// ResultSet rows and columns are counted from 1 and JTable
// rows and columns are counted from 0. When processing
// ResultSet rows or columns for use in a JTable, it is
// necessary to add 1 to the row or column number to manipulate
// the appropriate ResultSet column (i.e., JTable column 0 is
// ResultSet column 1 and JTable row 0 is ResultSet row 1).
public class ResultSetTableModel extends AbstractTableModel
{
private Connection connection;
private Statement statement;
private ResultSet resultSet;
6
22
private ResultSetMetaData metaData;
23
private int numberOfRows;
24
25
// keep track of database connection status
26
private boolean connectedToDatabase = false;
27
28
// constructor initializes resultSet and obtains its meta data
object;
29
// determines number of rows
30
public ResultSetTableModel( String url, String username,
31
String password, String query ) throws SQLException
32
{
33
// connect to database
34
connection = DriverManager.getConnection( url, username, password
);
35
36
// create Statement to query database
37
statement = connection.createStatement(
38
ResultSet.TYPE_SCROLL_INSENSITIVE,
39
ResultSet.CONCUR_READ_ONLY );
40
41
// update database connection status
42
connectedToDatabase = true;
43
44
// set query and execute it
45
setQuery( query );
46
} // end constructor ResultSetTableModel
47
48
// get class that represents column type
49
public Class getColumnClass( int column ) throws
IllegalStateException
50
{
51
// ensure database connection is available
52
if ( !connectedToDatabase )
53
throw new IllegalStateException( "Not Connected to Database" );
54
55
// determine Java class of column
56
try
57
{
58
String className = metaData.getColumnClassName( column + 1 );
59
60
// return Class object that represents className
61
return Class.forName( className );
62
} // end try
63
catch ( Exception exception )
64
{
65
exception.printStackTrace();
66
} // end catch
67
68
return Object.class; // if problems occur above, assume type
Object
69
} // end method getColumnClass
70
71
// get number of columns in ResultSet
72
public int getColumnCount() throws IllegalStateException
73
{
74
// ensure database connection is available
75
if ( !connectedToDatabase )
76
throw new IllegalStateException( "Not Connected to Database" );
77
78
// determine number of columns
7
79
try
80
{
81
return metaData.getColumnCount();
82
} // end try
83
catch ( SQLException sqlException )
84
{
85
sqlException.printStackTrace();
86
} // end catch
87
88
return 0; // if problems occur above, return 0 for number of
columns
89
} // end method getColumnCount
90
91
// get name of a particular column in ResultSet
92
public String getColumnName( int column ) throws
IllegalStateException
93
{
94
// ensure database connection is available
95
if ( !connectedToDatabase )
96
throw new IllegalStateException( "Not Connected to Database" );
97
98
// determine column name
99
try
100
{
101
return metaData.getColumnName( column + 1 );
102
} // end try
103
catch ( SQLException sqlException )
104
{
105
sqlException.printStackTrace();
106
} // end catch
107
108
return ""; // if problems, return empty string for column name
109
} // end method getColumnName
110
111
// return number of rows in ResultSet
112
public int getRowCount() throws IllegalStateException
113
{
114
// ensure database connection is available
115
if ( !connectedToDatabase )
116
throw new IllegalStateException( "Not Connected to Database" );
117
118
return numberOfRows;
119
} // end method getRowCount
120
121
// obtain value in particular row and column
122
public Object getValueAt( int row, int column )
123
throws IllegalStateException
124
{
125
// ensure database connection is available
126
if ( !connectedToDatabase )
127
throw new IllegalStateException( "Not Connected to Database" );
128
129
// obtain a value at specified ResultSet row and column
130
try
131
{
132
resultSet.absolute( row + 1 );
133
return resultSet.getObject( column + 1 );
134
} // end try
135
catch ( SQLException sqlException )
136
{
137
sqlException.printStackTrace();
8
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
} // end catch
return ""; // if problems, return empty string object
} // end method getValueAt
// set new database query string
public void setQuery( String query )
throws SQLException, IllegalStateException
{
// ensure database connection is available
if ( !connectedToDatabase )
throw new IllegalStateException( "Not Connected to Database" );
// specify query and execute it
resultSet = statement.executeQuery( query );
// obtain meta data for ResultSet
metaData = resultSet.getMetaData();
// determine number of rows in ResultSet
resultSet.last(); // move to last row
numberOfRows = resultSet.getRow(); // get row number
// notify JTable that model has changed
fireTableStructureChanged();
} // end method setQuery
}
// close Statement and Connection
public void disconnectFromDatabase()
{
if ( connectedToDatabase )
{
// close Statement and Connection
try
{
resultSet.close();
statement.close();
connection.close();
} // end try
catch ( SQLException sqlException )
{
sqlException.printStackTrace();
} // end catch
finally // update database connection status
{
connectedToDatabase = false;
} // end finally
} // end if
} // end method disconnectFromDatabase
// end class ResultSetTableModel
Класс ResultSetTableModel
Класс ResultSetTableModel расширяет класс AbstractTableModel (javax.swing.table),
который реализует интерфейс TableModel. Класс ResultSetTableModel переопределяет
методы getColumnClass, getColumnCount, getColumnName, getRowCount and getValueAt
9
объекта TableModel. Реализация методов по умолчанию isCellEditable и setValueAt
(обеспечиваемых AbstractTableModel) объекта TableModel не переопределяются,
поскольку в этом примере не поддерживается редактирование ячеек JTable. Реализация
методов по умолчанию addTableModelListener и removeTableModelListener
(обеспечиваемых AbstractTableModel) объекта TableModel не переопределяются,
поскольку реализация этих методов в AbstractTableModel правильно добавляет и удаляет
слушателей событий.
Конструктор ResultSetTableModel (строки 30–46) принимает четыре аргумента String—
URL на базу данных, имя пользователя, пароль и запрос по умолчанию для выполнения.
Конструктор вырабатывает все исключительные ситуации, которые происходят в его теле
обратно в приложение, которое создало объект ResultSetTableModel для того, чтобы
приложение могло определять, как обрабатывать эти исключительные ситуации
(например, сообщать от ошибке, завершать приложение). Строка 34 устанавливает
соединение с базой данных. Строки 37–39 вызывают метод createStatement объекта
Connection для создания объекта Statement. Этот пример использует версию метода
createStatement, который принимает два аргумента – тип и параллельность
результирующего набора данных. Тип результирующего набора данных (См. Таблицу
внизу) определяет способен ли курсор перемещаться в обоих направлениях или только
вперед, и является ли ResultSet чувствительным к изменениям, в том смысле, что
отражает он (ResultSet) либо не отражает изменения в ResultSet немедленно после того,
как они сделаны с помощью методов интерфейса ResultSet. Если ResultSet не
чувствителен к изменениям, то запрос, который произвел ResultSet должен быть
выполнен снова , чтобы отразить эти изменения. Одновременность результирующего
набора данных (concurrency) определяет может ли ResultSet быть изменен с помощью
методов изменения ResultSet.Этот пример использует ResultSet , который
прокручивается, не чувствителен к изменениям и только для чтения. Строка 45 вызывает
наш метод setQuery (строки 144–163) для выполнения запроса по умолчанию.
Типы констант. ResultSet для определения ResultSet type.
константа ResultSet
static type
Описание
TYPE_FORWARD_ONLY
Specifies that a ResultSet's cursor can move only in the forward
direction (i.e., from the first to the last row in the ResultSet).
TYPE_SCROLL_INSENSITIVE
Specifies that a ResultSet's cursor can scroll in either direction and
that the changes made to the ResultSet during ResultSet
processing are not reflected in the ResultSet unless the program
queries the database again.
TYPE_SCROLL_SENSITIVE
Specifies that a ResultSet's cursor can scroll in either direction and
that the changes made to the ResultSet during ResultSet
processing are reflected immediately in the ResultSet.
10
Константы ResultSet для задания свойств результата.
ResultSet static
concurrency constant
Описание
CONCUR_READ_ONLY
Specifies that a ResultSet cannot be updated (i.e., changes to the
ResultSet contents cannot be reflected in the database with
ResultSet's update methods).
CONCUR_UPDATABLE
Specifies that a ResultSet can be updated (i.e., changes to the
ResultSet contents can be reflected in the database with
ResultSet's update methods).
Попытка изменить ResultSet, когда драйвер базы данных не
поддерживает изменение ResultSets вызывает
SQLFeatureNotSupportedExceptions.
Попытка переместить курсор назад в ResultSet когда драйвер базы
данных не поддерживает изменение ResultSets вызывает обратный скроллинг
вызывает SQLException.
Метод getColumnClass (строки 49–69) возвращает объект a Class , который представляет
суперкласс всех объектов в определеннoм столбце. JTable использует эту информацию
для конфигурации оформителя ячейки по умолчанию и редактора ячейки в JTable.
Строка 58 использует метод getColumnClassName объекта ResultSetMetaData для
получения имени класса для полной спецификации определенного столбца. Строка 51
загружает класс и возвращает соответствующий объект Class. В случае исключения,
catch линии 63–66 выводят стек вызовов, и строка 68 возвращает Object.class—
экземпляр Class который представляет класс Object—как тип по умолчанию. [Замечание:
Строка 58 использует аргумент column + 1. Аналогично массивам, номера строк и
столбцов JTable отсчитываются с 0. Однако, строки и столбцы ResultSet отсчитываются
с 1. Таким образом, при обработке строк или столбцов ResultSet для использования в
JTable, необходимо добавлять 1 к номеру строки или столбца для обработки
соответствующих строк и столбцов ResultSet.]
Метод getColumnCount (строки 72–89) возвращают номер столбцов в модели
рассматриваемого ResultSet. Строка 81 использует method getColumnCount метод
ResultSetMetaData для получения для получения номера столбца в ResultSet. В случае
исключения, строки 83–86 блока catch выводят стек вызовов, а строка 88 возвращает 0 в
качестве номера столбца по умолчанию.
Метод getColumnName (строки 92–109) возвращает имя столбцов в действующей модели
ResultSet. Строка 101 использует метод getColumnName объекта ResultSetMetaData для
11
получения имен столбцов из ResultSet. В случае исключения, строки 103–106 блока
catch выводят стек вызовов и строка 108 возвращает пустую строку в качестве имени
столбца по умолчанию.
Метод getRowCount (строки 112–119) возвращает номера строк в действующей модели
рассматриваемого ResultSet. Когда метод setQuery (строки 144–163) выполняет запрос,
он запоминает количество строк в переменной numberOfRows.
Метод getValueAt (строки 122–141) возвращает Object для определенной строки и
столбца в действующей модели рассматриваемого ResultSet. Строка 132 использует
метод absolute объекта ResultSet для установки курсора ResultSet на заданную строку.
Строка 133 использует метод getObject объекта ResultSet для получения Object в
определенном столбце текущей строки. В случае исключения, строки 135–138 блока
catch выводят стек вызовов и строка 140 возвращает пустую строку в качестве значения
по умолчанию.
Когда метод setQuery (строки 144–163) выполняет запрос и, он получает в качестве
аргумента запрос для получения нового ResultSet (строка 152). Строка 155 получает
ResultSetMetaData для нового ResultSet. Строка 158 использует метод last объекта
ResultSet для установки положения курсора ResultSet на последнюю запись ResultSet.
[Замечание: Если таблица содержит много строк, ее загрузка может оказаться медленной.]
Строка 159 использует метод getRow объекта ResultSet для получения номера строки для
текущей строки в ResultSet. Строка 162 вызывает метод fireTableStructureChanged
(наследуемый от класса AbstractTableModel) для оповещения каждой JTable ,
использующей этот объект ResultSetTableModel в случае если структура модели
изменяется. Это является причиной перегрузки строк и столбцов JTable на основании
новых данных из ResultSet. Метод setQuery возвращает все исключения, которые
происходят в теле, обратно в приложение, которое вызывает setQuery.
Метод disconnectFromDatabase (строки 166–186) реализует соответсвующий метод
завершения для класса ResultSetTableModel. Разработчик класса должен обеспечить
public метод , который клиенты класса должны вызывать явно для того, чтобы
освободить ресурсы, которые использует объект. В этом случае метод
disconnectFromDatabase закрывает ResultSet, Statement и Connection (строки 173–
175), которые рассматриваются как ограниченные ресурсы. Клиенты класса
ResultSetTableModel должны всегда вызывать этот метод, когда экземпляр этого класса
больше не требуется. Перед высвобождением ресурсов строка 168 проверяет является ли
соединение уже завершенным. Если нет, то метод выполняется. Отметим, что все другие
методы в классе ResultSetTableModel вызывают IllegalStateException если
connectedToDatabase равно false. Метод disconnectFromDatabase устанавливает
connectedToDatabase равным false (строка 183) для обеспечения того, чтобы клиент не
использовал экземпляр ResultSetTableModel после его завершения.
IllegalStateException является исключением библиотек Java, которые соответствуют
обнарущению этого типа ошибок.
Класс DisplayQueryResults
12
Класс DisplayQueryResults реализует графический интерфейс приложения и
взаимодействует с ResultSetTableModel через объект JTable. Это приложение также
показывает возможности сортировки и фильтрации, введенные в Java SE 6.
Показывает содержимое базы данных books.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// DisplayQueryResults.java
// Display the contents of the Authors table in the books database.
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.sql.SQLException;
import java.util.regex.PatternSyntaxException;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.JTable;
import javax.swing.JOptionPane;
import javax.swing.JButton;
import javax.swing.Box;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.RowFilter;
import javax.swing.table.TableRowSorter;
import javax.swing.table.TableModel;
public class DisplayQueryResults extends JFrame
{
// database URL, username and password
static final String DATABASE_URL = "jdbc:mysql://localhost/books";
static final String USERNAME = "javafp";
static final String PASSWORD = "javafp";
// default query retrieves all data from authors table
static final String DEFAULT_QUERY = "SELECT * FROM authors";
private ResultSetTableModel tableModel;
private JTextArea queryArea;
// create ResultSetTableModel and GUI
public DisplayQueryResults()
{
super( "Displaying Query Results" );
// create ResultSetTableModel and display database table
try
{
// create TableModel for results of query SELECT * FROM authors
tableModel = new ResultSetTableModel( DATABASE_URL,
USERNAME, PASSWORD, DEFAULT_QUERY );
// set up JTextArea in which user types queries
queryArea = new JTextArea( DEFAULT_QUERY, 3, 100 );
queryArea.setWrapStyleWord( true );
queryArea.setLineWrap( true );
JScrollPane scrollPane = new JScrollPane( queryArea,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
13
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );
// set up JButton for submitting queries
JButton submitButton = new JButton( "Submit Query" );
// create Box to manage placement of queryArea and
// submitButton in GUI
Box boxNorth = Box.createHorizontalBox();
boxNorth.add( scrollPane );
boxNorth.add( submitButton );
// create JTable delegate for tableModel
JTable resultTable = new JTable( tableModel );
JLabel filterLabel = new JLabel( "Filter:" );
final JTextField filterText = new JTextField();
JButton filterButton = new JButton( "Apply Filter" );
Box boxSouth = boxNorth.createHorizontalBox();
boxSouth.add( filterLabel );
boxSouth.add( filterText );
boxSouth.add( filterButton );
// place GUI components on content pane
add( boxNorth, BorderLayout.NORTH );
add( new JScrollPane( resultTable ), BorderLayout.CENTER );
add( boxSouth, BorderLayout.SOUTH );
// create event listener for submitButton
submitButton.addActionListener(
new ActionListener()
{
// pass query to table model
public void actionPerformed( ActionEvent event )
{
// perform a new query
try
{
tableModel.setQuery( queryArea.getText() );
} // end try
catch ( SQLException sqlException )
{
JOptionPane.showMessageDialog( null,
sqlException.getMessage(), "Database error",
JOptionPane.ERROR_MESSAGE );
// try to recover from invalid user query
// by executing default query
try
{
tableModel.setQuery( DEFAULT_QUERY );
queryArea.setText( DEFAULT_QUERY );
} // end try
catch ( SQLException sqlException2 )
{
JOptionPane.showMessageDialog( null,
sqlException2.getMessage(), "Database error",
JOptionPane.ERROR_MESSAGE );
// ensure database connection is closed
14
117
tableModel.disconnectFromDatabase();
118
119
System.exit( 1 ); // terminate application
120
} // end inner catch
121
} // end outer catch
122
} // end actionPerformed
123
} // end ActionListener inner class
124
); // end call to addActionListener
125
126
final TableRowSorter< TableModel > sorter =
127
new TableRowSorter< TableModel >( tableModel );
128
resultTable.setRowSorter( sorter );
129
setSize( 500, 250 ); // set window size
130
setVisible( true ); // display window
131
132
// create listener for filterButton
133
filterButton.addActionListener(
134
new ActionListener()
135
{
136
// pass filter text to listener
137
public void actionPerformed( ActionEvent e )
138
{
139
String text = filterText.getText();
140
141
if ( text.length() == 0 )
142
sorter.setRowFilter( null );
143
else
144
{
145
try
146
{
147
sorter.setRowFilter(
148
RowFilter.regexFilter( text ) );
149
} // end try
150
catch ( PatternSyntaxException pse )
151
{
152
JOptionPane.showMessageDialog( null,
153
"Bad regex pattern", "Bad regex pattern",
154
JOptionPane.ERROR_MESSAGE );
155
} // end catch
156
} // end else
157
} // end method actionPerfomed
158
} // end annonymous inner class
159
); // end call to addActionLister
160
} // end try
161
catch ( SQLException sqlException )
162
{
163
JOptionPane.showMessageDialog( null, sqlException.getMessage(),
164
"Database error", JOptionPane.ERROR_MESSAGE );
165
166
// ensure database connection is closed
167
tableModel.disconnectFromDatabase();
168
169
System.exit( 1 ); // terminate application
170
} // end catch
171
172
// dispose of window when user quits application (this overrides
173
// the default of HIDE_ON_CLOSE)
174
setDefaultCloseOperation( DISPOSE_ON_CLOSE );
175
176
// ensure database connection is closed when user quits
application
15
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
addWindowListener(
new WindowAdapter()
{
// disconnect from database and exit when window has closed
public void windowClosed( WindowEvent event )
{
tableModel.disconnectFromDatabase();
System.exit( 0 );
} // end method windowClosed
} // end WindowAdapter inner class
); // end call to addWindowListener
} // end DisplayQueryResults constructor
// execute application
public static void main( String args[] )
{
new DisplayQueryResults();
} // end main
} // end class DisplayQueryResults
16
Строки 27–29 и 32 объявляют URL, имя пользователя, пароль и запроспо умолчанию,
который передается в конструктор ResultSetTableModel для того, чтобы установить
начальное соединение с базой данных и выполнить запрос по умолчанию. Конструктор
DisplayQueryResults (строки 38–189) создает объект ResultSetTableModel и
графический интерфейс приложения. Строка 68 создает объект JTable и передает объект
в конструктор JTable, который затем регистрирует JTable в качестве слушателя (listener)
для TableModelEvent, сгенерированного ResultSetTableModel.
Строки 85–124 регистрируют обработчик для кнопки submitButton , которую
пользователь нажимает для отправления запроса в базу данных. Когда пользователь
нажимает на кнопку, то метод actionPerformed (строки 90–122) вызывает метод
setQuery в классе ResultSetTableModel для выполнения нового запроса. Если запрос
пользователя некорректный (например, содержит синтаксические ошибки), строки 107–
108 выполняют запрос по умолчанию. Если и этот запрос некорректен, предполагается
более серьезная ошибка, и строка 117 обеспечивает закрытие соединения с базой данных,
а строка 119 – выход из программы. Скриншоты экранов, представленные выше
показывают результаты двух запросов. Первый экран показывает запрос по умолчанию,
который возвращает все данные из таблицы authors базы данных books. Второй экран
показывает имя и фамилию каждого автора из таблицы authors и дополнительно
выводит название и номер издания из таблицы titles. Попытайтесь ввести свои
собственные запросы и выполнить их, нажав кнопку Submit Query.
В Java SE 6, JTables в настоящее время позволяет пользователям сортировать строки в
соответствии с данными определенного столбца. Строки 126–127 используют класс
TableRowSorter (из пакета javax.swing.table) для создания объекта, который
использует ваш объект ResultSetTableModel для сортировки строк в JTable, которые
представляются в результате запроса. Когда пользователь кликает на заголовок
некоторого столбца JTable, то TableRowSorter взаимодействует с моделью TableModel,
для переупорядочения строк на основе данных этого столбца.. Строка 128 использует
метод setRowSorter объекта JTable для определения TableRowSorter для resultTable.
Также JTable сожжет в настоящее время показывать подмножество данных из
действующей модели TableModel. Это рассматривается как фильтрация данных. Строки
133–159 регистрируют обработчик событий для кнопки filterButton кот для выполнения
фильтрации данных. В методе actionPerformed (строки 137–157), строка 139 получает
текст фильтра. Если пользователь не определил текст фильтрации, то строка 142
использует метод setRowFilter объекта JTable для удаления любого ранее
установленного фильтра в значение null. В противном случае, строка 147–148,
использует метод setRowFilter для определения RowFilter (из пакета javax.swing) на
основании пользовательского ввода. Класс RowFilter обеспечивает несколько методов
создания фильтров. static метод regexFilter получает String , содержащую шаблон
регулярного выражения в качестве аргумента и необязательный набор индексов, который
задает столбцы для фильтрации. Если индексы не определены, то просматриваются все
колонки. В нашем примере пользователем вводится шаблон регулярного выражения.
После установки фильтра изменяется содержание таблицы в JTable на основе
отфильтрованной TableModel.
17
Download