您的位置:首页精文荟萃软件资讯 → 复杂表单的动态生成与动态验证

复杂表单的动态生成与动态验证

时间:2004/10/7 19:06:00来源:本站整理作者:蓝点我要评论(0)


            
             
              
             
            

               
               

            



            这里所谓的复杂表单,是指表单中包含多种不同的输入类型,比如下拉列表框、单行文本、多行文本、数值等。在经常需要更换这类表单的场合,需要有一个表单的动态生成程序。本文介绍的正是这样一个系统,它以数据库保存表单定义数据,利用ASP脚本动态生成表单HTML代码以及验证表单输入的脚本。
一、定义数据库表结构

   在Web上经常可以看到“每周调查”之类的表单,这就是一种需要经常更新的表单。如果有一个动态生成表单及其验证脚本的程序,可以大大减少制作这些表单的工作量。

   在本文的动态表单生成与验证示例中,我们使用一个Access数据库来存储有关表单的定义信息,同时为简单计,用户在表单中输入的数据也保存到同一数据库。定义表单需要两个表:第一个表(Definitons)用于表单输入域的定义,第二个表(Lists)保存各个输入域的附加信息,比如选择列表的选择项。

   表Definitons包含如下字段:

FieldName —— 赋予表单输入域的变量名字
Label —— 即文本标签,显示在输入域前面的提示性文字
Type —— 单个字符,该字符表示表单输入域的形式和输入值的类型,具体如下:
(t) 文本输入框,即< INPUT TYPE="TEXT" >。
(n) 文本输入框,但要求输入数字值。
(m) 备注型内容,用于注释或其他大量文本的输入,它是一个多行文本编辑框。
(b) 要求输入“是”或“否”。本实现中将用复选框来获取这种输入,复选框的文本标签为“是”。如果用户选中它,则返回值是“on”。
(r) 单选按钮。
(l) 下拉列表框。
Min —— 仅对数字型输入值有效,在这里给出最小值。在本例中有一个“Age”(年龄)数字型输入框,它的最小值设定为1。
Max —— 该字段的值与输入域形式有关。对于数字型输入框,它表示的是允许的最大值。例如“Age”的Max值为100。对于文本输入框,Max表示允许的最多字符个数。对于多行文本编辑框,Max表示可见区域的文本行数。
Required —— 表示是否必须输入。这种类型的值如果没有输入,则输入验证程序将报告错误。在表单中,必须输入的值以星号标记,并以脚注的形式提示用户该类值必须输入。
   本文的示例表单是一个ASP程序员调查表,在Definitons表中该表单的定义主要如下:

FieldName Label Type Min Max Required
Name 姓名 文本(t) - 50 否
Age 年龄 数字(n) 1 100 否
Sex 性别 单选按钮(r) - - 是
E-mail 邮件地址 文本(t) - - 是
Language 编程语言 下拉列表框(l) - - 否

   表Lists用于保存输入域定义的一些附加信息,本例有“Sex”和“Languages”两个输入值要用到它。表Lists非常简单,只包含如下三个字段:

FieldName —— 当前记录属于哪个表单输入域
Value —— 选择项的值
Label —— 用户所看到的选择项的提示文本
   输入域“Sex”只能从两个值选取:“男”或“女”。“Language”列出了几种可应用于ASP环境的编程语言,包括:VBScript,JavaScript,C,Perl和“其他”。

   第三个表“Records”保存用户提交的内容,它也包含三个字段,每个记录对应用户的一次提交:

Record —— 备注类型,以查询字符串形式保存的用户输入。
Created —— 用户提交该表单的日期和时间。 RemoteIP —— 表单提交者的IP地址。
   在实际应用中可能要收集更多有关用户的信息,为简单计,本例只记录提交时间和用户IP地址这两个附加信息。

   二、准备工作

   在完成上述数据结构和表单的定义之后,接下来就可以编写脚本。脚本的任务是生成表单以及处理用户提交的表单。

   无论是表单的生成还是处理,以下三个过程(任务)都是必不可少的:第一是确定验证类型,在生成表单时验证类型值通过查询字符串获得,在处理表单时从表单隐藏域读取。程序支持的表单验证方式共有以下四种类型:不进行验证,客户端JavaScript验证,服务器端ASP脚本验证,客户端和服务器端都进行验证(代号分别为0到3)。如果没有在查询字符串中指定合法的验证方式,则默认第四种验证方式。这种验证处理方式使得我们可以灵活地应用这个表单生成、处理系统,当客户端禁止使用JavaScript验证时就可以仅在服务器端执行验证过程。下面是确定验证类型的代码:

  '检查验证类型
  iValType = Request.QueryString("val")
  If IsNumeric(iValType) = False Then iValType = 3
  If iValType > 3 Or iValType < 0 Then iValType =3
   第二个任务是打开数据库连接,创建两个记录集对象:RS对象,这是本程序中的主要记录集对象,用来操作Definitions表;RSList对象,主要用于从Lists表读取数据。示例程序提供两种数据库连接方法:使用ODBC DSN或不使用ODBC DSN(使用DSN时需要先创建名为Dynamic的DSN,使用DSN连接数据库的代码已经被注释掉)。

   第三个任务是在生成(或处理)表单脚本的前面(和后面)输出一些静态的HTML代码,比如< HEAD >< /HEAD >,以及在脚本运行结束的时候释放RS、RSList等对象占用的资源。
   除了完成上述任务的代码外,示例应用中其余ASP脚本可能生成的页面有两种类型:提问表单(见上图)以及表单提交后出现的结果页面(后者同时还负责用户提交结果的记录)。要确定究竟运行哪一部分脚本,最简单的方法就是检查是否已经提交表单:如是,则处理表单;否则生成表单。

 '是生成表单还是处理表单?
  If Len(Request.Form) = 0 Then
  '生成表单
  ...略...
  Else
  '处理表单
  ...略...
  End If
   三、动态生成表单

   生成表单时,程序按照Definitons表中的各个输入域定义记录,依次生成相应的表单HTML代码和JavaScript代码。HTML代码中首先要生成的是文本标签:

 sHTML = sHTML & vbTab & "< TR >" & vbCrLf & vbTab & vbTab
 sHTML = sHTML & "< TD VALIGN=" & Chr(34) & "TOP" & Chr(34)
 sHTML = sHTML & " >" & vbCrLf & vbTab & vbTab & vbTab
 sHTML = sHTML & "< B >" & RS.Fields("Label")
   然后程序检查当前输入域是否必须输入。如果必须,则在标签文本之后加一个星号(表示该值必须输入),同时对于必须输入的值,还要生成相应的JavaScript代码来验证它。对于单选按钮或选择列表,需进一步检查用户确实选择了某个选项;对于所有其他输入类型,只要检查输入值不为空即可。

   紧接文本标签的是表单的输入元素,这些元素的HTML代码根据Definitions表中指定的类型和属性生成。再接下来就是根据输入值要求生成执行客户端验证任务的JavaScript代码。对于本例,只有数字型的值需要进一步检查以保证用户的输入确实是数字,而且数字值在许可的最大值和最小值之间。生成上述代码之后,就可以结束一个表格行(也就是一个输入域)继续处理Definitions表的下一个记录。一旦所有的数据库记录处理完毕,下一步就可以加入“提交”按钮和“清除”按钮的HTML代码。如果换个角度来看,程序在这里的任务就是根据数据库记录生成各个输入域,每个输入域占用一个表格行,每个表格行二个单元:第一个单元用来显示文本标签,第二个单元显示输入元素本身(代码见dForm.asp)。

   上述过程结束之后,表单的HTML代码和验证用JavaScript函数分别保存到了变量sHTML和sJavaScript中。在把这些内容写入页面之前,程序检查客户端是否要求执行JavaScript验证,如果不要求执行这类验证,则清除sJavaScript变量:

 If iValType = 0 Or iValType = 2 Then sJavaScript = ""
   在输出BODY标记之后,程序输出如下JavaScript函数:

 < SCRIPT LANGUAGE="JavaScript" >
 < !--
  function validate(TheForm){
  //客户端表单验证
  < %=sJavaScript% >
  return true;
  }
 
  function CheckRadio(objRadio){
  //单选按钮中是否有某个值被选中
  for(var n = 0; n < objRadio.length; n++){
  if(objRadio[n].checked){
  return true;
  }
  }
  return false;
  }
 
  function CheckList(objList){
  //是否已经在选择列表中选择了某个值
  for(var n = 1; n < objList.length; n++){
  if(objList.options[n].selected){
  return true;
  }
  }
  return false;
  }
 //-- >
 < /Script >
   如果客户端不需要JavaScript验证,则validate函数只剩下一个“return true”语句。上面代码中的后面两个静态JavaScript函数(CheckRadio和CheckList)用于验证单选按钮和下拉列表框,当这两种输入域需要验证时validate函数将调用它们。

   现在可以开始把表单写入页面:

 < FORM ACTION="./dform.asp" METHOD="POST" NAME="MyForm" onSubmit="return validate(this)" >
   在这里,只有当validate函数返回true时才执行表单提交操作。因此当客户端JavaScript验证功能关闭时,validate函数将自动返回true。

   接下来要加入的是名为val的隐藏域。如前所述,该值指示表单的验证模式。

 < INPUT TYPE="HIDDEN" NAME="val" VALUE="< %=iValType% >" >
   当用户提交表单时,处理脚本将根据该值确定是否执行服务器端验证。

   然后输出的是表格标记以及表格标题。标题保存在变量sTitleLabel中,该值在脚本开始执行时初始化:

 < TABLE BORDER="0" >
  < TR >
  < TD COLSPAN="2" ALIGN="CENTER" >
  < H2 >< %=sTitleLable% >< /H2 >
  < /TD >
  < /TR >
   作为改进措施,可以在表Definitions、Lists和Records中增加一个字段FormID。FormID唯一标识一个表单,这样程序就可以同时地定义多个表单、保存多个表单的用户应答结果。至于上面的sTitleLabel,我们可以用另外一个表(比如Forms)来保存。

   紧接着表格标记和表格标题,程序输出的是HTML表单以及“提交”、“清除”按钮的代码。在此之后,程序检查sHTML字符串中是否包含“*”,如包含的话说明表单中存在必须输入的内容,此时就输出一个脚注以说明该星号的含义。

 < %=sHTML% >
  < TR >
  < TD COLSPAN="2" ALIGN="CENTER" >
  < INPUT TYPE="SUBMIT" VALUE="提交表单" > < INPUT TYPE="reset" VALUE="清除" >
  < /TD >
 < %
  '是否存在必需输入的表单域,如存在,则输出表单脚注解释'*'的含义
  If InStr(sHTML,"*") Then
 % >
  < /TR >
  < TD COLSPAN="2" ALIGN="CENTER" >
  < FONT SIZE="2" >注意:有星号标记的值必需输入。< /FONT >
  < /TD >
  < /TR >
 < %
  End If
 % >
 < /TABLE >
 < /FORM >
   至此为止,表单的生成任务已经完成。

   四、处理提交结果

   ASP脚本剩下的任务是服务器端的表单处理,包括验证、将结果保存到数据库以及“提交成功/失败”页面的显示。在这部分表单验证代码中用到了一个字符串变量sBadForm,程序用它来保存错误信息。如果在验证过程结束时sBadForm为空,说明用户提交的表单是合法的;否则,拒绝该表单的提交并把sBadForm返回给浏览器。

   不管表单采用哪种验证模式,检查HTTP_REFERER都是一种好的习惯。这种检查可以防止脚本被盗用。要检查某个POST是否来自本网站的页面或脚本,只需比较两个服务器变量即可:

  If InStr(Request.ServerVariables("HTTP_REFERER"), _
  Request.ServerVariables("HTTP_HOST")) = 0 Then
  sBadForm = "< LI >表单提交自不正确的位置。" & vbCrlf
  End If
   如果表单的隐藏域指示必须进行服务器端验证,则程序遍历表单定义数据库记录作相应的检查,其过程与表单的生成非常相似,只不过此时程序是验证表单,且把输入值非法信息加入到sBadForm中去而已。具体代码见dForm.asp。

   程序最后检查sBadForm是否为空。如不为空,则拒绝表单提交并将sBadForm写入浏览器。如果sBadForm为空,则在Records表增加一个记录保存表单数据。在保存表单内容之前需要删除隐藏域val,这个隐藏域总是表单的第一个输入域:

  If Len(sBadForm) = 0 Then
  RS.Open "Records", DB, 3, 2, &H0002
  RS.AddNew
  RS.Fields("Record") = Mid(Request.Form, InStr(Request.Form, "&") + 1)
  RS.Fields("Created") = Now()
  RS.Fields("RemoteIP") = Request.ServerVariables("REMOTE_ADDR")
  RS.Update
  Response.Write("< H1 >谢谢.< /H1 >")
  RS.Close
  Else
  Response.Write("< H1 >表单提交失败。< /H1 >")
  Response.Write(vbCrLf & sBadForm)
  End If
  End If
   这就是服务器端表单处理的全部过程。根据是否存在已经提交的表单,我们可以把前面生成表单的代码和这里表单处理的代码用If语句封装,使得这两部分脚本共享部分公用代码,比如HTML文档的头、数据库对象的创建和资源释放等。

   总地看来,dForm.asp只具备了动态表单生成、验证所必需的核心功能,忽略了许多细节问题的处理。比如前面已经提到的多表单问题:增加一个表管理多个表单,使得脚本具有管理、生成、处理指定表单的能力。另外一个明显的缺乏是表单定义数据的增加、删除和更新功能,以及用户提交结果数据的访问,这类功能可以在一个独立的程序中实现,而且在大多数情况下可以做成传统的应用程序(非B/S结构的应用)。最后,dForm.asp支持的输入域类型也有限,在实践中可能会有其他的表单输入要求,比如专用的e-mail地址输入框等。然而,对于那些经常要更新表单的网站来说,本文所讨论的表单动态生成、动态验证功能确实是非常有用的。

