第一个WEB网页

这篇文章应该在 3 年以前就写的,那时候 Visual FoxPro 6 刚推出,它的一个卖点就是:与 ASP 合作,充当 Web Server。总的来说,国内对技术的理解、国内对技术的需求、国内对技术的接纳都明显落后于国外——在今天,应该是讨论 Web Service 的时候,我还是愿意花一点时间和大家一起探讨 Web Server。

至于,Web Server 与 Web Service 的区别,BOE 会有专题讨论。

我从来没有写过 ASP 代码,本文权作为引玉之石……

缘起

前些天,Boby 给了我一个 QXF 大侠写的 FoxWeb 应用,很不错。FoxWeb 是 Visual FoxPro 的一个第三方产品。当时我就在想,能不能用纯 Visual FoxPro 实现相同的功能呢?

当然可以,Web Server 技术与 FoxWeb 应用的核心技术都是 Visual FoxPro 编写的 COM 组件,只是作为第三方产品 FoxWeb 又加入了一些其他的功能,听说提供一种功能类似于 ASP 的脚本语言,它的语法习惯与 Fox 差不多。

这里,我们将不使用任何第三方产品来实现一个简单的 Web Server。现在,就让我们开始吧!

总的构架

基本 WEB 页面

你应该知道,最基本的页面(纯静态的那种,www.boeworks.com 就属于这一类) 是如何被显示在你的浏览器中的,你还应该知道浏览器的最基本的工作原理。

客户端浏览器向WEB 服务器发送 WEB 页面请求,然后 WEB 服务器处理这种请求,并通过 Internet 将 WEB 页面的 HTML 代码发送回发送请求的客户端浏览器,由浏览器来解析 HTML 代码,最后显示出来。这里的 HTML 代码当然可以包括一些其他的客户端支持的代码,如CSS、DHTML、XML甚至是JScrip、VBScrip,总之它们与 HTML 代码一样在客户端浏览器里执行或者解析。

总的来说,基本 WEB 页面就是 WEB 服务器收到请求后“直接”把 HTML 代码发送回给客户浏览器。这种模式的系统构架图是这样的:

服务器端的动态页面

