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