СТАТЬЯ
17.08.01

Создание Web-приложений с помощью C++Builder 5

Предыдущая часть

Наталия Елманова
КомпьютерПресс #2 2001

Статья была опубликована в КомпьютерПресс (www.cpress.ru)

Возврат дальше Применение баз данных в Web-приложениях

Мы можем создать код, позволяющий добавлять записи в какую-нибудь таблицу, в созданный ранее обработчик события WebModule1WebActionItem3Action (и таким образом действительно получить простейший список рассылки). Для этого необходимо добавить некоторые из компонентов доступа к данным в WebModule1 и установить соответствующие свойства (рис. 15):

Перепишем созданный ранее обработчик события WebModule1WebActionItem3Action:

void __fastcall TWebModule1::WebModule1WebActionItem3Action(
   TObject *Sender, TWebRequest *Request,
   TWebResponse *Response, bool &Handled)
{
   AnsiString CustName=Request->QueryFields->Values["T1"] +
      Request->ContentFields->Values["T1"];
   AnsiString CustEmail=Request->QueryFields->Values["T2"] +
      Request->ContentFields->Values["T2"];
   Table1->Open();
   Table1->Append();
   Table1->FieldByName("Name")->Value=CustName;
   Table1->FieldByName("E-mail")->Value=CustEmail;
   Table1->Post();
   Table1->Close();
   Response->Content=PageProducer2->Content();
}

Теперь наше приложение сохраняет пользовательский ввод в таблице базы данных. Чтобы убедиться в этом, можно скомпилировать, а затем протестировать приложение.

Мы рассмотрели простейший пример использования баз данных в Web-приложениях. Но, как правило, требуется публикация данных в Интернете и представление их в браузере. Для этой цели используются компоненты TDataSetTableProducer и TQueryTableProducer, получающие данные либо из компонентов TDataSet, либо c помощью запроса к базе данных и представляющие их в виде HTML-документа в табличном виде.

Для создания приложений, осуществляющих публикацию данных в Интернете, можно воспользоваться «мастером» DB Web Application Wizard со страницы Business репозитария объектов (рис. 16).

DB Web Application Wizard представляет собой последовательность диалоговых панелей, в которых следует выбирать базу данных, таблицу и публикуемые поля (рис. 17).

После заполнения всех форм мы получим компонент TWebModule, в который входяткомпоненты TTable (или TQuery), TSession и TDataSetPageProducer. Этого достаточно для создания простейшего приложения для публикации данных. Выглядеть оно будет примерно так, как показано на рис. 18.

Таблица, выбранная для этого примера (biolife.db из базы данных BCDEMOS), содержит графические поля. Рассмотрим варианты отображения их в таблице.

Один из способов решения этой проблемы — создание в таблице вычисляемого поля, содержащего соответствующий HTML-тэг со ссылкой на графический файл, полученный на основе изображения, извлеченного из соответствующей записи. Именно так мы и поступим. Кроме того, необходимо учитывать, что несколько человек могут обратиться к одной и той же таблице с разными запросами одновременно, поэтому конкретный пользователь не должен видеть в своем браузере изображения, которые ему не предназначены. Этого можно достичь, например, присвоив файлам с изображениями уникальные имена. Обработчик события OnCalcField для компонента Table1, реализующий этот прием, может выглядеть, например, так:

void __fastcall TWebModule1::Table1CalcFields(
   TDataSet *DataSet)
{
TDateTime DT = Now();
   Word hour,min,sec,msec;
   DecodeTime(DT,hour,min,sec,msec);
   //Создадим уникальный ID, основанный на текущем значении времени
   UserID=IntToStr(hour)+IntToStr(min)+IntToStr(sec)+IntToStr(msec);
   //Создадим уникальное имя для файла с изображением
   int i=random(1000000000);
   AnsiString FileName=UserID+"_"+IntToStr(i)+".JPG";
   //Save an image to a file
   TJPEGImage *JPG= new TJPEGImage;
   TPicture *P = new TPicture();
   P->Assign(Table1->FieldByName("Graphic"));
   JPG->Assign(P->Graphic);
   JPG->SaveToFile(FileName);
   Table1Picture->Value="<IMG SRC='"+FileName+"'>";
   &P->Free;
   &JPG->Free;
}

