Web数据库服务系统包括一个Web浏览器作为用户界面,一个数据库服务器用作信息存储和数据采集,一个连接两者的Web应用服务器,Web应用软件出色地将数据陈述标准化,DBMS则组织和标准化数据库的接收与存储,Web浏览器通过TCP/IP与Web服务器相连,将页面请求与输入的数据发送给Web服务器,Web应用服务器把来自Web浏览器的请求转化为数据库服务器能接受的形式(SQL),传给数据库服务器,然后数据库服务器在数据库中进行相应的操作(插入、查询等),并把结果送回服务器扩展程序,数据库可以是应用服务器本地数据库,也可以是某个数据库服务器上的数据库。通过ODBC、BDE与Web服务器接口,最后,Web服务器程序将结果转化成Web浏览器能够接受的形式(如HTML文件),并发送回Web浏览器。在这样一个Web数据库服务系统中,用户只要在机器上安装了Web浏览器(如IE),就可通过Web页上显示的表格与数据库进行交互操作。
Web数据库服务系统如图1所示:
图1
创建Web服务器程序的具体步骤如下:
第一步 Delphi的客户机/服务器版本已经包括了Web服务器端开发的框架:在object repository的第一页(NEW)上,选择Web Server Application图标,随后出现的对话框会为用户提供三个选项,ISAPI、CGI、WinCGI,如图2所示:
图2
选取第一个,Delphi将为我们生成一个ISAPI应用程序的的基本结构。服务应用程序基于TWebmodule类,它派生自TWebDispatcher(此类定义了Request、Response属性,这两个属性存储了客户请求与将要发回用户端的响应),它是用来控制整个程序正确执行的,包含在其中的Action items用来获取有关用户请求信息,根据请求的路径名定义一系列行为(存储在Action数组属性中),这样,应用程序就可以轻松地响应不同路径名的请求,为每个可能的路径名调用不同的onAction事件处理程序,也就是说首先定义对应各种行为的路径名,然后定义对应着这些路径名的onAction事件处理程序。
第二步 编写事件处理程序时,将相应数据库操作加进去,Delphi提供了许多Internet与数据库操作组件,如TPageproducer、TQuerytableproducer、TDatasetpageprodure等,用这些组件可以方便地根据Request(用户请求),将查询信息转换为数据库查询命令传给数据库服务器,再将返回的数据库查询结果变成HTML页返回给用户,还可以将组件稍加修改,将接收到的Request作为数据源对服务器提供的数据库进行数据输入。另外在Webmodule中加入一个Session部件,并对其进行属性设置,用于数据库有多个链接时的管理,Session部件可以对程序中同时运行的多个实例进行完善的管理。下面以具体例子说明:
例:下面一例是一个简便的通讯录管理,将通讯录表在Web上发布,用户也可以从浏览器将自己的地址输入到通讯录中。此例中有三个路径名,相应有三个onAction事件处理,二个查询,一个输入,如图3所示。
图3
dllparse 数据库输入程序。dllquery 将数据库满足固定查询条件的数据发给浏览器的程序。dllshow 接收用户的查询条件,然后将满足条件的数据发给浏览器的程序。在Webmodule中,加入了Table、Query、Database、Session、PageProducer、Query
TableProducer、DataSetPageProduce,如图4所示。
图4
处理程序的编码如下:
unit Web1;
interface
uses
Windows, Messages, SysUtils, Classes, HTTPApp, DSProd, DBWeb, DBTables, Db;
type
TWebModule1 = class(TWebModule)
Table1: TTable;
Query1: TQuery;
Database1: TDatabase;
Session1: TSession;
PageProducer1: TPageProducer;
QueryTableProducer1: TQueryTableProducer;
DataSetPageProducer1: TDataSetPageProducer;
procedure PageProducer1HTMLTag(Sender: TObject; Tag: TTag;const TagString: String; TagParams: TStrings;var ReplaceText: String);
procedure WebModule1dllparseAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
procedure WebModule1dllqueryAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
procedure WebModule1dllshowAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;
var
WebModule1: TWebModule1;
implementation
{$R *.DFM}
{在TPageproducer中加入数据库输入功能,并返回给浏览器输入是否成功的标志页}
procedure
TWebModule1.PageProducer1HTMLTag(Sender: TObject; Tag: TTag;const TagString: String; TagParams: TStrings; var ReplaceText: String);
var
data:tstrings;
i:integer;
begin
data:=nil;
with request do
begin
case methodtype of
mtpost:data:=contentfields;
mtget:data:=queryfields;
end;
replacetext:=data.Values[tagstring];
{将数据库表打开,把浏览器传来的数据分别赋给表的各个字段,再将数据写入数据库。}
table1.Open;
try
table1.append;
for i:=0 to table1.fieldcount-1 do table1.fields[i.value:=data.values[table1.fields[i].fieldname];
table1.post;
except //意外处理,处理数据库主键唯一性//
raise exception.create(‘输入错误(姓名重复)');
end;
table1.close;
end;
end;
procedure
TWebModule1.WebModule1dllparseAction(Sender: TObject;Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
response.content:=pageproducer1.Content ;
end;
{根据在 QUERY 定义的查询,用 QueryTableProducer 从数据库获取符合条件的数据,生成HTML页发给用户。}
procedure
TWebModule1.WebModule1dllqueryAction(Sender: TObject;Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
with querytableproducer1 do begin
header.add(‘<html>') ;
header.add(‘<body>');
footer.add(‘</body>');
footer.add(‘</html>');
query:=query1;
query1.open;
response.content:= querytableproducer1.Content ;
query.Close;
end;
end;
{从Request中得到用户要查询的name,将符合条件的记录用DataSetPageproducer组件生成HTML文件发给浏览器}
procedure
TWebModule1.WebModule1dllshowAction(Sender: TObject;Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
data1:tstrings;
aa:string;
i:integer;
begin
data1:=nil;
with request do
begin
case methodtype of
mtpost:data1:=contentfields;
mtget:data1:=queryfields;
end;
end;
aa:=data1.values[‘name'];
for i:=length(aa)+1 to 10 do
aa:=aa+‘ ';
query1.params[0].asstring:=aa;
query1.open;
response.content:=datasetpageproducer1.content;
query1.close;
end;
end.
第三步 将编好的程序编译成DLL文件,在支持程序的服务器上调试,在HTML中调用。编程过程中需要注意的是:
1. 在Webmodule中加入Session组件,以保证程序能支持数据库的多个链、支持多个浏览器的同时访问同一数据库的同一个表。
2. 在定义Database时,注意将数据库登录提示log prompt设为n, keep inactiveconnection 设为n,以免用户在浏览器访问数据库时不能登录。