Database 版 (精华区)

发信人: mengy (LEAR DLLS 命令时,将从内存中清除), 信区: Database
标  题: Visual Foxpro 与ASP 相 结 合 开 发Web 数 据 库 应
发信站: 哈工大紫丁香 (2000年12月13日07:59:44 星期三), 站内信件


 

 

Visual Foxpro 与ASP 相 结 合 开 发Web 数 据 库 应 用 
重 庆 出 版 社 电 脑 中 心 陈 刚 
1 . VFP 与Web 数 据 库 应 用 ---- 作 为 最 成 功 的 大 众 数 据 库,
Foxpro 简 便 易 学, 有 广 大 的 用 户。 随 着VFP 5.0 的 推 出,VFP 已 
经 成 为 一 个 强 大 的 企 业 级 开 发 工 具。 它 不 仅 可 以 开 发 文 
件/ 服 务 器(F/S) 数 据 库 应 用, 也 可 以 开 发C/S 应 用, 这 时
VFP 作 为 一 个 前 端 工 具, 后 端 可 以 是SQL Server,Sybase 等 数 据
 库Engine。 通 过Remote View 和SQL Passthrough 函 数,VFP 可 以 像 操 作
 本 地 数 据 一 样, 方 便 地 处 理 服 务 器 端 数 据。 
---- 在Internet/ Intranet 影 响 日 益 巨 大 的 今 天, 开 发Web 数 据 库
 应 用 成 为 引 人 关 注 的 技 术。Web 数 据 库 应 用 有 一 个 天 然 的
 多 层C/S 结 构。 在 这 个 结 构 中, 客 户 端(Client) 仅 由Browser 组
 成, 几 乎 没 有 软 件 维 护 和 升 级 的 问 题。 来 自Client 的 请 求 
发 送 到Web Server, 我 们 只 须 开 发Web Server 端 软 件, 处 理 请 求
, 与 数 据 库 服 务 器 交 互、 并 把 结 果 返 回Client, 系 统 维 护 和
 升 级 非 常 方 便。 只 要 允 许, 任 意 一 个 客 户 都 可 以 通 过
Internet 或Intranet 访 问 我 们 的 数 据。 

---- VFP 完 全 具 备 开 发Web 数 据 库 应 用 的 能 力。 不 过 有 意 思 
的 是, 这 次VFP 被 推 到 了 后 台, 在 数 据 库 服 务 器 上 专 门 处 理
 数 据 存 取 和 实 现 商 业 逻 辑。 数 据 库 服 务 器 和Web Server 可 以
 运 行 在 同 一 个 网 络 服 务 器 上, 或 者 运 行 在 由 高 速 通 道 连
 接 的 两 台 网 络 服 务 器 上( 如NT Server), 这 样 网 络 传 输 瓶 颈
 不 再 存 在。 并 且 借 助NT Server 的 安 全 管 理, 客 户 并 不 能 直 
接 接 触VFP 数 据 库, 而 是 通 过Web Server 存 取 数 据,VFP 数 据 库 
的 安 全 特 性 得 以 大 大 提 高, 而 此 两 项 一 般 认 为 是VFP 的 重 
要 弱 点。 

2 . ASP(Active Server Page) 与 VFP 的 组 件 技 术 ---- Web 数 据 库 
应 用 可 以 由CGI、ISAPI、IDC、ASP 等 实 现。 其 中ASP 的 功 能 最 为 强
 大, 在 其 中 可 以 混 用HTML、DHTML、ActiveX、VBSsript 或JavaSript, 
特 别 是 可 以 使 用 服 务 器 端 组 件。 此 服 务 器 端 组 件 可 以 用
VFP、VB、VC++、Delphi 等 任 意 支 持COM 技 术 的 语 言 编 写, 以 实 现
 用 户 特 定 的 商 业 逻 辑。 如 果 不 出 意 外,ASP 将 成 为 主 流 技 
术。 目 前 有Microsoft 的IIS(Internet Information Server,NT Server) 
和PWS(Personel Web Server,Win95) 支 持ASP。 
---- 在 传 统 的F/S 或C/S 应 用 中, 组 件 作 为 面 向 对 象 的 编 程 风
 格, 你 可 以 随 自 己 的 喜 好, 采 用 或 不 采 用 它。 然 而 在ASP 中
 使 用VFP, 组 件( 一 个OLE Server DLL) 是 你 唯 一 的 选 择。 你 的 
处 理 过 程 都 应 封 装 在 一 个 或 多 个 组 件 中。 

