Сетевые приложения |
Аплет FormНа примере аплета Form мы покажем, как приложения Java могут взаимодействовать с расширениями сервера Web, такими как программы CGI или приложения ISAPI. В окне нашего аплета находится форма, содержащая два однострочных поля редактирования, кнопку и многострочное поле редактирования (рис. 5). Рис. 5. Окно аплета Form Эта форма предназначена для добавления записей в базу данных, содержащую электронные почтовые адреса. Заполнив поля имени и адреса E-Mail, пользователь должен нажать кнопку Send. При этом введенная информация будет передана расширению сервера CGI, который запишет ее в базу данных, а затем отправит обратно аплету. Сохраненные записи, полученные от программы CGI, аплет FORM отобразит в многострочном поле редактирования, как это показано на рис. 5. Исходные тексты аплета FormИсходные тексты аплета Form представлены в листинге 5. Листинг 5. Файл Form.java import java.applet.*; import java.awt.*; import java.net.*; import java.io.*; import java.util.*; public class Form extends Applet implements Runnable { private Thread m_store = null; TextField txtName; TextField txtEMail; TextArea txta; Button btnGetText; public void init() { Label lbName; Label lbEMail; Label lbPress; lbName = new Label("Enter your name:"); lbEMail = new Label( "Enter your E-Mail address:"); add(lbName); txtName = new TextField("Your name", 40); add(txtName); add(lbEMail); txtEMail = new TextField("your@email", 40); add(txtEMail); btnGetText = new Button("Send!"); add(btnGetText); txta = new TextArea(8, 65); add(txta); setBackground(Color.yellow); } public void paint(Graphics g) { setBackground(Color.yellow); Dimension dimAppWndDimension = getSize(); g.setColor(Color.black); g.drawRect(0, 0, dimAppWndDimension.width - 1, dimAppWndDimension.height - 1); } public boolean action(Event evt, Object obj) { Button btn; if(evt.target instanceof Button) { btn = (Button)evt.target; if(evt.target.equals(btnGetText)) { startTransaction(); } else return false; return true; } return false; } void startTransaction() { m_store = new Thread(this); m_store.start(); } public void stop() { if (m_store != null) { m_store.stop(); m_store = null; } } public void run() { URL u; URLConnection c; PrintStream ps; DataInputStream is; try { String szSourceStr = txtName.getText() + ", " + txtEMail.getText(); String szReceived; String szURL = "http://frolov/scripts/store.exe"; u = new URL(szURL); c = u.openConnection(); ps = new PrintStream( c.getOutputStream()); ps.println(szSourceStr); ps.close(); is = new DataInputStream( c.getInputStream()); szReceived = is.readLine(); is.close(); txta.appendText(szReceived + "\r\n"); repaint(); } catch (Exception ioe) { showStatus(ioe.toString()); stop(); } } } Исходный текст документа HTML, который был подготовлен для нас системой Java Workshop, мы немного отредактировали, изменив параметр CODEBASE (листинг 6). Листинг 6. Файл Form.tmp.html <applet name="Form" code="Form.class" codebase="http://frolov/" width="500" height="200" align="Top" alt="If you had a java-enabled browser, you would see an applet here."> <hr>If your browser recognized the applet tag, you would see an applet here.<hr> </applet> В этом параметре следует указать путь к каталогу, в котором располагается байт-код аплета. Описание исходныех текстов аплета FormПри инициализации метод init создает все необходимые органы управления и добавляет их в окно аплета. Когда пользователь заполняет форму и нажимает кнопку Send, обработчик соответствующего события вызывает метод startTransaction, запускающий процесс обмена данными с расширением сервера Web: if(evt.target.equals(btnGetText)) { startTransaction(); } Метод startTransaction, определенный в нашем приложении, создает и запускает на выполнение поток, который и будет взаимодействовать с программой CGI: void startTransaction() { m_store = new Thread(this); m_store.start(); } При этом в качестве отдельного потока, работающего одновременно с кодом аплета, выступает метод run. Именно в нем сосредоточена вся логика обмена данными с сервером Web. Так как в процессе взаимодействия могут возникать различные исключения, мы предусмотрели их обработку при помощи блока try-catch: URL u; URLConnection c; PrintStream ps; DataInputStream is; try { . . . } catch (Exception ioe) { showStatus(ioe.toString()); stop(); } Название возникшего исключения будет отображено в строке состояния браузера. Теперь о том, что делает метод run после получения управления. Первым делом он извлекает из однострочных текстовых полей имя и электронный адрес, объединяя их и записывая полученную текстовую строку в поле szSourceStr: String szSourceStr = txtName.getText() + ", " + txtEMail.getText(); В строке szURL находится адрес URL программы CGI: String szURL = "http://frolov/scripts/store.exe"; В реальном приложении этот адрес необходимо передавать аплету через параметр. Мы использовали непосредственное кодирование только для упрощения исходного текста. На следующем этапе метод run создает для программы CGI объект класса URL и открывает с ним соединение: u = new URL(szURL); c = u.openConnection(); Пользуясь этим соединением, метод run создает форматированный поток вывода, записывает в него строку имени и электронного адреса, а затем закрывает поток: ps = new PrintStream(c.getOutputStream()); ps.println(szSourceStr); ps.close(); Переданные таким образом данные попадут в стандартный поток ввода программы CGI, откуда она их и прочитает. Сделав это, программа CGI запишет в стандартный выходной поток строку ответа, которую необходимо прочитать в методе run нашего аплета. Для этого мы открываем входной поток, создаем на его основе форматированный входной поток данных, читаем одну строку текста и закрываем входной поток: is = new DataInputStream(c.getInputStream()); String szReceived; szReceived = is.readLine(); is.close(); Сразу после этого программа CGI завершит свою работу и будет готова к обработке новых запросов на добавление записей. Что же касается метода run, то он добавит полученную от расширения сервера текстовую строку в многострочное окно редактирования, как это показано ниже, а затем инициирует перерисовку окна аплета: txta.appendText(szReceived + "\r\n"); repaint(); Заметим, что использованный нами способ передачи данных подходит только для латинских символов. Если вам нужно передавать символы кириллицы, следует преобразовывать их из кодировки UNICODE, например, в гексадецимальную кодировку, а в программе CGI выполнять обратное преобразование. Аналогичную методику можно применять и для передачи произвольных двоичных данных. Исходный текст программы CGI store.exeИсходный текст программы CGI store.exe очень прост и показан в листинге 7. Листинг 7. Файл store.c #include <windows.h> #include <tchar.h> #include <wchar.h> #include <stdio.h> #include <stdlib.h> #include <string.h> void main(int argc, char *argv[]) { int nInDatasize; char * szMethod; char szBuf[2000]; FILE *fDatabase; CRITICAL_SECTION csAddRecord; szMethod = getenv("REQUEST_METHOD"); if(!strcmp(szMethod, "POST")); { nInDatasize = atoi( getenv("CONTENT_LENGTH")); fread(szBuf, nInDatasize, 1, stdin); szBuf[nInDatasize] = '\0'; InitializeCriticalSection(&csAddRecord); EnterCriticalSection(&csAddRecord); fDatabase = fopen("c:\\EMAIL.DAT", "a+"); if(fDatabase != NULL) { fputs(szBuf, fDatabase); fclose(fDatabase); } LeaveCriticalSection(&csAddRecord); DeleteCriticalSection(&csAddRecord); printf( "Content-type: text/plain\r\n\r\n"); printf("Stored information: %s", szBuf); } } Этот текст подготовлен для работы в среде Windows 95 или Windows NT, так как для синхронизации доступа к файлу мы использовали специфические для этих операционных систем функции работы с критическими секциями. Свою работу программа CGI начинает с анализа переменной среды REQUEST_METHOD. Убедившись, что при запуске программы ей передали данные методом POST, программа определяет размер этих данных исходя из содержимого переменной среды CONTENT_LENGTH. Далее программа считывает соответствующее количество байт данных из стандартного потока ввода, записывает их в файл. Затем, после добавления заголовка "Stored information:", программа CGI записывает полученную строку в стандартный выходной поток, передавая ее таким образом аплету Form. Так как при реальной работе в сети Internet вашу программу CGI могут одновременно запустить несколько пользователей, для синхронизации обновления файла базы данных мы применили критическую секцию. В результате с файлом может работать в любой момент времени только одна копия программы CGI. Еще одно замечание касается пути к файлу, который в нашем случае создается в корневом каталоге диска C:. При установке программы CGI на сервер вам необходимо обеспечить доступ на запись к каталогу, в котором располагается файл, для удаленных пользователей. О том, как это сделать, вы можете узнать из документации на ваш сервер Web. |