Назад Вперед
На примере аплета 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. |