![]() |
![]() |
![]() | |
Сетевые приложения |
Аплет 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. |