Аплет Form

Оглавление

Сетевые приложения
Адрес IP
Адрес URL
Класс URL
Сокеты
Потоковые сокеты
Класс Socket
Датаграммные сокеты
Связь с Web
Аплет ShowChart
Приложения SocketServ и SocketClient
Аплет Form

Назад Вперед

На примере аплета Form мы покажем, как приложения Java могут взаимодействовать с расширениями сервера Web, такими как программы CGI или приложения ISAPI.

В окне нашего аплета находится форма, содержащая два однострочных поля редактирования, кнопку и многострочное поле редактирования (рис. 5).

 

 

 

pic05.gif (4332 bytes)

Рис. 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.

Назад Вперед