3 . 使 用 的 环 境 和 工 具 ---- 对 于ASP , 需 要WinNT 4.0(Service 
Pack 3)、IIS 3.0(WinNT 自 带)、Visual InterDev1.0 。 也 可 以 是:
Win95、PWS(Visual InterDev1.0 中 提 供) 、Visual InterDev1.0。 
---- 为 了 使IIS 或 PWS 支 持ASP, 在 安 装Visual InterDev 时 必 须 首 
先 在 服 务 器 上 选 择 安 装 其 中 的Server Components:FrontPage 
Server Extensions 和 Active Server Pages, 然 后 在 开 发 服 务 器 上 安
 装Client Components:Visual InterDev Client。 也 可 以 把 这 些 都 安 
装 在 同 一 台 机 器 上, 这 样 可 以 在 单 机 上 方 便 地 编 程、 调 试
。 

4. VFP 组 件 的 实 现 ---- 在VFP 中 开 始 一 个Project, 取 名 为
Classes, 然 后 在 此Project 中 建 立 一 个Program, 取 名Classdef.prg。
 它 定 义 了 一 个OneRecord 类, 其 功 能 是 一 条 条 显 示 一 个 数 据
 库, 具 有 向 前、 向 后 和 定 位 能 力。 使 用 一 个DBF 文 件d:
\vfpweb\data\booksno.dbf, 结 构 为: 
Field_name Field_type Field_len
bookno  C   16
bookname C    50
author  C    12
editor  C   14
pubdate  D   8
charnum   N   4.0 

在Classdef.prg 中 键 入 代 码:
Define class onerecord as custom olepublic
mcDatapath=""
*---------------------------
function getdatapath
return (this.mcdatapath)
*---------------------------
function getcurrentno
return recno()
*---------------------------
function init
set exclu off
set century on
set date to ansi
return
*---------------------------
function  setdatapath
lparameter cpath
if type("cpath")<  >"C" 
return 
endif
this.mcdatapath=cpath
set defau to (cpath)
if not used("booksno")
select 0
use booksno
else
select booksno
endif 
return
*--------------------------
function movenext
if .not.eof() 
skip
endif
return 
*--------------------------
function moveprevious
if .not.bof() 
skip -1
endif
return
*--------------------------
function destroy
use
*clear all &&clear all 将 挂 起 服 务 器
return
*--------------------------
function iseof
if eof() 
return .t.
else
return .f.
endif
*--------------------------
function  isbof
if bof() 
return .t.
else
return .f.
endif
*--------------------------
function getbookno
return bookno
*--------------------------
function getpubdate
if empty(pubdate)
return ""
else
return pubdate
endif
*--------------------------
function geteditor
return editor
*--------------------------
function getbookname
return bookname
*--------------------------
function goto
lparameter recnum
if type("recnum")<  >"N"  &&error data type

return
endif
if recnum< 1 .or. recnum >reccount()
return
else
goto (recnum)
endif
return
EndDefine
---- 在 菜 单Project, 选 中 Set Main, 然 后Build , 在Build 对 话 框 
中 选Build OLE DLL。 好 了, 我 们 到 此 就 完 成 了 一 个OLE Server, 
并 且 它 已 经 自 动 注 册 在 我 们 的 机 器 上。 我 们 可 以 在 菜 单
Project | Project Info 弹 出 的Project Information 对 话 框 中 看 到 这
 个 组 件 的 信 息: 

Server Classes:onerecord
Project Name:Classes
OLE
---- Server 的 引 用 方 法 是createobject("ProjectName.ClassName"), 对 
于 我 们 这 个 组 件, 就 是:createobject("classes.onerecord")。 可 以 
直 接 在VFP 的Command 窗 口 中 交 互 式 地 测 试 之, 在Command 窗 口 中
 键 入: 

ox=createobject("classes.onerecord")
ox.setdatapath("d:\vfpweb\data")
?ox.bookname
?ox.getbookname
ox.movenext
?ox.getbookname
ox.goto(30)
?ox.getbookname
---- 可 以 直 接 看 到 执 行 结 果, 最 后 不 要 忘 了 释 放 该 组 件:
 

release ox
---- 这 个 组 件 是 针 对 特 定 数 据 库 进 行 操 作 的, 测 试 很 方 便
。 下 面, 我 们 再 实 现 一 个 更 为 一 般 的 类ClsQ2T, 其 功 能 是 任
 意 指 定 一 条SQL 查 询 语 句( 针 对 任 意 一 个 或 多 个 数 据 库),
 将 查 询 结 果 以 表 格 的 形 式 显 示 在Web 页 面 上, 其 中 使 用 了