Необходимо также сослаться на соответствующий h-файл:

#include <vcl\jpeg.hpp>

Видимо, приведенный выше код нуждается в некоторых комментариях. При написании предполагалось, что вероятность извлечения какого-либо изображения двумя пользователями одновременно в течение одной и той же миллисекунды ничтожно мала. В этом случае можно сгенерировать имена файлов извлекаемых изображений, комбинируя величину, основанную на значении времени с точностью до миллисекунды, со случайным числом, которое уникально для каждой записи в данном сеансе работы пользователя, но, к сожалению, не уникально для нескольких пользователей одновременно.

Может возникнуть вопрос: почему файл с графическим изображением не удаляется в обработчике события OnCalcFields? Дело в том, что изображение может быть загружено в браузер намного позже, чем приложение завершит свою работу (особенно если пользователь имеет доступ в Интернет по обычной телефонной линии с помощью модемного соединения). Это означает, что файлы с изображениями после окончания работы приложения должны храниться на жестком диске Web-сервера. Поэтому удаляться они должны другим приложением либо просто другим экземпляром того же самого приложения, запущенным позже. Пример кода, реализующего удаление ненужных файлов с графическими изображениями в предположении, что для загрузки всех изображений в браузер конкретного пользователя достаточно десяти минут, приведен ниже:

void __fastcall TWebModule1::WebModuleCreate(TObject *Sender)
{
//Delete old *.JPG files
   TSearchRec sr;
if (FindFirst("*.JPG", faAnyFile, sr) == 0)
{
   do
      {
         if (Double(Now())-Double(FileDateToDateTime(sr.Time))>0.00694)
         //10 минут - это примерно 0.00694 часть дня
         DeleteFile(sr.Name);
      } while (FindNext(sr) == 0);
      FindClose(sr);
}
//инициализируем генератор случайных чисел
Randomize();
}

В обработчике события OnCrerate нашего объекта TWebModule удаляем все изображения, хранящиеся в каталоге Web-приложения более десяти минут, и инициализируем генератор случайных чисел.

Отметим, что каталог, в котором размещены файлы с графическими изображениями, должен быть доступен для чтения пользователями Интернета. Поскольку в нашем примере это тот же самый каталог, где находится исполняемый файл, не исключено, что для работоспособности этого приложения нужно внести соответствующие изменения в настройки каталогов Web-сервера — например, каталог Scripts Internet Information Services, где обычно помещают Web-приложения, по умолчанию такого разрешения не имеет. Однако с точки зрения безопасности более оправданно размещение файлов с изображениями в другом каталоге.

Наконец, щелкнем правой клавишей мыши на компоненте TDataSetTableProducer, выберем опцию Response Editor и изменим вид HTML-таблицы (рис. 19).

Можно, например, изменить свойства Cellpadding, Cellspacing, Border, BgColor HTML-таблицы, отвечающие за расстояние между ячейками, их цвет, толщину линий сетки. Кроме того, мы можем сгенерировать объекты THTMLTableColumn и изменить их свойства, что позволит установить свои правила отображения колонок таблицы и их заголовков.

Теперь можно сохранить, скомпилировать и протестировать приложение. Результат изображен на рис. 20.

Выполнение всех рассмотренных выше примеров возможно с помощью Delphi 5 и C++Builder 5 Enterprise и Professional, а также Delphi 4 и C++Builder 4 Enterprise. Пример, который будет рассмотрен в следующей части статьи, можно выполнить только посредством Delphi 5 и C++Builder 5 Enterprise, поскольку в нем использованы компоненты InternetExpress, отсутствующие в других версиях этих средств разработки.

