В этой главе мы вкратце перечислим важные аспекты технологии Java, до сих пор не освещенные в книге, но необходимые для дальнейшего изложения.
Архиватор jar
Для упаковки нескольких файлов РІ РѕРґРёРЅ архивный файл, СЃРѕ сжатием или без сжатия, РІ технологии Java разработан формат архивирования JAR. РРјСЏ архивного jar-файла может быть любым, РЅРѕ обычно РѕРЅРѕ получает расширение jar. РЎРїРѕСЃРѕР± упаковки Рё сжатия основан РЅР° методе ZIP. Название JAR (Java ARchive) перекликается СЃ названием известной утилиты TAR (Tape ARchive), разработанной РІ UNIX.
Отличие jar-файлов от zip-файлов только в том, что в jar-файлы автоматически включается каталог META-INF, содержащий несколько файлов с информацией об упакованных в архив файлах.
Архивные файлы очень удобно использовать в апплетах, о чем уже говорилось в главе 18, поскольку весь архив загружается по сети сразу же, одним запросом. Все файлы апплета с байт-кодами, изображениями, звуковые файлы упаковываются в один или несколько архивов. Для их загрузки достаточно в теге
Основной файл MillAnim.class должен находиться в каком-либо из архивных файлов firstjar или second.jar. Остальные файлы отыскиваются в архивных файлах, а если не найдены там, то на сервере, в том же каталоге, что и HTML-файл. Впрочем, файлы апплета можно упаковать не только в jar-архив, но и в zip-архив со сжатием или без сжатия.
Архивные файлы удобно использовать и в приложениях (applications). Все файлы приложения упаковываются в архив, например appljar. Приложение выполняется прямо из архива, интерпретатор запускается с параметром jar, например:
java -jar appl.jar
РРјСЏ РѕСЃРЅРѕРІРЅРѕРіРѕ класса приложения, содержащего метод main(), указывается РІ файле MANIFEST.MF, речь Рѕ котором пойдет чуть позже.
При установке JDK на MS Windows автоматически создается ассоциация расширения имени файла jar с интерпретатором javaw, которая действует при двойном щелчке мыши по имени файла, а именно:
"C:\jre1.6.0 02\bin\javaw.exe" -jar "%1" %*
Если такой ассоциации нет, то ее легко создать средствами Windows.
Архивные файлы удобны и просты для компактного хранения всей необходимой для работы программы информации. Программа может работать с файлами архива прямо из архива, не распаковывая их, с помощью классов пакета java.util.jar.
Создание архива
Jar-архивы создаются с помощью классов пакета java.util.jar или посредством утилиты командной строки jar.
Правила использования утилиты jar очень похожи на правила применения утилиты tar. Набрав в командной строке слово jar и нажав клавишу
Рис. 25.1. Правила употребления утилиты jar |
Параметры утилиты jar меняются от версии к версии, на время написания книги они выглядели так:
jar {ctxui}[vfm0Me] [jar-file] [manifest-file] [entry-point] [-C dir] files...
Р’ этой строке зашифрованы правила применения утилиты. Фигурные СЃРєРѕР±РєРё показывают, что после слова jar Рё пробела надо написать РѕРґРЅСѓ РёР· Р±СѓРєРІ: c, t, x, u или i. Рти Р±СѓРєРІС‹ означают следующие операции:
□ c (create) — создать новый архив;
□ t (table of contents) — направить в стандартный вывод список содержимого архива;
□ x (extract) — извлечь из архива один или несколько файлов;
□ u (update) — обновить архив, заменив или добавив один или несколько файлов.
После буквы, без пробела, можно написать одну или несколько букв, перечисленных в квадратных скобках. Они означают следующее:
□ v (verbose) — выводить сообщения о процессе работы с архивом в стандартный вывод;
□ f (file) — записанный далее параметр jar-file показывает имя архивного файла;
□ m (manifest) — записанный далее параметр manifest-file показывает имя файла описания;
□ 0 (нуль) — не сжимать файлы, записывая их в архив;
□ m (manifest) — не создавать файл описания;
в–Ў e (entry) — используется РїСЂРё создании архива. Записанный далее параметр entry-point означает РёРјСЏ РѕСЃРЅРѕРІРЅРѕРіРѕ класса, содержащего метод main(), СЃ которого начинается выполнение программы. Рто РёРјСЏ будет занесено РІ создаваемый файл MANIFEST.MF (СЃРј. далее).
Параметр -i (index) предписывает создать в архиве файл INDEX.LIST. Он используется уже после формирования архивного файла.
После буквенных параметров-файлов через пробел записывается имя архивного файла jar-file, потом, через пробел, имя файла описания manifest-file, далее, после пробела, имя основного класса entry-point, затем перечисляются имена файлов, которые надо занести в архив или извлечь из архива. Если это имена каталогов, то операция выполняется рекурсивно со всеми файлами каталога.
Перед первым именем каталога может стоять параметр -с. Конструкция -c dir означает, что на время выполнения утилиты jar текущим каталогом станет каталог dir.
Необязательные параметры занесены в квадратные скобки.
Ртак, РІ конце командной строки должно быть записано хотя Р±С‹ РѕРґРЅРѕ РёРјСЏ файла или каталога. Если среди параметров есть Р±СѓРєРІР° f, то первый РёР· этих файлов понимается как архивный jar-файл. Если среди параметров находится Р±СѓРєРІР° m, то первый файл понимается как файл описания (manifest-file). Если среди параметров присутствуют РѕР±Рµ Р±СѓРєРІС‹, то РёРјСЏ архивного файла Рё РёРјСЏ файла описания должны идти РІ том же РїРѕСЂСЏРґРєРµ, что Рё Р±СѓРєРІС‹ f Рё m.
Если параметр f и имя архивного файла отсутствуют, то архивным файлом будет служить стандартный вывод.
Если параметр m и имя файла описания отсутствуют, то по умолчанию файл MANIFEST.MF, лежащий в каталоге META-INF архивного файла, будет содержать только номер версии.
На рис. 25.2 показан процесс создания архива Base.jar в каталоге ch3.
Сначала показано содержимое каталога ch3. Затем создается архив, в который включается файл Base.class и все содержимое подкаталога classes. Снова выводится содержимое каталога ch3. В нем появляется файл Base.jar. Потом выводится содержимое архива.
Как видите, в архиве создан каталог META-INF, а в нем файл MANIFEST.MF.
Рис. 25.2. Работа с утилитой j ar |
Файл описания MANIFEST.MF
Файл MANIFEST.MF, расположенный в каталоге META-INF архивного файла, предназначен для нескольких целей:
□ перечисления файлов из архива, снабженных цифровой подписью;
□ перечисления компонентов JavaBeans, расположенных в архиве;
□ указания имени основного класса для выполнения приложения из архива;
□ указания имени файла, содержащего изображение загрузочного окна;
□ записи сведений о версии пакета.
Вся информация сначала записывается в обычном текстовом файле с любым именем, например manif. Потом запускается утилита jar, в которой этот файл указывается как значение параметра m, например:
jar cmf manif Base.jar classes Base.class
Утилита проверяет правильность записей в файле manif и переносит их в файл MANIFEST.MF, добавляя свои записи.
Файл описания manif должен быть написан по строгим правилам, изложенным в спецификации JAR File Specification. Ее можно найти в документации Java SE, в файле docs/technotes/guides/j ar/j ar.html.
Например, если мы хотим выполнять приложение с главным файлом Base.class из архива Base.jar, то файл manif должен содержать как минимум две строки:
Main-Class: Base
Первая строка содержит относительный путь к главному классу, но не к файлу, т. е. без расширения class. В этой строке каждый символ имеет значение, даже пробел. Вторая строка пустая — файл обязательно должен заканчиваться пустой строкой, точнее говоря, символом перевода строки '\n'.
РРјСЏ файла, например name.gif, СЃ изображением для загрузочного РѕРєРЅР° (splash screen) указывается строкой
SplashScreen-Image: name.gif
После того как создан архив Base.jar, можно выполнять приложение прямо из него:
java -jar Base.jar
Файл INDEX.LIST
Для ускорения РїРѕРёСЃРєР° файлов Рё более быстрой РёС… загрузки можно создать файл РїРѕРёСЃРєР° INDEX.LIST. Рто делается после формирования архива. Утилита jar запускается еще раз СЃ параметром -i, например:
jar -i Base.jar
После этого в каталоге META-INF архива появляется файл INDEX.LIST. На рис. 25.3 представлено, как создается файл поиска и как выглядит содержимое архива после его создания.
Рис. 25.3. Создание файла поиска |
Компоненты JavaBeans
РњРЅРѕРіРёРµ программисты предпочитают разрабатывать приложения СЃ графическим интерфейсом пользователя СЃ помощью визуальных средств разработки IDE (Integrated Development Environment), таких как NetBeans, IntelliJ IDEA, Eclipse, JBuilder Рё РґСЂ. Рти средства позволяют помещать компоненты РІ контейнер графически, СЃ помощью мыши.
В окне приложения центральное место занимает форма, на которой размещаются компоненты. Сами компоненты показаны ярлыками на панели компонентов, расположенной обычно выше формы или сбоку от формы.
Чтобы поместить компонент на форму, надо щелкнуть кнопкой мыши на ярлыке компонента, перенести курсор мыши в нужное место формы и щелкнуть кнопкой мыши еще раз.
Далее следует определить свойства (properties) компонента: текст, цвет текста и фона, вид курсора мыши, когда он появляется над компонентом. Свойства определяются в окне свойств, расположенном обычно справа от формы. Окно свойств появляется чаще всего при выборе пункта меню Properties из контекстного меню, появляющегося при щелчке правой кнопкой мыши на компоненте. В левой колонке окна свойств перечислены имена свойств, в правую колонку надо записать их значения.
Потом можно задать обработку событий, открыв вторую страницу окна свойств или выбрав соответствующий пункт контекстного меню.
Для того чтобы компонент можно было применять РІ таком визуальном средстве разработки, как Eclipse, РѕРЅ должен обладать дополнительными качествами. РЈ него должен быть ярлык, помещаемый РЅР° панель компонентов. Среди полей компонента должны быть выделены свойства (properties), которые Р±СѓРґСѓС‚ показаны РІ РѕРєРЅРµ свойств. Следует определить методы доступа getXxx ()/setXxx()/isXxx() Рє каждому свойству. Ртими методами будет пользоваться IDE, чтобы определить свойства компонента.
Компонент, снабженный этими и другими необходимыми качествами, в технологии Java называется компонентом JavaBean. В него может входить один или несколько классов. Как правило, файлы этих классов упаковываются в jar-архив и отмечаются в файле MANIFEST.MF как Java-Bean: True.
Все компоненты AWT и Swing являются компонентами JavaBeans. Если вы создаете свой графический компонент по правилам, изложенным в части III, то вы тоже получаете свой JavaBean. Но для того чтобы не упустить каких-либо важных качеств JavaBeans, лучше использовать для их разработки специальные средства, входящие в состав всех IDE, например, в NetBeans.
Последние изменения правил создания JavaBeans и примеры даны в документации Java SE, в каталоге technotes/guides/beans.
Правила оформления компонентов JavaBeans изложены в спецификации JavaBeans API Specification, которую можно найти по адресу:
.
Визуальные средства разработки — это не основное применение JavaBeans. Главное достоинство компонентов, оформленных как JavaBeans, в том, что они без труда встраиваются в любое приложение. Более того, приложение можно собрать из готовых JavaBeans как из строительных блоков, остается только настроить их свойства.
Специалисты пророчат большое будущее компонентному программированию. РћРЅРё считают, что СЃРєРѕСЂРѕ Р±СѓРґСѓС‚ созданы тысячи компонентов JavaBeans РЅР° РІСЃРµ случаи жизни Рё программирование сведется Рє РїРѕРёСЃРєСѓ РІ Рнтернете нужных компонентов Рё СЃР±РѕСЂРєРµ РёР· РЅРёС… приложения.
Связь с базами данных через JDBC
В основном информация хранится не в файлах, а в базах данных. Приложение должно уметь связываться с базой данных для получения из нее информации или для помещения информации в базу данных. Дело здесь осложняется тем, что СУБД (системы управления базами данных) сильно отличаются друг от друга и совершенно по-разному управляют базами данных. Каждая СУБД предоставляет собственный набор функций для доступа к базам данных, и приходится для каждой СУБД писать свое приложение. Но что делать при работе по сети, когда неизвестно, какая СУБД управляет базой на сервере?
Выход был найден корпорацией Microsoft, создавшей набор интерфейсов ODBC (Open Database Connectivity) для СЃРІСЏР·Рё СЃ базами данных, оформленных как прототипы функций языка C. Рти прототипы одинаковы для любой СУБД, РѕРЅРё просто описывают набор действий СЃ таблицами базы данных. Р’ приложение, обращающееся Рє базе данных, записываются вызовы функций ODBC. Для каждой системы управления базами данных разрабатывается так называемый драйвер ODBC, реализующий эти функции для конкретной СУБД. Драйвер просматривает приложение, находит обращения Рє базе данных, передает РёС… СУБД, получает РѕС‚ нее результаты Рё подставляет РёС… РІ приложение. Рдея оказалась очень удачной, Рё использование ODBC для работы СЃ базами данных стало общепринятым.
Компания Sun подхватила эту идею Рё разработала набор интерфейсов Рё классов, названный JDBC, предназначенный для работы СЃ базами данных. Рти интерфейсы Рё классы составили пакет java.sql, Р° также пакет javax.sql Рё его подпакеты, входящие РІ Java SE.
"JDBC" — это не аббревиатура, а самостоятельное слово, хотя иногда расшифровывается как "Java Database Connectivity".
РљСЂРѕРјРµ классов СЃ методами доступа Рє базам данных для каждой СУБД необходим драйвер JDBC — промежуточная программа, реализующая интерфейсы JDBC методами данной СУБД. Драйверы JDBC РјРѕРіСѓС‚ быть написаны разработчиками СУБД или независимыми фирмами. Р’ настоящее время написано несколько сотен драйверов JDBC для разных СУБД РїРѕРґ разные РёС… версии Рё платформы. РС… СЃРїРёСЃРѕРє можно посмотреть РЅР° странице или РЅР° JDBCVend.htm.
Существуют четыре типа драйверов JDBC:
в–Ў драйвер, реализующий методы JDBC вызовами функций ODBC. Рто так называемый РјРѕСЃС‚ (bridge) JDBC—ODBC. Непосредственную СЃРІСЏР·СЊ СЃ базой РїСЂРё этом осуществляет драйвер ODBC, который должен быть установлен РЅР° той машине, РЅР° которой работает программа;
□ драйвер, реализующий методы JDBC вызовами функций API самой СУБД. В этом случае на машине должен быть установлен клиент СУБД;
в–Ў драйвер, реализующий методы JDBC вызовами функций сетевого протокола, независимого РѕС‚ СУБД, например HTTP. Ртот протокол должен быть, затем, реализован средствами СУБД;
□ драйвер, реализующий методы JDBC вызовами функций сетевого протокола СУБД.
Перед обращением к базе данных следует установить нужный драйвер, например мост JDBC—ODBC:
try{
Class dr = sun.jdbc.odbc.JdbcOdbcDriver.class;
}catch(ClassNotFoundException e){
System.err.println("JDBC-ODBC bridge not found " + e);
}
Объект dr не понадобится в программе, но таков синтаксис.
Другой способ установки драйвера показан в листинге 25.1.
После того как драйвер установлен, можно связаться СЃ базой данных. Методы СЃРІСЏР·Рё описаны РІ интерфейсе Connection. Ркземпляр класса, реализующего этот интерфейс, можно получить РѕРґРЅРёРј РёР· статических методов getConnection( ) класса DriverManager, например:
String url = "jdbc:odbc:mydb";
String login = "admin";
String password = "1nF4vb";
Connection con = DriverManager.getConnection(url, login, password);
Обратите внимание на то, как формируется адрес базы данных url. Он начинается со строки "jdbc:", потом записывается подпротокол (subprotocol), в данном примере используется мост JDBC—ODBC, поэтому записывается "odbc:". Далее указывается адрес (subname) по правилам подпротокола, здесь просто имя локальной базы "mydb". Второй и третий аргументы — это имя и пароль для соединения с базой данных.
Связавшись СЃ базой данных, можно посылать запросы. Запрос хранится РІ объекте, реализующем интерфейс Statement. Ртот объект создается методом createStatement( ), описанным РІ интерфейсе Connection. Например:
Statement st = con.createStatement();
Затем запрос (query) заносится в этот объект методом execute () и потом выполняется методом getResultSet(). В простых случаях это можно сделать одним методом
executeQuery(), например:
ResultSet rs = st.executeQuery("SELECT name, code FROM tbl1");
Здесь из таблицы tbl1 извлекается содержимое двух столбцов name и code и заносится в объект rs класса, реализующего интерфейс ResultSet.
SQL-операторы insert, update, delete, create table и др. в простых случаях выполняются методом executeUpdate ().
Остается методом next () перебрать элементы объекта rs — строки полученной выборки - и извлечь данные многочисленными методами getXxx () интерфейса ResultSet, на
пример: while (rs.next()){
emp[i] = rs.getString("name"); num[i] = rs.getInt("code"); i++;
}
Методы интерфейса ResultSetMetaData позволяют узнать количество полученных столбцов, их имена и типы, название таблицы, имя ее владельца и прочие сведения о представленных в объекте rs сведениях.
Если объект st получен методом
Statement st = con.createStatement(ResultSet.TYPE SCROLL SENSITIVE,
ResultSet.CONCUR_UPDATABLE) ;
то можно перейти к предыдущему элементу выборки методом previous (), к первому элементу — методом first(), к последнему — методом last(). Можно также модифицировать объект rs методами updateXxx () и даже изменять, удалять и добавлять соответствующие строки базы данных. Не все драйверы обеспечивают эти возможности, поэтому надо проверить реальный тип объекта rs методами rs.getType() и
rs.getConcurrency().
Рнтерфейс Statement расширен интерфейсом PreparedStatement, позволяющим создавать предварительно откомпилированный запрос, перед выполнением которого можно задавать аргументы методами setXxx ().
Рнтерфейс PreparedStatement, РІ СЃРІРѕСЋ очередь, расширен интерфейсом CallableStatement, РІ котором описаны методы выполнения хранимых процедур.
В листинге 25.1 приведен типичный пример запроса к базе Oracle через драйвер Oracle Thin. Апплет выводит в окно браузера четыре поля ввода для адреса базы, имени и пароля пользователя, и запроса. По умолчанию формируется запрос к стартовой базе Oracle, расположенной на локальном компьютере. Результат запроса выводится в окно браузера.
Листинг 25.1. Апплет, обращающийся к базе Oracle
import java.awt.*; import java.awt.event.*; import java.applet.*; import java.util.*; import java.sql.*;
public class JdbcApplet extends Applet implements ActionListener, Runnable{ private TextField tf1, tf2, tf3; private TextArea ta; private Button b1, b2;
private String url = "jdbc:oracle:thin:@localhost:1521:ORCL",
login = "scott", password = "tiger",
query = "SELECT * FROM dept"; private Thread th; private Vector results;
public void init(){
setBackground(Color.white); try{
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); }catch(SQLException e){
System.err.println(e);
}
setLayout(null);
setFont(new Font("Serif", Font.PLAIN, 14));
Label 11 = new Label("URL базы:”, Label.RIGHT);
11. setBounds(20, 30, 70, 25); add(l1);
Label l2 = new Labe1(РїРРјСЏ:Рї, Label.RIGHT);
12. setBounds(20, 60, 70, 25); add(l2);
Label l3 = new Labe1(пПароль:п, Label.RIGHT);
13. setBounds(20, 90, 70, 25); add(l3); tf1 = new TextField(url, 30);
tf1.setBounds(100, 30, 280, 25); add(tf1); tf2 = new TextField(login, 30); tf2.setBounds(100, 60, 280, 25); add(tf2); tf3 = new TextField(password, 30); tf3.setBounds(100, 90, 280, 25); add(tf3); tf3.setEchoChar('*');
Label l4 = new Labe1(,,Запрос:,,, Label.LEFT);
14. setBounds(10, 120, 70, 25); add(l4);
ta = new TextArea(query, 5, 50, TextArea.SCROLLBARS NONE); ta.setBounds(10, 150, 370, 100); add(ta);
Button b1 = new Button(,,Отправить,,); b1.setBounds(280, 260, 100, 30); add(b1); b1.addActionListener(this);
}
public void actionPerformed(ActionEvent ae){ url = tf1.getText();
login = tf2.getText();
password = tf3.getText();
query = ta.getText();
if (th == null){
th = new Thread(this); th.start();
}
}
public void run(){ try{
Connection con = DriverManager.getConnection(url, login, password); Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query);
ResultSetMetaData rsmd = rs.getMetaData();
// Узнаем число столбцов int n = rsmd.getColumnCount(); results = new Vector();
while (rs.next()){
String s = " ";
// Номера столбцов начинаются с 1! for (int i = 1; i <= n; i++) s += " " + rs.getObject(i);
results.addElement(s);
}
rs.close(); st.close(); con.close(); repaint();
}catch(Exception e){
System.err.println(e);
}
repaint();
}
public void paint(Graphics g){ if (results == null){
g.drawString("Can't execute the query", 5, 30); return;
}
int y = 30, n = results.size();
for (int i = 0; i < n; i++)
g.drawString((String)results.elementAt(i), 5, y += 20);
}
}
Замечание по отладке
В главе 24 упоминалось, что для отладки сетевой программы удобно запустить и клиентскую, и серверную часть на одном компьютере, обращаясь к серверной части по адресу
127.0.0.1 или доменному имени localhost. Не забывайте, что апплет может связаться по сети только с тем хостом, откуда он загружен. Следовательно, на компьютере должен работать Web-сервер. Если Web-сервер прослушивает порт 8080, то чтобы загрузить HTML-страницу с апплетом, надо в браузере указывать адрес URL вида JdbcApplet.html. При этом учтите, что Web-сервер устанавливает свою иерархию каталогов, и каталог public на самом деле может быть каталогом usr/local/http/public или каким-нибудь другим.
Таким образом, JDBC позволяет проделать весь цикл работы с базой данных. Подробно со всеми возможностями JDBC можно познакомиться, прочитав спецификацию JDBC, имеющуюся по адресу: http://java.sun.com/products/jdbc/ .
В документации Java SE, в каталоге technotes/guides/jdbc/, есть ссылки на пособия по использованию JDBC.
Вопросы для самопроверки
1. Почему в Java создан свой формат архивирования JAR?
2. Нужно ли распаковывать jar-архивы для использования классов, содержащихся в них?
3. Можно ли упаковывать апплеты в j ar-архив?
4. Куда надо помещать jar-файлы для использования их в приложении?
5. Что такое JavaBeans: классы, интерфейсы, пакеты, правила оформления классов?
6. Что должно быть в классе, называемом JavaBean?
7. Где применяются JavaBeans?
8. Что такое JDBC?
9. Какие существуют типы драйверов JDBC?
10. Какие фирмы разрабатывают драйверы JDBC?
ГЛАВА 26