ASP 的 接 口。 它 不 仅 封 装 了 数 据 处 理, 而 且 通 过ASP 接 口, 也
 封 装 了 数 据 显 示。 

---- 仍 在Classdef.prg 之 中, 接 着 最 后 一 行 代 码, 键 入: 

***************************************************
define class clsq2t as custom olepublic
mcontext=.null.
*-----------------------------------------
function onstartpage(ocontext)
this.mcontext=ocontext &&对ASP接口的引用
return
*-----------------------------------------
function init 
set exclu off
set safety off
return
*---------------------------------------------
function setdatapath(strpath)
merrnum=0
on error merrnum=error( )
set default to (strpath)
if merrnum<  >0 
return "Error in setdatapath"+message()+chr(13)
endif
on error
return "OK,setdatapath"+strpath+chr(13)
*-------------------------------------------------
*函数querytotable要求传入一个SQL Select串,如:
* "select bookname,editor from booksno where charnum >500"
* -------------------------------------------------
function querytotable(querystring)
merrnum=0
on error merrnum=error( )
oResp=this.mcontext.response &&引用ASP对象response
tempname=SUBSTR(SYS(2015), 3, 10) &&产生唯一的文件名
&querystring into cursor (tempname)
if merrnum<  >0 
return "Error in querytotable,create sql view"+message()
       +alltrim(str(lineno( )))+chr(13)
endif
outstring="< table border=1 >"+chr(13)+"< tr >"+chr(13)
oresp.write(outstring)
if merrnum<  >0 
return "Error in querytotable,oresp.write"+message()
         +alltrim(str(lineno( )))+chr(13)
endif
outstring=""
fc=fcount()
for i=1 to fc
if type("eval(field(i))")="G" 
  loop
endif
outstring=outstring+"< td >"+field(i)+"< /td >"+chr(13)
next
outstring=outstring+"< /tr >"+chr(13)
oresp.write(outstring)
outstring=""
if merrnum<  >0 
return "error in oresp.write header"+message()
      +alltrim(str(lineno( )))+chr(13)
endif
scan
outstring=outstring+"< tr >"+chr(13)
for i=1 to fc 
  if type("eval(field(i))")="G" 
   loop
  endif
  mt=eval(field(i))
  do case
   case type("mt")="C"
    outstring=outstring+"< td >"+mt+"< /td >"
   case type("mt")="T"
    outstring=outstring+"< td >"+ttoc(mt)+"< /td >"
   case type("mt")="D"
    outstring=outstring+"< td >"+dtoc(mt)+"< /td >" 
   case type("mt")$"NY"
    outstring=outstring+"< td >"+alltrim(str(mt,5))+"< /td >"
  endcase
  outstrin=outstring+chr(13)
next 
outstring=outstring+"< /tr >"+chr(13)
endscan
oresp.write(outstring)
outstring="< /table >"
oresp.write(outstring)
use
on error
return "OK of querytotable, ended"+chr(13)
endfunc
EndDefine
---- 键 入 代 码 后Build , 在Build 对 话 框 中 仍 选Build OLE DLL, 在
 确 认 覆 盖 时 选 择"Y", 在Project Information 对 话 框 中 看 到 这 个
 组 件 的 信 息 已 有 变 化: 

Server Classes:onerecord clsq2t 
Project Name:Classes
---- 加 上 了 新 增 的clsq2t。 

---- 这 段 代 码 中 较 特 别 的 是onstartpage(ocontext), 它 在 每 次.
asp 页 面 启 动 时 由IIS 自 动 调 用, 并 传 入 一 个 参 数。 该 参 数 
是 对ASP 的 一 个 容 器ScriptingContext 的 引 用, 通 过 它 可 以 引 用
ASP 的 所 有 内 在 对 象(Intrinsic Object), 如response、reuqest。 通
 过 这 些 内 在 对 象,VFP 可 以 直 接 读 取 用 户 在Web 页 面 上 的 输
 入, 也 可 以 把 结 果 直 接 写 回Web 页 面。 

---- 组 件clsq2t 的 调 试 要 困 难 得 多。 可 以 在 函 数querytotable 中
 注 释 掉 与oResp 有 关 的 行 以 及define class clsq2t as custom 
olepublic 和 EndDefine 两 行, 然 后 增 加 一 些 代 码 直 接 调 用 各 个
 函 数, 以 进 行 调 试 排 错。 确 认 无 误 后 再 恢 复 上 述 各 行, 并
 重 新 Build。 