Возврат дальше Интерактивные формы для редактирования данных

Вернемся ненадолго к примеру, в котором реализована форма ввода данных в таблицу, содержащую список рассылки. Если при работе с подобным приложеним пользователь введет в какие-либо поля формы некорректные данные, узнает он об этом только после отправки данных формы на Web-сервер и получения результата их обработки. Иными словами, интерактивность данного приложения невелика.

Несколько иначе обстоит дело с более интерактивным Web-приложением, которое позволяет, как минимум, не обращаться к серверу для проверки соответствия введенных данных каким-либо банальным требованиям типа отсутствия букв в числовом поле, а также контролирует корректность введенных данных в момент, когда фокус ввода покидает данное поле, а не когда вся запись отправляется на сервер. Пути достижения этой цели известны, и наиболее распространенным из них является применение скриптовых языков (VBScript или JavaScript). Фрагменты кода на этих языках, содержащие логику проверки корректности данных, могут находиться в HTML-странице, и при отображении в браузере они интерпретируются им, позволяя произвести такую проверку без обращения к серверу. В этом случае наше CGI- или ISAPI-приложение должно «уметь» генерировать страницы, содержащие код на одном из этих языков.

В принципе, при наличии времени и знаний одного из скриптовых языков создать интерактивный аналог приведенных выше примеров не так уж сложно. Однако при наличии Delphi 5 или C++Builder 5 Enterprise добиться интерактивности можно более простым способом. Этот способ заключается в применении компонентов InternetExpress, которые предназначены для создания MIDAS-клиентов, являющихся Web-приложениями. Подобные приложения обмениваются XML-данными с браузерами, поддерживающими интерпретацию кода JavaScript. Подробности о MIDAS-приложениях подобного типа можно узнать из статьи «MIDAS3: новые возможности» (КомпьютерПресс, № 1’2000).

Отметим, что применение компонентов InternetExpress не ограничено только «истинными» MIDAS-приложениями с отдельным сервером доступа к данным — с помощью этих компонентов можно создать Web-приложение, являющееся обычным клиентом серверной СУБД. Однако подобное приложение более интерактивно, чем традиционное HTML-приложение, и ниже мы увидим, в чем это выражается.

Итак, создадим простейшее приложение, иллюстрирующее применение компонентов InternetExpress. В этом примере мы поместим MIDAS-сервер и MIDAS-клиент в одно и то же приложение. Для этого создадим новое CGI-приложение и поместим компоненты TTable и TDataSetProvider в объект TWebModule — они представляют собой «серверную» часть этого приложения. Теперь необходимо установить значения свойств DatabaseName и TableName компонента Table1 (например, BCDEMOS и Customers.db). Далее следует установить значение свойства DataSet компонента DataSetProvider1 равным Table1 — это означает, что компонент Table1 теперь доступен для будущих MIDAS-клиентов.

Теперь поместим в тот же самый объект TWebModule компоненты TXMLBroker и TmidasPageProducer, представляющие собой «клиентскую» часть нашегоWeb-приложения. Первый из них отвечает за получение пакетов данных от MIDAS-сервера, а второй — за генерацию Web-страницы, направляемой в браузер. В данном примере MIDAS-сервер находится внутри нашего же приложения, поэтому установим значение свойства ProviderName компонента XMLBroker1 равным DataSetProvider1, оставив свойство RemoteServer пустым (рис. 21).

Далее необходимо выбрать пункт Web Page Editor из контекстного меню компонента MidasPageProducer1. Этот редактор свойств позволяет указать, какие интерфейсные элементы для отображения и редактирования данных нужно отображать в браузере. Например, добавим в него компонент DataForm с вложенными в него компонентами FiedlGroup и DataNavigator. Установим значение свойства XMLBroker компонента FieldGroup1 равным XMLBroker1, а свойства XMLComponent компонента DataNavigator1 — FieldGroup1 (рис. 22).