这种简单的页面处理模式并不能解决我们的需求,因为 WEB 服务器只是简单的把现成的 HTML 代码返回给客户浏览器,这就显得非常“木讷”了。例如在一个论坛网站(像 www.myf1.net 或者 http://www.foxcn.com)里,难道每有一个新的帖子,网站的维护者就要重新做一张页面吗?这显然是不可能的!

为了在 WEB 服务器接受客户浏览器发送请求和返回页面之间能灵活的干预页面的产生,人们提出了很多办法:CGI、ISAPI、ASP、ASP.NET、PHP、JSP……它们的共同特点就是:干预被返回的WEB 页面的生成,这样就能根据 Web 服务器的具体(往往是根据数据库)情况产生不同内容的网页,这就是所谓的动态页面。刚才说的 www.myf1.net 就是基于 ASP 的(但是没有用到外挂组件),而 http://www.foxcn.com 是基于 CGI 技术的。 

从 MS 方面看,对动态网页的支持主要是通过 CGI、ISAPI、ASP 和 ASP.NET 实现的,它们都运行在 MS 的 WEB 服务器产品 Internet Information Server(IIS)上。

好了,回过头来看我们的 Visual FoxPro 是如何参与到这些应用中去的。Visual FoxPro 完全支持 ISAPI、ASP、ASP.NET,Visual FoxPro 可以为它们提供组件。说到组件,当然是指 Visual FoxPro 开发的 COM 组件了。

今天的专题不涉及 ISAPI 和 ASP.NET 与 Visual FoxPro COM 组件的结合应用(BOE 有计划专题讨论与 ASP.NET 的结合应用的问题),这里我们只是集中精力讨论 ASP 与 Visual FoxPro 开发的 COM 组件的联合应用。

当 ASP 离开了 COM 组件

首先,我们用自己的 Fox 经验思考一下:Visual FoxPro 编写的 COM 一般能提供一些什么功能?我的答案是对数据库的处理,包括 Visual FoxPro 的本地数据和各种类型的远程数据(来自Access、SQL Server的数据)。确定了这一点以后,再让我们看看在 ASP 里有没有处理数据库的语素:有,就是著名的ADO。ADO 属于 ASP 的内置(Built In)组件,类似的还有 Session、Application 等组件。 

据我所知,现在有不少人在 Visual FoxPro 里使用 ADO 了,那么再用 Visual FoxPro 开发 COM 给 ASP 调用是不是多此一举?我看,不见得,原因如下:

第一。在 ASP 里驱动程序运行的是脚本语言(通常是 VBScrip)。既然是脚本语言,就注定了 ASP 程序是解释执行的,效率很低!而 Visual FoxPro 是编译执行的语言,漫长的 Fox 历史证明了它处理数据、处理字符串时迅捷的速度,把大量处理数据库、处理字符串的运算放在 Visual FoxPro 编写的 COM 组件里,无疑能提高 ASP 的运行效率。有人测试,用了 Visual FoxPro 的 COM 以后比纯 ASP 的程序的速度提高几倍甚至几十倍!

第二。如果你看过别人编写的 ASP 的代码,你可能会头疼——专业的程序员会很不习惯 ASP 里HTML 与 VB 脚本混杂在一起。所以,常常有人抱怨:页面一变,ASP 代码就混乱的一塌糊涂……如果,我们把相关代码分装在 COM 组件里,利用 Visual FoxPro 面向对象和面向过程的优势,能使得整个代码更整洁、更容易维护。

第三。在一些大型应用里,可能要考虑服务器的负载平衡和分布事务,这通过单纯的 ASP 是根本无法解决的。而 Visual FoxPro 编写的 COM 支持 MS 的 COM+,通过 COM+ 就能解决负载平衡和分布事务的难题。

第四。这是最实惠的一点。用了 COM ,就能使传统的 Visual FoxPro 程序员一下子成为了 WEB 解决方案的一员,而且不需要另外学习更多的新技术,起码对数据的处理,我们是“行家里手”。

ASP 里调用 Visual FoxPro 编写的 COM 的构架

上面这张就是“ASP 里调用 Visual FoxPro 编写的 COM ”的构架图,这里我解释一下:

与“基本 WEB 页面”类似,客户端浏览器发送请求到 WEB 服务器,WEB 服务器接收到有关请求后执行 ASP 脚本程序,产生 HTML 代码返回给发送请求的客户浏览器,客户浏览器解析 HTML 代码,显示 WEB 页面。在执行 ASP 脚本程序时,可以根据需要调用各种 COM 组件,一般的 COM 组件会返回一些数据以帮助 ASP 生成 HTML 代码。这里的 COM 组件可以由各种开发工具编写,当然包括 Visual FoxPro 编写的。如果是 Visual FoxPro 编写的 COM 组件,在运行时必须有相关的Visual FoxPro 运行时刻支持。例如,在 Visual FoxPro 7 里,编译成为“多线程”进程内的 COM 的运行时刻文件是 VFP7t.dl。

在上面这张图里,大家可能对 ASP.DLL 会有疑问,这其实是 ASP 的运行库文件,ASP 的功能都来源于它!

更新 COM 组件

一般来说,COM 组件运行在 IIS 的内存空间里(进程内组件)。当 IIS 被启动(往往是开机的时候),第一次调用 COM 组建以后,COM 组建就运行在 IIS 的内存里了(所以第一次调用特别慢),这时我们就不能重新编译、更新 COM 组件了。以前,往往看到重新启动计算机的建议,这就给调试 COM 组件带来了很大的麻烦。这里,我介绍一种简单的方法:

在命令行窗口里执行:iisreset

它的作用是尝试关闭并且重新启动 IIS ,这样被运行的 COM 组件就被释放出来了。这样,就能很容易的重新编译、更新 COM 组件了!

实例教程

概览

这是一个计算机中级考试的成绩查询系统,可以通过姓名或者准考证号码查询出考试成绩,查询界面是这样的:

如果有结果返回,返回的结果江这样显示:

如果没有记录被查到,将显示这个页面:

代码分析

Index.htm

这是客户端浏览器上的查询界面,负责向 WEB 服务器发送请求。关键代码是:

<FORM name=search onsubmit="return validate_form()" action=search.asp method=post>

表示用 POST 方法调用名称为 search.asp 的ASP 页面。这里提交请求时,它会将客户端控件 cxxx 和 cxnr 的值一并传递到 WEB 服务器。其中 cxxx 表示查询的关键字:是按照姓名查询还是按照准考证查询;cxnr 表示查询内容,就是具体姓名或者准考证号码。

Search.asp

接着就是search.asp了,刚才客户端指明 WEB 服务器用 search.asp 来对应客户端的请求。所有代码,如下:

<%set ox=server.createobject("vfpweb.computertest")response.write ox.search(CBool(request("cxxx")),CStr(request("cxnr")))set ox=nothing%>

这是用 VB Script 编写的 ASP 脚本程序,很简单。先是创建 COM 对象实例,这和 Visual FoxPro 里的 CreateObject() 是很像的:

set ox=server.createobject("vfpweb.computertest")

创建了 COM 对象实例以后,就要调用它了。这时通过 ASP 的 Request 对象取得查询参数 cxxx 和 cxnr ,由于 VB Script 里仅有一种数据类型就是 Variant,为了保证 COM 通讯时,参数的数据类型不出错误,我们进行强制类型转换;调用 search 函数,并等待 search 函数返回 HTML 代码。最后将产生的 HTML 代码返回到客户端浏览器。

response.write ox.search(CBool(request("cxxx")),CStr(request("cxnr")))

Visual FoxPro 里 COM 组建的源代码

这里,我们分析一下核心的代码:

FUNCTION search(p1 as Boolean ,p2 as String ) as StringLOCAL cHtml as StringcHtml=""TRYIF p1 SELECT zkzh,xm,sfzh,dw,fs1,fs2,fs3,fs4,fs5,zfs from Hmhg WHERE zkzh=ALLTRIM(p2) INTO CURSOR TempELSESELECT zkzh,xm,sfzh,dw,fs1,fs2,fs3,fs4,fs5,zfs from Hmhg WHERE xm like "%"+ALLTRIM(p2)+"%" INTO CURSOR TempENDIF IF _tally=0cHtml=this.NoRecord() ELSEcHtml=this.GetResult()ENDIFCATCH TO oErrorcHtml=this.ErrorResult()strtofile('出错:'+oError.ErrorMessage+transform(datetime())+CL+CL,'c:\log.txt',.t.) ENDTRYRETURN cHtmlENDFUNC

根据不同的查询关键字,使用不同的查询语句。

如果没有查询到任何数据(查询结果 Cursor 的记录数目是0),就调用函数 NoRecord,并把 NoRecord 返回的HTML 描述返回给调用程序(这里是 ASP);

如果结果 Cursor 不存在,这说明查询时出现了错误。这时就调用函数 ErrorResult,并把 ErrorResult 返回的HTML 描述返回给调用程序(这里是 ASP);

如果查到了结果,就调用函数 GetResult ,由 GetResult 对查询结果 Cursor 进行配置,产生 HTML 描述返回给调用程序(这里是 ASP)。

这里有一点大家应该注意一下,NoRecord、GetResult、ErrorResult 函数都在声明时都使用了 Hidden 关键字,表示它们在类的外部是不可见的!

接着,我们再来分析一下函数 GetResult 的源代码:

HIDDEN FUNCTION GetResult() as StringLOCAL cResult,cXml as StringTEXT TO cResult TEXTMERGE noshow<HTML><style><!--.title { font-family: Verdana; font-size: 1em; color: #FF0000; letter-spacing: 1pt; font-weight: bold; background-color: #C0C0C0 }--></style><HEAD></HEAD><TITLE>计算机考试结果查询</TITLE><BODY><XML ID=xmlresult>ENDTEXTCURSORTOXML("temp","cXml",1,16,0,"")cResult=cResult+cXmlTEXT TO cResult TEXTMERGE ADDITIVE NOSHOW </XML><TABLE ID=tblresult DATASRC=#xmlresult DATAPAGESIZE=10 BORDER=2 CELLPADDING=2 DATAPAGESIZE=10 bordercolorlight="#800000" bordercolordark="#808080" style="border-collapse: collapse" bordercolor="#111111" cellspacing="1"><THEAD><TR class="title"><TH>准考证编号</TH><TH>姓名</TH><TH>身份证编号</TH><TH>单位</TH><TH>分数_1</TH><TH>分数_2</TH><TH>分数_3</TH><TH>分数_4</TH><TH>分数_5</TH><TH>总分</TH></TR></THEAD><TR><TD><DIV datafld="zkzh"></DIV></TD><TD><DIV datafld="xm"></DIV></TD><TD><DIV datafld="sfzh"></DIV></TD><TD><DIV datafld="dw"></DIV></TD><TD><DIV datafld="fs1"></DIV></TD><TD><DIV datafld="fs2"></DIV></TD><TD><DIV datafld="fs3"></DIV></TD><TD><DIV datafld="fs4"></DIV></TD><TD><DIV datafld="fs5"></DIV></TD><TD><DIV datafld="zfs"></DIV></TD></TR></TABLE><P>每页显示记录数:<INPUT TYPE=TEXT VALUE=10 STYLE="WIDTH:20"ONBLUR="tblresult.dataPageSize=this.value;"></p><BUTTON ID=first onclick="tblresult.firstPage()">&lt;&lt;</BUTTON><BUTTON ID=previous onclick="tblresult.previousPage()">&lt;</BUTTON><BUTTON ID=next onclick="tblresult.nextPage()">&gt;</BUTTON><BUTTON ID=last onclick="tblresult.lastPage()">&gt;&gt;</BUTTON></BOBY></HTML>ENDTEXTRETURN cResultENDFUNC

这里用 TEXT TO 命令把 TEXT TO cResult TEXTMERGE ADDITIVE NOSHOW .......ENDTEXT 当中的 HTML 描述方便的送入了内存变量 cResult 中。这一部分是 “死” 的 HTML 代码,它定义了返回的页面的框架、标题、样式表格,以及用于显示查询结果的表格的框架。

好了,进行到这里,就只差把查询结果数据转化成为 HTML 了。这里我只是用了两句代码就实现了:

CURSORTOXML("temp","cXml",1,16,0,"")*把查询结果 Cursor 转换成为 XML 字符串,送入内存变量 cXml 中cResult=cResult+cXml*把查询结果与 HTML 框架描述拼接

小结

从客户端发送请求,到服务器端的响应,再到 COM 组件的调用和运作,最后返回客户端浏览器能够解析的 HTML 代码描述(这里我们的返回信息中,还包含了XML、DHTML 、CSS,所以不是所有的浏览器都能够解析这些东东,我想 IE 5.5 以上 应该没问题的。如果想返回的代码适合更多的浏览器,那就尽量返回标准的 HTML 代码)。

编译、发布COM 

在 Visual FoxPro 里把项目编译成为一个多线程的进程内组件;

在 IIS 里建立一个虚拟目录:

这里,你也许要问:在本地目录 D:\myweb 里需要存在一些什么文件,我的 COM 是不是也要放在里面,还有我的数据库是不是也要存放在这个目录里?

我的回答是:COM 不必要存放在这个目录里,你可以把 COM 编译在任何目录里面,这样那些喜欢使用 WebZip 之类软件下载整个网站的人,就对我们的程序的核心没法子了,哈哈,多好!!!

这里,数据源 hmhg.dbf 被存放在了 C:\ 的一个目录下面,这样是不是很安全?

在 IIS 的其他设置,使用 默认值就行了!

说了半天,我把我机器上的目录安排给大家看一看:

c:\vfp_data\ 存放hmhg.dbf

d:\vfpweb\ 存放 vfpweb.dll、vfpweb.tbl、vfpweb.vbr

d:\myweb\ 是 IIS 的对应的本地目录。这里存放着,index.htm、search.asp,还有一些图片。

结束

终于写完了,我发现我的“吹牛”的水平真的很不错——没有做过任何 ASP 程序的我,竟然在这里大吹了一通用 ASP+COM 实现的 Web Server,大家如果觉得不满意,我也没办法了,技尽于此……

我想,作为一个优秀的 WEB 开发人员,应该是个通才(除非你所在的公司很大,分工明确)——既要会 ASP 编程,也要懂得网页制作,最好还会组件开发。总之,不会开发组件的 WEB 程序员,只是脚本语言的程序员;当然会组件开发的程序员,像我这样,只是一个 Visual FoxPro 程序员,离开 Web 程序员,还有好长的距离……

猫猫的心里话

加菲猫的VFP|狐友会社群接收投稿啦

加菲猫的VFP,用VFP不局限VFP,用VFP混合一切。无论是VFP,还是JS,还是C,只要能混合起来,都可以发表。

商业模式,销售技巧、需求规划、产品设计的知识通通可以发表。

暂定千字50元红包,,优秀的文章红包更大,一经发表,红包到手。

如何帮助使用VFP的人?

用VFP的人,有专业的,有非专业了,很多人其实是小白,问出的问题是小白,如果问题不对,我们引导他们问正确的问题。无论如何请不要嘲笑他们说帮助都不看,这么简单的问题都不会,嘲笑别人不行,而无法提出建设性答案,是很low的。

我们无论工作需要,还是有自己的软件,都是是需要真正的知识,如何让更多人学习真正的VFP知识呢,只需要点赞,在看,能转发朋友圈就更好了。

加菲猫的vfp倡导用"VFP极简混合开发,少写代码、快速出活,用VFP,但不局限于VFP,各种语言混合开发"

我已经带领一百多名会员成功掌到VFP的黑科技,进入了移动互联网时代,接下来我们要进入物联网领域。

2026年狐友会社群会员继续招募中

社群会员获取的权益有:

祺佑三层开发框架商业版(猫框),终身免费升级,终身技术支持。

开放的录播课程有:

微信小程序,微信公众号开发,H5 APP开发,Extjs BS开发,VFP面向对象进阶,VFP中间层开发,VFP Layui 开发

源码类资源有:

支付组件源码,短信源码,权限组件源码,一些完整系统的源码。这个可以单独出售的,需要的可以联系我。

会员也可以实现群内资源对接,可以接分包,合作等各项商业或技术业务

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值