Internet是目前世界上最大的计算机互联网络,它遍布全球,将世界各地各种规模的网络连接成一个整体。作为Internet上一种先进的,易于被人们所接受的信息检索手段,World Wide Web(简称WWW)发展十分迅速,成为目前世界上最大的信息资源宝库。据估计,目前Internet上已有上百万个Web站点,其内容范围跨越了教育科研、文化事业、金融、商业、新闻出版、娱乐、体育等各个领域,其用户群十分庞大,因此,建设一个好的Web站点对于一个机构的发展十分重要。近年来,随着网络用户要求的不断提高及计算机科学的迅速发展,特别是数据库技术在Internet中的广泛应用,Web站点向用户提供的服务将越来越丰富,越来越人性化。
在过去,客户机/服务器结构的设计与Web的相关技术几乎处于平行线上,两者相互独立并无法作出集成性的设计。现在我们利用IIS+ASP构成三层式Web结构(如图2.1所示)的中间一层,将客户机/服务器结构与Web密切结合,完成前后端两者的集成输出功能,使得Web站点的开发更方便,实现的功能更强大。
利用IIS+ASP技术来集成Web前后端所带来的强大效益可归结为以下几个方面:
1. 减少构建和维护成本
2. 加快联机过程
3. 应用软件集中在服务器端开发管理
4. 前端可使用任何
5. 后端可存取任何数据库 (SQL、Access…..)
6. 可使用任何脚本语开发 (VBScript、JavaScript、PERL…..)浏览器(IE、Netscape…..)
ASP提供了6个功能强大的内部对象,每个对象具有各自的属性(Property)、方法(Method),有的还拥有数据集合(Collection)与事件(Event),它们共同完成Web中的一些重要工作。这6个对象及其功能描述如表2.1所示。
表2.1 ASP 内部6大对象及其功能
对象名称 |
功能描述 |
Request |
从客户端取得信息 |
Response |
将信息送给客户端 |
Server |
提供一些Web服务器工具 |
Session |
储存在一个Session内的用户信息,该信息仅可被该用户访问 |
Application |
在一个ASP-Application中让不同的客户端共享信息 |
ObjectContext |
配合Microsoft Transaction服务器进行分布式事务处理 |
合理地运用这些对象可以使原本复杂,烦琐的工作变得简捷而条理清晰。
我们可以用以下的语法直接使用这些对象:对象/属性/方法/数据集合
每一个以Active Server Pages为基础的应用程序都拥有一个Global.asa文件(ASA后缀名其实是Active Server Application的缩写),它位于每一个应用程序的基点目录之下。当Active Server Pages做下面两个动作时,Server便会去读Global.asa文件:
1.Web Server启动之后,一个应用程序目录中任一个ASP文件被提出第一个HTTP请求(Request)时。
2.不具有任何Session的客户端向Server请求一个ASP文件时。
前面已经提到Application和Session这两个ASP的内部对象。Application对象内的信息供所有正在执行该应用程序的用户分享,它创建于Web Server启动后一个应用程序中任一ASP文件被提出第一个HTTP请求时,结束于Server端停止运行。而Session对象仅属于一位用户,维持一个用户端的信息,其他用户无法访问,它创建于一个不具有Session的用户向Server请求一个ASP文件时,结束于该Session到期(即用户端超过某时间段没有向Server提出要求或刷新Web页面)或Abandon语句的调用。可见,Global.asa文件的调用与Application与Session这两个对象密切相关。事实上我们通常在Global。asa文件中写入以下内容:
1. Application或Session的开始事件(Start-event)。
2. Application或Session的结束事件 (End-event)。
这样,在一个Application或Session对象被创建或结束时,系统会自动完成Global.asa文件中写入的相应事件。值得注意的是,如果一个Application与一个Session同时开始,Active Server Pages会先处理Application的开始事件,而如果一个Application与一个Session同时结束,Active Server Pages则会先处理Session的结束事件。
ADO(ActiveX Data Objects)是一种操作Microsoft所支持的数据库的新技术。在ASP中,ADO可以看作是一个服务器组件(Server Component),更简单点说,是一系列的对象,应用这些功能强大的对象,即可轻松完成对数据库复杂的操作。本文中个性化页面的实现便大量地用到了ADO技术。具体的操作步骤可以归纳为以下几步:
1.创建数据库源名(DSN)
2.创建数据库链接(Connection)
3.创建数据对象
4.操作数据库
5.关闭数据对象和链接
每一步的作法如下:
一、创建数据源名
DSN(Date Source Name)即数据源名称。我们知道,ODBC是一种访问数据库的方法,只要系统中有相应的ODBC驱动程序,任何程序就可以通过ODBC操纵驱动程序的数据库。比如我们系统中有Access的ODBC驱动程序,那么即使我们没有Access软件,也可以在我们的程序中对一个Access的MDB数据库加、删、改记录。而且我们根本不用知道这个数据库是放在哪里的。我们只要写出SQL语句,ODBC驱动程序就会帮我们做一切事情。我们在给ODBC驱动程序传SQL指令时,即是用DSN来告诉它到底操作的是哪一个数据库。如果数据库的平台变了,比如我们改用了SQL Server的数据库,只要其中表的结构没变,我们就不用改写我们的程序,只要重新在系统中配置DSN就行了。由此可见,DSN是应用程序和数据库之间的桥梁。
二、创建数据库链接(Connection)
链接用以保持一些关于正在访问的数据的一些状态信息,以及链接者信息。ASP文件中如果要访问数据,必须首先创建与数据库的链接,其语法如下:
set Conn=Server.createObject(“ADODB.CONNECTION”)
这条语句创建了链接对象Conn,接下来:Connstr="Driver={Microsoft Access Driver (*.mdb)};dbq=" & Server.MapPath(db)
conn.Open connstr
这条语句打开链接,用到了DSN,本例为“connstr”。
以上两个步骤缺一不可,因为链接对象的创建与打开是两回事,只有打开了才真正可以使用。
三、创建数据对象(Record Set)
ADO中的数据对象通常保存的是查询结果。Record Set是ADO中最复杂的对象,有许多属性和方法。Record Set保存的是一行行的记录,并标有一个当前记录。以下是创建方法:
Set Record Set=Conn.Execute(sqtStr)
这条语句创建并打开了对象Record Set,其中Conn是先前创建的链接对象,sqtStr是一个字串,代表一条标准的SQL语句。例如:
sqtStr=“SELECT * FROM shop_books” Set Record Set=Conn.Execute(sqtStr)
这条语句执行后,对象Record Set中就保存了表tab1中的所有记录。
四、操作数据库
我们通过调用链接对象的Execute方法来将查询结果返回给一个数据对象或进行插入、删除、修改等操作。例如:
sqtStr =“INSERT INTO tab1 VALUES(1,2)”
Conn.Execute(sqtStr)
/执行插入操作
sqtStr =“Delete from tab1 where a=b”
/执行删除操作
sqtStr =“update tab set a=b,c=d”
/执行修改操作
五、关闭数据对象和链接对象
在使用了ADO对象之后要关闭它,因为它使用了一定的服务器资源。通过调用方法close实现关闭,然后再释放它。
Record Set.close
Set Record Set=Nothing
/关闭创建的数据对象
Conn.close
Set Conn=Nothing
/关闭创建的链接对象
2.5 ASP与CGI的比较
CGI(Common Gateway Interface,通用网关接口)也是Internet上一种功能强大的Web页面技术,其工作方式有别于ASP。我们现对二者进行比较。
Active Server Pages开发Web应用程序的特点:
1. 完全嵌入HTML,与HTML、Script语言完美结合。
2. 无须手动编译和链接程序。
3. 面向对象,并可扩展ActiveX Server组件功能。
4. 使用脚本语言(JavaScript、VBScript或PERL)编写。
5. 存取数据库轻松容易(使用ADO组件)。
6. 可使用任何语言编写自己的ActiveX Server组件。
7. 无浏览器兼容问题。
8. 程序代码隐藏,客户端仅能看到ASP输出的HTML文件。
9. 缩短Web开发时间。
相比之下,使用CGI开发Web应用程序具有以下缺点:
1. 不易与HTML文件集成。
2. 须使用其他较复杂的语言来开发CGI程序。
3. 程序开发时间较长。
4. 存取数据库不容易。
5. 每个CGI程序被不同用户执行时都得重新执行一次,并占去Server的一个端口(Port),降低Server效率。
可见,ASP在数据库访问、与HTML的集成、提高服务器的效率等诸多方面都优于CGI,更适应Web应用程序开发的需要,因此本文选择了ASP作为个性化页面生成器的开发工具。
在开始制作之前,要明确贴吧能做些什么事情,,也就是所谓的需求。所以必须把需求做清楚,然后才能进行设计。
其实在贴吧里大家最熟悉的就是用户浏览贴吧已有的内容,针对别人的主题展开讨论,也可以发表自己的观点供大家品评。同时为了防止用户发布一些不健康不合法的内容需要有管理人员来对这些内容进行删除修改,在扩展一点,若用户想在贴吧发布信息,不允许他再来发布非法内容。这样需要管理员对用户和贴吧的内容都要进行管理。
我们要做一个多版面的贴吧。在这里用户可以注册,浏览贴吧版面和帖子,发布自己的帖子,也可以相互联系。管理人员可以设置贴吧的系统参数,管理注册用户和版面。
当用户来到贴吧可以看到版面列表。通过版面可以看到相关的帖子。如果需要进一步的功能,就需要用户注册。
用户注册以后,可以发表自己的帖子或者回复别人的主题,也可以修改自己的帖子,如果发帖数量很多,会给用户一定的积分。用户也可以升级为版主,可以删除别人的帖子,将帖子置顶,设为精华等。用户还可以修改自己的信息,查看其他用户公开的注册信息。
管理人员可以管理版面、帖子、用户、设置系统参数。
首先来做名词分析。大家可能觉得奇怪,这不是阅读理解,为什么要做这个?分析需求就是要理解需求,得出重点。首先要做的就是找出这个贴吧要针对哪些进行操作,对需求中的名词进行一次筛选,得出一个简洁的列表。
下边这个表是表示各个对象间关联的,关联是单向的,是指左侧对象对上方对象的活动。没有关联我们就用X,如果两者只有单向关联,那么另一个对象反关联时我们用对号表示。根据需求,得出各个对象间的关联表。如表3.1所示
表3.1个对象间的关联表
用户 |
版面 |
帖子 |
管理人员 |
系统参数 |
|
用户 |
注册】 修改 浏览 联系 |
浏览 |
浏览 发布 修改 删除 特殊操作 |
√ |
X |
版面 |
√ |
X |
X |
√ |
X |
帖子 |
√ |
X |
X |
√ |
X |
管理人员 |
删除 授权 |
添加 删除 修改 |
添加 删除 修改 |
X |
设置 |
系统参数 |
X |
X |
√ |
X |
有了表3.1就可以进行十实质性的工作了。现在就来设计功能。首先从用户开始,在表3.1中用户关联的对象是自身,版面,帖子,分别根据用户与这些对象的联系给出一个明确的菜单,见表3.2
表3.2用户功能列表
序号 |
功能名称 |
说明 |
1 |
用户注册 |
用户在贴吧填写必要的信息后就可以注册成为注册用户,用户登录网站可以修改自己的用户信息 |
2 |
用户登录 |
用户在贴吧注册后,可以使用用户名密码在贴吧登录 |
3 |
浏览其他用户信息 |
用户注册后可以查看其他用户信息 |
4 |
浏览版面 |
用户可以看到以列表形class.asp式展现的版面信息 |
5 |
浏览帖子 |
用户可以以列表形式浏览帖子主题及帖子的全部内容 |
6 |
发布删除修改帖子 |
用户在登录后可以发布帖子,修改自己的帖子。如果被赋予版主权限还可以修改其他用户的帖子 |
7 |
与其他用户联系 |
在用户注册时要求用户填写电子邮件地址,那么其他用户可以利用电子邮件与其联系 |
8 |
对帖子特殊操作 |
接下来的版面,帖子都没有和其他对象的关联,他们在贴吧属于被动的对象,是被其他对象所操作的。因此针对他们的功能主要是由其他对象产生,例如浏览版面就属于用户的功能。
管理人员是贴吧的一个特殊群体,他们的主要工作的是保证贴吧的正常运转,他们可以和所有对象产生联系,因此他们的功能也很丰富。表3.3列出了管理人员的功能。
表3.3管理人员功能列表
序号 |
功能名称 |
说明 |
1 |
用户删除 |
对于在贴吧发表一些非法言论。给贴吧造成很坏的影响的用户应该删除他们的身份,不允许他们的存在 |
2 |
用户授权 |
贴吧的管理是纷繁复杂的,需要很多的知识需要给一些具有能力用户一些特殊权限让他们帮助管理人员完成对贴吧的维护。 |
3 |
版面管理 |
版面是贴吧的枝干,对于新的只是需要添加新的版面有些版面的内容可能不太适合了可以考虑修改,对于没有存在意义的版面就要删除了。 |
4 |
帖子的管理 |
帖子是一个贴吧的叶子,他们的内容如何,反应了贴吧使用者和管理这的水平,需要管理人员对帖子的全权管理,以保证贴吧内容的水平。、 |
5 |
设置系统参数 |
系统参数包含的内容很多他们直接关系到贴吧的正常运行。 |
现在系统功能部分已经分析完了,接下来需要对这些功能进行分类,同时根据功能给出详细的数据库设计。
一般初学程序设计的人,即掌握了某种程序设计语言的语法,按照教材做过简单实例的人,在遇到现实生活的应用系统时,他的分析思路是从计算机实现的角度来考虑问题,而不是从系统的使用者的角度考虑问题,这就制约了他的思路一个系统是给人用的,开发者需要考虑用户使用起来是否方便,而不是及其实现起来是否方便。模块的划分主要是按每一个对象操作来归类。贴吧操作的对象是上面所归纳的5个,下面就针对这5个对象划分功能模块。
用户:应该有两个模块,一个是用户注册、登录、修改信息等功能组合,是用户对用户的操作;另一个是管理人员对用户进行删除,授权,是管理人员对用户的操作。这两个模块功能列表如3.4所示
表3.4用户功能模块列表
模块 |
模块包含的功能 |
用户模块 |
用户注册 |
用户登录 |
|
浏览其他用户信息 |
|
与其他用户联系 |
|
用户控制自己的信息 用户登录添加验证码 |
|
管理人员模块 |
用户删除 |
用户授权 |
|
版面:也有两个模块,一个是浏览模块,一个是管理模块,其功能模块列表如表3.5所示
表3.5版面功能模块列表
模块 |
模块包含的功能 |
版面浏览模块 |
浏览版面 |
版面管理模块 |
版面管理 |
帖子:帖子的功能是最多的,也是最复杂的,但是仍把它分为两大模块。根据操作对象来区分,有很多功能是重复的,但是由于操对象不同仍然需要列出。其功能如表3.6所示
表3.6帖子功能模块
模块 |
模块包含的功能 |
帖子模块 |
浏览帖子 |
发布、修改、删除帖子 |
|
对帖子的特殊操作 |
|
帖子收藏 |
|
帖子搜索 |
|
帖子管理模块 |
帖子管理 |
管理人员:管理人员主要是对其它对象进行操作,针对他的模块就没有了。但是这里很多模块的操作人员是他,同时把系统参数设置的功能也划分出来。其功能列表如表3.7所示。
表3.7管理人员管理功能模块
模块 |
模块包含的功能 |
管理人员管理模块 |
设置系统参数 |
数据备份 |
|
非法言论过滤 |
|
非法IP限制 |
这样贴吧的模块划分就完成了。从以上分析可以了解到模块划分的依据,就是功能的使用者。
从表可以的到贴吧的功能框架,即系统的各个部分已经确定,知道贴吧是什么样的,但是要把贴吧系统完整的构架出来,还需要进一步思考模块间的关系。
贴吧系统信息的存储一般是在文件或者数据库中,在这里选择数据库,用数据库要简单高效一些,能够对贴吧进行更好的控制。使用数据库的第一步就是涉及数据库的表结构,一个良好的数据库表结构,可以提高效率,方便维护,并且以后进行功能的扩充留有余地,就好比高楼大厦的地基一样,有了稳固的基础,才能有优秀的成果。
下面来设计贴吧的数据库。
首先给出贴吧使用的数据表如表3.9所示
表3.9贴吧数据表
序号 |
表名 |
说明 |
1 |
QiQiBoy_Admin_Disp |
管理员信息表 |
2 |
QiQiBoy_Board_Disp |
贴吧列表 |
3 |
QiQiBoy_Class_Disp |
二级版面信息表 |
4 |
QiQiBoy_Nlass_Disp |
一级版面信息表 |
5 |
QiQiBoy_Status_Disp |
贴吧状态表 |
6 |
QiQiBoy_System_Disp |
系统信息表 |
7 |
QiQiBoy_Topic_Disp |
主题,帖子信息表 |
8 |
QiQiBoy_User_Disp |
用户信息表 |
数据库概念结构设计完毕就可以通过数据库软件转化为实际的数据模型,即数据库的逻辑设计。本系统采用的数据库软件是MICROSOFT ACCESS.
序号 |
字段名 |
字段类型 |
说明 |
备注 |
1 |
UserID |
自动编号 |
用户编号 |
主键 |
2 |
UserName |
文本 |
用户帐号 |
|
3 |
Pwd |
文本 |
用户密码 |
|
4 |
Sex |
数字 |
用户性别 |
|
5 |
|
文本 |
用户邮箱 |
|
6 |
OICQ |
文本 |
用户qq |
|
7 |
Question |
文本 |
找回密码提示问题 |
|
8 |
Answer |
文本 |
提示答案 |
|
9 |
UserGroupID |
数字 |
用户类别 |
|
10 |
Ip |
文本 |
用户IP |
|
11 |
RegTime |
日期/时间 |
用户注册时间 |
|
12 |
LastLogin |
日期/时间 |
用户最后登录时间 |
|
13 |
Visits |
数字 |
用户访问次数 |
|
14 |
LockUser |
数字 |
是否锁定 |
|
15 |
Integral |
数字 |
用户积分 |
|
16 |
Topics |
数字 |
用户发表主题数 |
|
17 |
Replys |
数字 |
用户回复帖子数 |
|
18 |
Area |
文本 |
用户地址 |
|
19 |
Websites |
文本 |
用户主页 |
|
20 |
List |
备注 |
用户简介 |
|
21 |
Photo |
文本 |
用户头像 |
在用户信息表里保存的是所有在贴吧注册的用户的信息,用户编号是用户在贴吧的唯一标识,是不重复的,同时用户名在贴吧中也是不能重复的,大家可能奇怪既然用户名也不可以重复,为什么不用用户名作为用户在贴吧中的唯一标识呢?大家可以考虑一下,假如你有一份一百个人的名单,每个人有一个序号,这是让你从中找一个人,如果只告诉你名字,那么找起来会很麻烦,如果告诉你他是多少号是不是要简单的多?同样道计算机对数字的检索更加快速,特别是用用户很所的时候。用户名和密码是不能为空的,这是因为当用户名登录时必须输入用户名和密码我们才能定位到用户的信息,验证用户是不是真正在贴吧注册了,电子邮件不能为空的目的是为了是其他用户能够很方便的和该用户联系,同时又可以作为用户忘记密码是取回密码的联系方式。密码问题和密码答案的主要应用是。当用户忘记密码时,由系统提问,如果用户能够准确的给出密码答案我们将提示给用户密码。
2.管理员信息表(QiQiBoy_Admin_Disp)
序号 |
字段名 |
字段类型 |
说明 |
备注 |
1 |
ID |
自动编号 |
管理员ID |
主键 |
2 |
uid |
文本 |
管理员姓名 |
|
3 |
pwd |
文本 |
管理员密码 |
|
4 |
groups |
文本 |
管理员类别 |
|
5 |
loginip |
文本 |
管理员登录IP |
|
6 |
updatetime |
日期/时间 |
管理员最后登录时间 |
|
7 |
loginnum |
数字 |
管理员登录次数 |
3.二级版面信息表(QiQiBoy_Class_Disp)
序号 |
字段名 |
字段类型 |
说明 |
备注 |
1 |
BoardClass |
自动编号 |
二级版面编号 |
主键 |
2 |
BoardClassName |
文本 |
二级版面名字 |
|
3 |
BoardNlass |
数字 |
上级版面 |
4.贴吧状态表(QiQiBoy_Status_Disp)
序号 |
字段名 |
字段类型 |
说明 |
备注 |
||||
1 |
StatusID |
自动编号 |
状态信息ID |
主键 |
||||
2 |
RegUsers |
数字 |
注册用户数 |
|||||
3 |
TotalBoards |
数字 |
版面数 |
|||||
4 |
TotalTopics |
数字 |
主题数 |
|||||
5 |
TotalReplys |
数字 |
回复主题数 |
|||||
5.版面信息表2(QiQiBoy_Class_Disp)
序号 |
字段名 |
字段类型 |
说明 |
备注 |
|||
1 |
BoardNlass |
自动编号 |
一级版面ID |
主键 |
|||
2 |
BoardNlassName |
文本 |
版面名称 |
||||
版面列表(QiQiBoy_Board_Disp)
序号 |
字段名 |
字段类型 |
说明 |
备注 |
|||
1 |
BoardID |
数字 |
版面ID |
主键 |
|||
2 |
BoardNlass |
数字 |
二级版面编号 |
||||
3 |
BoardClass |
数字 |
一级版面编号 |
||||
4 |
BoardName |
文本 |
版面名称 |
||||
5 |
BoardDescription |
文本 |
版面描述 |
||||
6 |
BoardMaster |
文本 |
版主 |
||||
7 |
LastModify |
日期/时间 |
最后修改时间 |
||||
8 |
BoardTopics |
数字 |
版面主题数 |
||||
9 |
BoardReplys |
数字 |
版面回复数 |
||||
6.系统信息表(QiQiBoy_System_Disp)
序号 |
字段名 |
字段类型 |
说明 |
备注 |
||||
1 |
SystemID |
自动编号 |
系统信息编号 |
主键 |
||||
2 |
SystemName |
文本 |
网站名称 |
|||||
3 |
SystemList |
文本 |
网站介绍 |
|||||
4 |
SystemUrl |
文本 |
网站地址 |
|||||
5 |
SystemLogo |
文本 |
网站LOGO |
|||||
6 |
SystemUser |
网站站长 |
||||||
7 |
Systememailr |
文本 |
邮件地址 |
|||||
8 |
SystemQQ |
文本 |
QQ号码 |
|||||
9 |
SystemReg |
备注 |
注册提示信息 |
|||||
10 |
SystemHelp |
备注 |
网站帮助指南 |
|||||
11 |
SystemPic |
备注 |
||||||
12 |
SystemFilter |
备注 |
过滤字符 |
|||||
13 |
SystemMeun |
备注 |
首页导航菜单 |
|||||
14 |
SystemFont |
文本 |
字体颜色 |
|||||
15 |
SystemRefresh |
数字 |
开启/关闭防刷新功能 |
|||||
16 |
SystemRefreshTime |
数字 |
防刷新间隔时间 |
|||||
17 |
SystemOff |
数字 |
网站开启/关闭 |
|||||
18 |
SystemVip |
数字 |
会员发表/回复帖子 |
|||||
19 |
SystemUbb |
数字 |
UBB编辑功能 |
|||||
20 |
SystemUp |
数字 |
图片上传功能 |
|||||
21 |
SystemMailAddress |
文本 |
在线发送邮箱地址 |
|||||
22 |
SystemSmtpAddress |
文本 |
发送邮箱SMTP地址 |
|||||
23 |
SystemMailName |
文本 |
发送邮箱登陆帐号 |
|||||
24 |
SystemMailPass |
文本 |
发送邮箱登陆密码 |
|||||
25 |
SystemCopyTxt |
文本 |
||||||
26 |
SystemCode |
数字 |
||||||
27 |
SystemEmNum |
数字 |
帖子表情允许数目 |
|||||
这是个核心表,但是他的每个字段都很简单,贴吧设置字段存储了贴吧名称,贴吧地址,贴吧联系方式,过滤词这个字段很重要。他的内容是不允许发布在贴吧上的当用户发布题写非法言论是,可以通过这个字段检查出来。
7.主题,帖子信息表(QiQiBoy_Topic_Disp)
序号 |
字段名 |
字段类型 |
说明 |
备注 |
||
1 |
TopicID |
自动编号 |
主题id |
主键 |
||
2 |
ParentID |
数字 |
父文章id |
|||
3 |
RootID |
数字 |
主题号 |
|||
4 |
BoardNlass |
数字 |
一级版面号 |
|||
5 |
BoardClass |
数字 |
二级版面号 |
|||
6 |
UserName |
文本 |
发表主题者 |
|||
7 |
LastPost |
文本 |
最后发帖者 |
|||
8 |
Title |
文本 |
主题类型 |
|||
9 |
Content |
备注 |
主题内容 |
|||
10 |
Img |
文本 |
主题图片内容 |
|||
11 |
DateAndTime |
日期/时间 |
发表主题时间 |
|||
12 |
UpdateTime |
日期/时间 |
最后发帖时间 |
|||
13 |
Reads |
数字 |
阅读次数 |
|||
14 |
Replys |
数字 |
回复次数 |
|||
15 |
Status |
数字 |
主题状态 |
|||
16 |
TopicIp |
文本 |
发表主题者的IP |
|||
17 |
ReplyIp |
文本 |
回复者的IP |
|||
18 |
Favorite |
备注 |
收藏该主题 |
|||
在整个系统开发的过程中,数据库连接是必不可少的,是公用的,我们可以把这一部分先拿出来,单独做成一个页面,在需要的时候只需要调用这个页面就可以了,而不用每次都去写连接数据库的程序,这个做法叫做复用,是在程序开发中经常用到的。
首先要建立同数据源的连接,我们利用ADO的Connection来建立同数据库的连接。建立asodb.connection对象,使用此对象的open方法打开数据库。
现在来看代码如程序3.01所示:
数据库连接程序(conn.asp)
<%
%>
第一行是容错语句,发生错误后,继续执行下一句,接下来就用dim声明了变量 rs,sql,Conn,Connstr,Db,connstr这个变量是用来存储连接数据库的信息的,变量db声明了数据库文件所在的路径。
第五行,为connstr赋值。这是很关键的一步,这里声明的是ole db 连接数据库的方式,只看data sourse部分,他后面跟的是数据库文件的路径。Server.mappath函数是asp内置的server对象的一个函数,用来获取五网站目录下文件的绝对路径。
在7~9行写了一个判断错误的信息,如果连接数据库错误,系统会给出一个错误,这时候通过asp的err对象判断错误的存在,首先将错误信息从内存清除,然后将conn对象从内存中清除。
数据库连接完了,接下来要做的就是实际模块程序的编写了。首先要写的是用户模块,用户模块包含7个功能,其中有些功能是相辅相成的。现在就一步步地实现本模块的功能。
我们已经有了用户信息表,其中的用户名和用户密码字段是用来验证用户身份的,有了这两个字段,我们就可以很容易地写出验证用户登陆的程序了。首先来看用户登陆的界面,如图所示。
我们将这个页面命名为login.asp,先看页面的内容。“用户帐号”和“用户密码”这两项就是用来读取用户名和密码的地方。接下来是一个cookie选项,cookie是用来保存用户信息的一种方式,系统登录页面所涉及的HTML表单元素如表2所示:
表2系统登录页面所涉及的HTML表单元素
名称 |
类型 |
含义 |
重要属性 |
form |
Form |
表单 |
action=" loginfox.asp" method="POST" |
UserName |
text |
用户帐号 |
onFocus="this.select(); " οnmοuseοver="this.style.background='#EAEAEA';" οnmοuseοut="this.style.background='#FFFFFF'" |
Password |
password |
用户密码 |
onFocus="this.select(); " οnmοuseοver="this.style.background='#EAEAEA';" οnmοuseοut="this.style.background='#FFFFFF'" |
verifycode |
text |
验证码 |
onFocus="this.select(); " οnmοuseοver="this.style.background='#EAEAEA';" οnmοuseοut="this.style.background='#FFFFFF'" size="6" maxlength="4" |
AutoLogin |
checkbox |
Cookies |
type="checkbox" id="AutoLogin" value="true" |
submit |
submit |
【我要登录】按钮 |
class="input" value=" 我要登 录 " |
submit2 |
reset |
【擦除重填】按钮 |
value=" 擦除重 填 " class="input" |
验证用户身份程序(loginfox.asp)
<%
dim UserName,Password,VerifyCode
UserName=replace(trim(Request.form("UserName")),"'","")
Password=replace(trim(Request.form("Password")),"'","")
VerifyCode=replace(trim(Request.Form("VerifyCode")),"'","")
if UserName="" then
response.write ("")
response.end
end if
if Password="" then
response.write ("")
response.end
end if
If HOST_CODE=0 then
if VerifyCode="" then
response.write ("")
response.end
end if
if VerifyCode <> Trim(Session("VerifyCode")) then
response.write ("")
response.end
end if
end if
ip = request.ServerVariables("HTTP_X_FORWARDED_FOR")
if ip = "" then ip = request.ServerVariables("REMOTE_ADDR")
Sql="select * from [QiQiBoy_User_Disp] where LockUser=0 and UserName='"&showstring(UserName)&"'"
Set Rs=Conn.execute(Sql)
f Rs.eof and rs.bof then
Response.Write ("")
Response.end
else
if rs("Pwd")<>md5(Password) then
Response.Write ("")
Response.end
else
response.Cookies("UserName")=UserName
response.Cookies("Pwd")=Md5(Password)
response.cookies("automember")=UserName
response.Cookies("automember").Expires=now()+365
if LCase(Request.Form("AutoLogin"))="true" then
response.Cookies("UserName").Expires=now()+365
response.Cookies("Pwd").Expires=now()+365
end if
Sql="Update [QiQiBoy_User_Disp] set Visits=Visits+1,LastLogin='"&now()&"',ip1='"&ip&"',Integral=Integral+1 where UserName='"&showstring(UserName)&"'"
Conn.execute(Sql)
end if
end if
rs.close
set rs=nothing
Response.Write ("")
Response.end
%>
Rs.eof and rs. Bof then 判断用户信息是否存在,eof 和bof是数据查询记录集的属性,它们分别表示最后一条记录的后面和第一条记录的前面。看这一句,既在最后一条的后面,又是第一条前面,说明这样的记录集一定是空的,用户是不存在的。如果数据集不为空,我们将把数据集的信息写入存储用户信息的字符串中。这里的SQL语句中只用了用户名来取信息,下边if rs("Pwd")<>md5(Password) then这一句的内容就是判断用户密码是否和数据库中的密码相符。在经过许多判断之后就获得了用户的信息。
接下来谈谈Cookie。我们知道,用户进入了贴吧后,需要访问很多页面,其中的一部页面是需要注册用户登陆才能看到的,那么要想知道用户是否登陆,这就用到Cookie了,
Cookie是由Web页服务器置于硬盘上的一个非常小的文本文件。从本质上讲,它是你的身份证。它不能作为代码执行,也不会传送病毒。它为你所专有,并且只能有提供它的服务器来读取。但是Cookie是有限制的,每个Cookie文件的大小不超过4KB。另外浏览器中选择可接受Cookie,否则一旦ASP程序中使用了Cookie,它们将无法正常运行。现在我们把用户信息写入Cookie的程序,如程序所示。
<%
response.Cookies("UserName")=UserName
response.Cookies("Pwd")=Md5(Password)
response.cookies("automember")=UserName
response.Cookies("automember").Expires=now()+365
if LCase(Request.Form("AutoLogin"))="true" then
response.Cookies("UserName").Expires=now()+365
response.Cookies("Pwd").Expires=now()+365
%>
涉及到用户注册,我们就会想到用户信息的验证,总不能一个用户只写个空格我们也让他注册吧,还有就是用户如果忘记密码怎么办?我们也应提供相应的服务,现在我们就对用户注册部分的网页部分,以及各个网页间的联系:如图11所示。下面就来说明程序是如何编写的。首先是registr.asp
。用户注册,首先要检查的就是用户填写的信息其中包括:
表注册页面所涉及的HTML表单元素
名称 |
类型 |
含义 |
重要属性 |
form |
Form |
表单 |
action=" registrfox.asp " method="POST" |
username |
text |
用户帐号 |
maxLength="8" size="25" name="username" value="<%=session("UserName")%>" |
Password |
password |
用户密码 |
maxLength="18" size="25" name="password" |
checkPassword |
text |
验证密码 |
input type="password" maxLength="18" size="25" name="checkPassword" |
sex |
list |
用户性别 |
|
area |
text |
用户地区 |
maxLength="80" size="30" name="area" value="<%=session("Area")%>" |
|
text |
邮箱地址 |
maxLength="180" size="40" name="email" value="<%=session("Email")%>" |
question |
text |
密码问题 |
maxLength="18" size="30" name="question" value="<%=session("Question")%>" |
answer |
text |
密码答案 |
maxLength="18" size="50" name="answer" value="<%=session("Answer")%>" |
websites |
text |
个人主页 |
size="60" name="websites" maxLength="250" value="<%=session("Websites")%>" |
list |
textarea |
个人简介 |
rows="6" cols="60"><%=session("List")%> |
submit |
submit |
【我要注册】按钮 |
class="input" value=" 我要登 录 " |
submit2 |
reset |
【擦除重填】按钮 |
value=" 擦除重 填 " class="input" |
用户注册各个页面与数据库间的联系
下面看用户注册验证程序(registrfox.asp)
<%
UserName=replace(trim(Request.Form("UserName")),"'","")
Password=replace(trim(Request.Form("Password")),"'","")
checkPassword=replace(trim(Request.Form("checkPassword")),"'","")
Sex=replace(trim(Request.Form("Sex")),"'","")
Area=replace(trim(Request.Form("Area")),"'","")
Email=replace(trim(Request.Form("Email")),"'","")
Oicq=replace(trim(Request.Form("Oicq")),"'","")
Question=replace(trim(Request.Form("Question")),"'","")
Answer=replace(trim(Request.Form("Answer")),"'","")
Websites=replace(trim(Request.Form("Websites")),"'","")
List=replace(trim(Request.Form("List")),"'","")
Photo=replace(trim(Request.Form("Photo")),"'","")
VerifyCode=replace(trim(Request.Form("VerifyCode")),"'","")
if UserName="" then
response.write ("")
response.end
end if
if Password="" then
response.write ("")
response.end
end if
if checkPassword="" then
response.write ("")
response.end
end if
if checkPassword<>Password then
response.write ("")
response.end
end if
if Sex="" then
response.write ("")
response.end
end if
if Area="" then
response.write ("")
response.end
end if
if Email="" then
response.write ("")
response.end
end if
if isvalidemail(Email)=false then
response.write ("")
response.end
end if
if Oicq="" then
response.write ("")
response.end
end if
if not isnumeric(Oicq) then
response.write ("")
response.end
end if
if Question="" then
response.write ("")
response.end
end if
if Answer="" then
response.write ("")
response.end
end if
if List<>"" then
if len(List)>250 then
response.write ("")
response.end
else
List=trim(List)
end if
end if
If HOST_CODE=0 then
if VerifyCode="" then
response.write ("")
response.end
end if
if VerifyCode <> Trim(Session("VerifyCode")) then
response.write ("")
response.end
end if
end if
if Yes="" then
response.write ("")
response.end
end if
Ip = Request.ServerVariables("HTTP_X_FORWARDED_FOR")
If Ip = "" Then Ip = Request.ServerVariables("REMOTE_ADDR")
Sql="select * from [QiQiBoy_User_Disp] where UserName='"&showstring(UserName)&"'"
Set Rs=Conn.execute(Sql)
If not Rs.eof then
Response.Write ("")
Response.end
else
Sql="select * from [QiQiBoy_User_Disp] where Email='"&showstring(Email)&"'"
Set Rs=Conn.execute(Sql)
if not Rs.eof then
Response.Write ("")
Response.end
else
Sql="select Max(UserID) from [QiQiBoy_User_Disp]"
Set Rs=Conn.execute(Sql)
MaxUserID=Rs(0)
If isNull(MaxUserID) then MaxUserID=0
Sql="insert into [QiQiBoy_User_Disp] (UserID,UserName,Pwd,Sex,Area,Email,OICQ,Question,Answer,Websites,List,Photo,UserGroupID,Ip,Integral) values ("&MaxUserID+1&",'"&UserName&"','"&md5(Password)&"','"&Sex&"','"&Area&"','"&Email&"','"&OICQ&"','"&Question&"','"&md5(Answer)&"','"&Websites&"','"&List&"','"&Photo&"',1,'"&Ip&"',2)"
Set Rs=Conn.execute(Sql)
Sql="Update [QiQiBoy_Status_Disp] set RegUsers=RegUsers+1 where StatusID=1"
Set Rs=Conn.execute(Sql)
response.cookies("automember")=UserName
response.Cookies("automember").Expires=now()+365
end if
rs.close
set rs=nothing
end if
rs.close
set rs=nothing
Response.Write ("")
Response.end
% >
一、BOF 与 EOF 属性
通常我们在 ASP 程序中编写代码来检验 BOF 与 EOF 属性,从而得知目前指标所指向的 RecordSet 的位置,使用 BOF 与 EOF 属性,可以得知一个 Recordset 对象是否包含有记录或者得知移动记录行是否已经超出该 Recordset 对象的范围。
如:
< % if not rs.eof then ... %>
< % if not (rs.bof and rs.eof) %>
若当前记录的位置是在一个 Recordset 对象第一行记录之前时, BOF 属性返回 true,反之则返回 false。
若当前记录的位置是在一个 Recordset 对象最后一行记录之后时, EOF 属性返回 true,反之则返回 false。
BOF 与 EOF 都为 False:表示指标位于 RecordSet 的当中。
BOF 为 True:目前指标指到 RecordSet 的第一笔记录。 EOF 为 True:目前指标指到 RecordSet 的最后一笔记录。
BOF 与 EOF 都为 True:在 RecordSet 里没有任何记录。
二、 Move 方法
您可以用 Move 方法移动指标到 RecordSet 中的某一笔记录,语法如下:
rs.Move NumRecords,Start
这里的“rs”为一个对象变量,表示一个想要移动当当前记录位置的 Recordset 对象;“NumRecords”是一个正负数运算式,设定当前记录位置的移动数目;“start”是一个可选的项目,用来指定记录起始的标签。
所有的 Recordset 对象都支持 Move 方法,如果 NumRecords 参数大于零,当前记录位置向末尾的方向移动;如果其小于零,则当前记录位置向开头的方向移动;如果一个空的 Recordset 对象调用 Move 方法,将会产生一个错误。
MoveFirst 方法:将当前记录位置移至第一笔记录。
MoveLast 方法:将当前记录位置移至最后一笔记录。
MoveNext 方法:将当前记录位置移至下一笔记录。 MovePrevious 方法:将当前记录位置移至上一笔记录。
Move [n] 方法:移动指标到第 n 笔记录, n 由 0 算起。
用户修改信息程序(edit.asp)
<%
UserName=replace(trim(Request.Form("UserName")),"'","")
Password=replace(trim(Request.Form("Password")),"'","")
checkPassword=replace(trim(Request.Form("checkPassword")),"'","")
Sex=replace(trim(Request.Form("Sex")),"'","")
Area=replace(trim(Request.Form("Area")),"'","")
Email=replace(trim(Request.Form("Email")),"'","")
Oicq=replace(trim(Request.Form("Oicq")),"'","")
Question=replace(trim(Request.Form("Question")),"'","")
Answer=replace(trim(Request.Form("Answer")),"'","")
Websites=replace(trim(Request.Form("Websites")),"'","")
List=replace(trim(Request.Form("List")),"'","")
Photo=replace(trim(Request.Form("Photo")),"'","")
VerifyCode=replace(trim(Request.Form("VerifyCode")),"'","")
Yes=replace(trim(Request.Form("Yes")),"'","")
if isvalidemail(Email)=false then
response.write ("")
response.end
end if
<%
function isvalidemail(email)
dim names, name, i, c
isvalidemail = true
names = Split(email, "@")
if ubound(names) <> 1 then
isvalidemail = false
exit function
end if
for each name in names
if len(name) <= 0 then
isvalidemail = false
exit function
end if
for i = 1 to len(name)
c = lcase(mid(name, i, 1))
if inStr("abcdefghijklmnopqrstuvwxyz_-.", c) <= 0 and not isnumeric(c) then
isvalidemail = false
exit function
end if
next
if left(name, 1) = "." or right(name, 1) = "." then
isvalidemail = false
exit function
end if
next
if inStr(names(1), ".") <= 0 then
isvalidemail = false
exit function
end if
i = len(names(1)) - instrrev(names(1), ".")
if i <> 2 and i <> 3 then
isvalidemail = false
exit function
end if
if instr(email, "..") > 0 then
isvalidemail = false
end if
end function
%>
if Oicq="" then
response.write ("")
response.end
end if
if not isnumeric(Oicq) then
response.write ("")
response.end
end if
if Question="" then
response.write ("")
response.end
end if
if List<>"" then
if len(List)>250 then
response.write ("")
response.end
else
List=trim(List)
end if
end if
if Password<>"" then
if Password="" then
response.write ("")
response.end
end if
if checkPassword="" then
response.write ("")
response.end
end if
if checkPassword<>Password then
response.write ("")
response.end
end if
end if
Sql="update [QiQiBoy_User_Disp] set Pwd='"&Password&"',Sex='"&Sex&"',Area='"&Area&"',Email='"&Email&"',OICQ='"&Oicq&"',Question='"&Question&"',Answer='"&Answer&"',Websites='"&Websites&"',List='"&List&"',Photo='"&Photo&"' where UserID="&int(UserID)
Set Rs=Conn.execute(Sql)
response.Cookies("Pwd")=Password
end if
rs.close
set rs=nothing
response.redirect "edit.asp"
response.end
%>
用户列表程序(userlist.asp)
<%
set rs=server.CreateObject("ADODB.RecordSet")
Sql="select * from [QiQiBoy_User_Disp] Order By UserID desc"
rs.Open sql,conn,1,1
if not rs.eof then
%>
<%=int(rs(0))%>
<%=Topic_Filter(showstring(rs(1)))%>
<%=showstring(rs(4))%>
<%=showstring(rs(10))%>
<%=int(rs(14))%>
<%
else
exit for
end if
rs.movenext
next
%>
现在我们进入最关键的部分,版面模块部分。这是贴吧的主要功能。现在来看模块程序。
版面显示程序(class.asp)
<%
dim BoardNlass
BoardNlass=trim(request.querystring("Cid"))
Set rs =Server.CreateObject("ADODB.Recordset")
sql="select BoardNlassName from QiQiBoy_Nlass_Disp where BoardNlass="&int(BoardNlass)
Set Rs=Conn.execute(Sql)
BoardNlassName=rs(0)
Set N_rs = Server.CreateObject("ADODB.Recordset")
sql="select * from [QiQiBoy_Nlass_Disp] where BoardNlass="&int(BoardNlass)
N_rs.open sql,conn,1,1
if not N_rs.eof then
do while not N_rs.eof
BoardNlassID=N_rs("BoardNlass")
Set C_rs =Server.CreateObject("ADODB.Recordset")
sql="select * from [QiQiBoy_Class_Disp] where BoardNlass="&int(BoardNlassID)
C_rs.open sql,conn,1,1
if not C_rs.eof then
do while not C_rs.eof
BoardClassID=C_rs("BoardClass")
BoardClassName=C_rs("BoardClassName")
Sql="select count(*) from [QiQiBoy_Board_Disp] where BoardClass="&int(BoardClassID)
Set Rs=Conn.execute(Sql)
BoardID=rs(0)
rs.close
set rs=nothing
%>
<%
Set B_rs = Server.CreateObject("ADODB.Recordset")
sql="select Top 50 * from [QiQiBoy_Board_Disp] where BoardClass="&int(BoardClassID)
B_rs.open sql,conn,1,1
do while not B_rs.eof
%>
<%if not B_rs.eof then%> "><%=showstring(B_rs("BoardName"))%> <% B_rs.movenext end if %> <%if not B_rs.eof then%> "><%=showstring(B_rs("BoardName"))%> <% B_rs.movenext end if %> <%if not B_rs.eof then%> <% B_rs.movenext end if %> <%if not B_rs.eof then%> "><%=showstring(B_rs("BoardName"))%> <% B_rs.movenext end if %> <%if not B_rs.eof then%> "><%=showstring(B_rs("BoardName"))%> <% B_rs.movenext end if %>
<%
loop
B_rs.Close
set B_rs=nothing
C_rs.movenext
loop
end if
N_rs.movenext
loop
end if
conn.close
set conn=nothing
%>
未完待续。。。