Следующим шагом будет установка значения свойства IncludePathURL компонента MidasPageProducer1. Это URL, где наше Web-приложение должно найти JavaScript- и HTML-файлы, используемые для генерации Web-страниц. Файлы *.js и *.html следует скопировать из каталога Cbuilder5\Source\Webmidas в каталог, соответствующий этому URL.

Следует заметить, что каталог Inetpub\Scripts, являющийся по умолчанию каталогом для Web-приложений Microsoft Internet Information Services и, следовательно, потенциальным местом для размещения нашего Web-приложения, — не самое подходящее место для данных файлов. Дело в том, что по умолчанию файлы из этого каталога можно запускать на выполнение, но они недоступны для чтения. Поэтому нужно изменить настройки этого каталога или, что более предпочтительно, использовать другой каталог.

Наконец, следует создать объект TWebActionItem, установить значение его свойства Default равным true, а значение свойства Producer — MidasPageProducer1. Наше приложение готово.

Теперь можно сохранить проект, скомпилировать его и перенести исполняемый файл в соответствующий каталог Web-сервера. Результат выполнения данного приложения показан на рис. 23.

Теперь осталось рассмотреть, почему полученное приложение более интерактивно, чем приложение, результат выполнения которого изображен на рис. 12. Анализ поведения последнего приложения показывает, что оно позволяет редактировать одновременно несколько записей, перемещаться между ними, использовать кнопки Undo или Post, добавлять и удалять записи – и все это без обращения к Web-серверу. Только нажатие кнопки ApplyUpdates инициирует новый запуск Web-приложения для того, чтобы сохранить внесенные пользователем изменения в базе данных. Если внимательно рассмотреть текст Web-страницы, генерируемый этим приложением, можно увидеть фрагменты кода JavaScript, а также XML-данные, соответствующие содержимому таблицы или запроса (их объем можно ограничить свойством MaxRecords компонента TXMLBroker). Поскольку код JavaScript интерпретируется браузером, а все необходимые данные содержатся внутри Web-страницы, при перемещении по записям и их редактировании нет необходимости обращаться к Web-серверу, пока пользователю не потребуется новая порция записей из базы данных. Это означает, что InternetExpress-приложения более интерактивны, чем HTML-приложения. 

Возврат Заключение

В данной статье мы рассмотрели создание наиболее часто встречающихся типов Web-приложений с помощью C++Builder. Изучили, как динамически генерировать Web-страницы, обрабатывать пользовательский ввод и сохранять его в базе данных, как публиковать данные в Интернете и организовать вывод графических изображений. Наконец, мы обсудили, как создать интерактивное Web-приложение для редактирования данных.

Следует заметить, что создание приложений подобного класса возможно с помощью не только средств разработки Borland, но и большинства других (Microsoft Visual Basic, Sybase PowerBuilder, Microsoft Visual FoxPro и т.д.). Названия классов, применяемых при генерировании таких приложений, могут быть иными, но основные принципы остаются примерно теми же, что и в приведенных примерах.

В заключение отметим, что CGI/ISAPI — не единственная технология создания Web-приложений, содержащих код, исполняемый на Web-сервере. В настоящее время все более популярной становится технология ASP (Active Server Pages), позволяющая включать результат выполнения серверного кода в Web-страницы. Подробнее об этом можно прочитать в других статьях, в частности в статье Сергея Трепалина «Создание серверных компонентов для ASP-приложений» на нашем CD-ROM.

Дополнительную информацию Вы можете получить в компании Interface Ltd.

Отправить ссылку на страницу по e-mail
Обсудить на форуме Inprise/Borland


Interface Ltd.
Тel/Fax: +7(095) 105-0049 (многоканальный)
Отправить E-Mail
http://www.interface.ru
Ваши замечания и предложения отправляйте автору
По техническим вопросам обращайтесь к вебмастеру
Документ опубликован: 17.08.01