Аплет Form

Оглавление Сетевые приложения Адрес IP Адрес URL Класс URL Сокеты Потоковые сокеты Класс Socket Датаграммные сокеты Связь с Web Аплет ShowChart Приложения SocketServ и SocketClient Аплет 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.

Назад Вперед