5. 在ASP 中 使 用VFP 组 件 ---- 下 面 将 建 立 两 个ASP 页 面:
Onerecord.asp 和Clsq2t.asp 测 试 我 们 完 成 的 这 两 个 组 件。 启 动
Visual InterDev, 开 始 一 个 新 的 工 程:New Projects, 然 后 选 取Web
 Project Wizard , 在Project Name 中 输 入VFPClasses, 点 击OK 后,
Visual InterDev 产 生 一 些 辅 助 文 件, 为 新 的 工 程 做 好 准 备, 
然 后 打 开 该 工 程。 我 们 在 该 工 程 中 首 先 建 立 一 个HTML 页 面
index.htm, 以 调 用 上 述 两 个ASP 页 面。 点 击 菜 单File | New, 在
New 对 话 框 中 选Files | HTML Page, 并 指 定HTML 页 面 的 名 字:
index.htm。Visual InterDev 将 会 为 我 们 产 生 一 个 空 的 框 架, 在 
其 中 用 手 工 加 入 代 码, 也 可 用Visual InterDev 附 带 的FrontPage 
Editor 等 可 视 化 工 具 编 辑 代 码, 完 成 后 的HTML 页 面 如 下: 
< HTML >
< HEAD >
< /HEAD >
< BODY >
< p >< a href="Onerecord.asp" >To scan the records< /a >
        < /p >
< p >To send a query:< br >
< form action="Clsq2t.asp" method="post" name="input" >
< input type="submit" name="Btoquery" value="Query" >
< input   type="text" size="40" name="qstring" 
           value="Input a query here" > 
< /p >
< /form >
< /BODY >
< /HTML >
---- index.htm 中 包 括 一 个 到Onerecord.asp 的 超 联 接、 一 个Text 用
 于 输 入 查 询 语 句、 一 个Submit Button 用 于 提 交 查 询, 点 击 该
Button 后 将 调 用Clsq2t.asp。 

---- 点 击 菜 单File | New , 在New 对 话 框 中 选Files | Active 
Server Page, 新 建Onerecord.asp, 它 使 用onerecord 组 件 在Web 页 面 上
 浏 览 数 据 库, 代 码 如 下: 

< %@ LANGUAGE="VBSCRIPT" % >
< html >
< HEAD >
< /HEAD >
< BODY >
< FORM ACTION="Onerecord.asp" METHOD="POST" ID="scanform" >
< %set ox=server.createobject("classes.onerecord")
ox.setdatapath("d:\vfpweb\data")
if session("currentno")="" then
session("currentno")=1'first time open the page
currentno=1
else
if isnumeric(session("currentno")) then
  currentno=session("currentno")
else
  currentno=1
end if
end if
ox.goto(currentno)
% >
< %if request.form("cmdnext")<  >"" then
ox.movenext
end if% >
< %if request.form("cmdprev")<  >"" then
ox.moveprevious
end if% >
< %if isnumeric(request.form("txtgoto")) then
temp=cint(request.form("txtgoto"))
ox.goto(temp)
end if% >
< %session("currentno")=ox.getcurrentno% >
< p >
当前记录:< %=ox.getcurrentno% >< br >
书  号:< %=ox.getbookno% >< br >
书  名:< %=ox.getbookname% >< br >
责  编:< %=ox.geteditor% >< br >
出版时间:< %=ox.getpubdate% >< br >
< /p >
< p >
< %if not ox.iseof then'如果不是文件未则显示按钮Next% >
< INPUT TYPE=submit VALUE="Next" NAME="cmdnext" >
< %end if% > 
< %if not ox.isbof then'如果不是文件头则显示按钮Prev% >
< INPUT TYPE=submit VALUE="Prev" NAME="cmdprev" >
< %end if% >
< %set ox=nothing% >
< INPUT LANGUAGE="VBScript" TYPE=submit 
           VALUE="Goto" 