相关阅读 Windows错误代码大全 Windows错误代码查询激活windows有什么用Mac QQ和Windows QQ聊天记录怎么合并 Mac QQ和Windows QQ聊天记录Windows 10自动更新怎么关闭 如何关闭Windows 10自动更新windows 10 rs4快速预览版17017下载错误问题Win10秋季创意者更新16291更新了什么 win10 16291更新内容windows10秋季创意者更新时间 windows10秋季创意者更新内容kb3150513补丁更新了什么 Windows 10补丁kb3150513是什么

文章评论
发表评论

热门文章 360快剪辑怎么使用 36金山词霸如何屏幕取词百度收购PPS已敲定!3

最新文章 微信3.6.0测试版更新了微信支付漏洞会造成哪 360快剪辑怎么使用 360快剪辑软件使用方法介酷骑单车是什么 酷骑单车有什么用Apple pay与支付宝有什么区别 Apple pay与贝贝特卖是正品吗 贝贝特卖网可靠吗

人气排行 xp系统停止服务怎么办?xp系统升级win7系统方电脑闹钟怎么设置 win7电脑闹钟怎么设置office2013安装教程图解:手把手教你安装与qq影音闪退怎么办 QQ影音闪退解决方法VeryCD镜像网站逐个数,电驴资料库全集同步推是什么?同步推使用方法介绍QQ2012什么时候出 最新版下载EDiary——一款好用的电子日记本