ONCLICK="if not isnumeric(scanform.txtgoto.value) then
window.alert("Must input a number")
window.event.cancelbubble=true
end if"
NAME="cmdgoto" >
< INPUT TYPE=text SIZE=20 NAME="txtgoto" >< /p >
< a href=index.htm > Return Index< /a >
< /FORM >
< /BODY >
< /HTML >
---- 该 页 面 显 示 数 据 库 当 前 记 录 各 字 段 的 值, 并 在 页 面 下
 方 显 示 三 个 按 钮Next( 下 一 条),Prev( 上 一 条) 和Goto。 其 中
 使 用 了Server Side Code( 符 号< % 和% > 之 间 的 代 码, 在 服 务 器
 端 执 行), 产 生 组 件 及 对 组 件 各 方 法 和 属 性 的 调 用;Client
 Side Code( 在 客 户 端 执 行), 在ONCLICK 的 事 件 响 应 中 检 验 用
 户 输 入 的 记 录 号( 必 须 是 一 个 数 字)。 由 于Web Browser 基 于
 的HTTP 是 一 个 无 状 态 协 议, 它 并 不 知 道 各 客 户 的 当 前 记 录
。 为 了 在 各 个 页 面 调 用 中 记 住 当 前 记 录 号, 使 用 了
session 对 象。session 对 象 在 跟 踪 和 保 持 客 户 的 使 用 状 态 上 
很 有 用 处, 感 兴 趣 者 可 以 查 阅Visual InterDev 的 联 机 帮 助。 

---- 再 新 建Clsq2t.asp , 它 使 用 使 用clsq2t 组 件 在Web 页 面 上 显
 示 任 意 查 寻 结 果, 代 码 如 下: 

< %@ LANGUAGE="VBSCRIPT" % >
< HTML >
< HEAD >
< /HEAD >
< BODY >
< %qs=request.form("qstring")% >
你输入的查询要求是: < br >< %=qs% >< hr >
< a href=index.htm > Return Index< /a >< br >
< %set ox=Server.CreateObject("classes.clsq2t")% >
< %ox.SetDataPath("d:\vfpweb\data")% >
< %ox.QueryToTable(qs)% >
< %Set ox = Nothing% >
< /BODY >
< /HTML >
---- 由 于 输 出 操 作 都 已 封 装 在 组 件clsq2t 之 中, 故 该 组 件 的
 使 用 相 当 简 明。 应 该 指 出 的 是, 该 组 件 应 该 用 于 开 发 之 
中, 而 不 应 提 供 给 最 终 用 户, 因 为 不 能 保 证 用 户 输 入 的SQL
 Select 串 的 有 效 和 合 法。 

6. 调 试 注 意 事 项 ---- 此 处 两 个 组 件 皆 是 进 程 内 服 务 器, 当
 有Bug 时 将 会 使 系 统 挂 起 甚 至 崩 溃。 
---- 当 修 改 组 件 代 码 时, 你 会 发 现 无 法 覆 盖 老 的.dll 文 件。
 这 是 因 为 即 使 退 出Visual InterDev, 组 件 仍 被Web Server 锁 定(
 这 就 是 为 什 么VFP 试 图 用clear all 释 放 资 源 时 会 挂 起 服 务 器
)。 这 时 必 须 停 止Web Server 并 再 启 动 之, 在 开 发 过 程 中 可 
能 要 如 此 反 复 多 次。 如 果 系 统 被 挂 起 或 崩 溃,Web Server 无 
法 响 应, 这 时 只 有 使 出 最 后 一 招: 关 机 并 重 新 启 动。VFP 5.0
 版 本 的Run Time Library 只 支 持 一 个 实 例, 就 是 说: 如 果 上 述
 两 个 组 件 在 两 个 不 同 的prg 文 件 中 实 现, 则 它 们 不 能 同 时
 被 使 用。 这 一 点 在VFP6.0 中 已 得 到 改 进( 但 仍 是 单 线 程 的)
。 

7. 评 述 ---- Web 数 据 库 开 发 更 专 业 化 的 方 法 似 乎 是
ASP+VB+ADO(ActiveX Data Object)+SQLServer。 其 中ADO 不 仅 可 用 于Web 
数 据 库 开 发, 也 可 用 在VB、VFP 中 替 代DAO、RDO 开 发 传 统 的C/S 
应 用, 功 能 更 为 强 大。 然 而 对 于 中 小 企 业 来 说,VFP 简 便 易
 用, 对 资 源 要 求 不 高, 而 且 我 国 很 多 高 校 学 生 都 学 习 过
Foxbase 或Foxpro, 他 们 可 以 很 快 掌 握Visual Foxpro, 故 可 以 比 较
 容 易 地 找 到 编 程 和 系 统 维 护 人 才。VFP 用 于 开 发
Internet/Intranet 是 一 个 较 好 的 选 择, 国 外 已 有 许 多 大 型 应 
用 的 成 功 凡 例。 

--

       大海无边天做岸
               山登绝顶我为风

※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: 202.118.227.121]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:208.844毫秒