asp 与 database (3)

5.4  XML技术报表打印方案

随着Internet的迅速发展和广泛普及,XML的出现体现出了它的适用性和重要性。XML是由W3C定义的一种标记语言,由于XML是没有版权限制的,这样用户可以建立属于自己的一套软件而无须支付任何费用。利用ASP结合XML技术,可以实现对XML数据的报表打印操作。其原理是:通过XML强大的自定义功能,用户可以很方便地自定义出所需要的数据结构,然后在服务器端进行动态编码,通过Web服务器将数据发送到客户端,在客户端进行格式解析后,再根据服务器端定义的打印格式,从客户端直接控制打印机打印出所需要的报表。

5.4.1  打印XML数据报表

XML的出现推动了Web的发展。在XML文档中用户可以自己定义标记,从而明确表达出数据之间的结构关系。在一些数据量不是很大的情况下,可以使用XML文档作为存储数据的容器,因为相对于访问数据库而言,访问XML文档的速度比较快。在ASP应用程序中,可以访问XML文档中的数据,从而将其显示到页面中进行打印操作。

1.方案分析

XML具有灵活的语法和扩展性,极大地强化了保存数据和处理数据的能力。

XML文档中的标记是由用户自己定义的,浏览器是不能识别的,这就使得XML文档的数据和显示格式是分离的。在ASP中,通过DOM技术可以访问XML文档中的数据,然后将其内容显示到ASP页面中,再应用打印技术打印此XML数据报表。

打印XML数据报表的流程图,如图5.28所示。

图

图5.28  打印XML数据报表流程图

2.实施过程

01  实例位置光盘"mr"5"5.4"5.4.1

XML在处理数据的方面应用很广泛,在ASP中通过使用Microsoft XML类库,可以访问和操控XML文档中的数据,从而实现对数据的有效操作。下面以网上企业办公自动化管理系统为例,介绍如何将存储在XML文档中的员工工资信息读取到ASP页面并进行打印操作。运行效果如图5.29所示。

线形标注 2: 打印从XML文档中读取的数据报表图

图5.29  打印XML数据报表

在运行本例程之前,需要建立有效的XML文档,代码如下:

例程5-16  代码位置:光盘"mr"5"5.4"5.4.1"payfor.xml

<?xml version="1.0" encoding="gb2312"?>

<Records>

   <Record>

       <num>001</num>

       <Name>杨丽丽</Name>

       <age>31</age>

       <department>研发部</department>

       <payfor>5500</payfor>

       <other>1000</other>

   </Record>

   <Record>

       <num>002</num>

       <Name>刘圆圆</Name>

       <age>28</age>

       <department>销售部</department>

       <payfor>4600</payfor>

       <other>592</other>

   </Record>

   <Record>

       <num>003</num>

       <Name>李方方</Name>

       <age>25</age>

       <department>广告部</department>

       <payfor>4050</payfor>

       <other>976</other>

   </Record>

   <Record>

       <num>004</num>

       <Name>李明明</Name>

       <age>29</age>

       <department>采购部</department>

       <payfor>4650</payfor>

       <other>1050</other>

   </Record>

</Records>

在员工工资查看程序处理页面中,首先创建Document对象实例,然后设置该对象的async属性值为false(即不允许异步下载),并调用Document对象的Load方法加载指定的XML文档,再调用Document对象的getElementsByTagName方法以及childNodes属性读取XML文档中的数据。代码如下:

例程5-17  代码位置:光盘"mr"5"5.4"5.4.1"index.asp

<%

   Set xmlDoc=Server.CreateObject("Microsoft.XMLDOM")

   Set xml_Record=Server.CreateObject("Microsoft.XMLDOM")

   Set xml_child=Server.CreateObject("Microsoft.XMLDOM")

   xmlDoc.async=False

   xmlDoc.Load(Server.MapPath("payfor.xml"))

   If xmlDoc.parseError.errorCode <> 0 Then

     Response.Write("<tr><td colspan='6'>出现异常错误!</td></tr>")     

   Else

调用Document对象的getElementsByTagName方法返回指定名称的元素集合,使用集合的length属性获取到元素的总数,再应用for…to循环语句读取元素中各节点的内容。

     Set xml_Record=xmlDoc.getElementsByTagName("Record")

     record_num=xml_Record.length

     For i=0 to (record_num-1)

     Set xml_child=xml_Record.item(i)

  %>

<tr>

  <td height="22" align="center" valign="middle" bgcolor="#FFFFFF"><%=xml_child.childNodes(0).text%></td>

  <td height="22" align="center" valign="middle" bgcolor="#FFFFFF"><%=xml_child.childNodes(1).text%></td>

  <td height="22" align="center" valign="middle" bgcolor="#FFFFFF"><%=xml_child.childNodes(2).text%></td>

  <td height="22" align="center" valign="middle" bgcolor="#FFFFFF"><%=xml_child.childNodes(3).text%></td>

  <td height="22" align="center" valign="middle" bgcolor="#FFFFFF"><%=xml_child.childNodes(4).text%></td>

  <td align="center" valign="middle" bgcolor="#FFFFFF"><%=xml_child.childNodes(5).text%></td>

</tr>

<%Next

  End If

%>

将XML文档中的数据信息显示到ASP页面后,就可以应用WebBrowse组件对页面中的报表信息进行打印操作了。代码如下:

例程5-18  代码位置:光盘"mr"5"5.4"5.4.1"index.asp

<style type="text/css">

@media print{

.Noprint{display:none /*应用该样式的对象在实际打印时将不可见*/

}

</style>

<object id=WebBrowser classid=ClSID:8856F961-340A-11D0-A96B-00C04Fd705A2 width="0" height="0"></object>

<a href="#" onclick="document.all.WebBrowser.Execwb(8,1)" class="Noprint">页面属性</a> <a href="#" onclick="document.all.WebBrowser.Execwb(7,1)" class="Noprint">打印预览</a> <a href="#" onclick="document.all.WebBrowser.Execwb(6,1)" class="Noprint">打印</a>

   注意:在打印时,通过页面设置可以设置打印时的边距。

3.补充说明

在实际应用中,有时需要将数据库中的数据导出到XML文档中,再进行下一步的操作(如打印XML数据库报表、查询XML数据等)。

通过创建XML文档对象,并设置对象的相关属性和调用相关方法,可以实现将数据库中的数据写入到指定XML文档的功能,代码如下:

<%

If Not Isempty(Request("sure")) Then

'将数据库中的数据写入到XML文档中

Set rs = Server.CreateObject("ADODB.RecordSet")

sqlstr = "SELECT * FROM tb_user"   

rs.Open sqlstr,conn,1,1

If rs.Eof Then

  Response.Write("<script language='javascript'>alert('数据库中暂无记录,请添加记录后再尝试运行本程序!');window.location.href='index.asp';</script>")

  Response.End()

Else       

  Dim objXMLDOM, objRootNode, objNode

  Set objXMLDOM = Server.CreateObject("MSXML2.DOMDocument") '创建XML文档对象

  Set objRootNode = objXMLDOM.createElement("xml") '创建根节点  

  objXMLDOM.documentElement = objRootNode

  Do While Not rs.Eof      

       Set objRowNode = objXMLDOM.createElement("row") '创建父节点

       Set objNode = objXMLDOM.createElement("UserName") '创建子节点

       objNode.text = rs("UserName")

       objRowNode.appendChild(objNode)

       Set objNode = objXMLDOM.createElement("UserPassword") '创建子节点

       objNode.text = rs("Upwd")           

       objRowNode.appendChild(objNode)                 

       Set objNode = objXMLDOM.createElement("UserTel")     '创建子节点      

       objNode.text = rs("Utel")           

       objRowNode.appendChild(objNode)                 

       objRootNode.appendChild(objRowNode)       

       rs.MoveNext

  loop                

objXMLDOM.Save Server.MapPath("MyXMLDoc.xml")

Response.Write("<script language='javascript'>alert('将数据库中的数据成功写入到XML文档中!');window.location.href='index.asp';</script>")

  Set objNode = Nothing            

  Set objRowNode = Nothing        

  Set objRootNode = Nothing    

End If   

rs.Close   

Set rs = Nothing

End If

%>

5.4.2  分页报表打印

在一般情况下,显示数据的页面都会提供分页程序,以方便用户查看数据信息。在ASP应用程序中,可以使用JavaScript脚本语言来操作XML文档中存储的数据,并将信息进行分页显示。

1.方案分析

在使用XML文档作为存储数据的容器时,根据实际情况,对显示的数据可以进行分页控制。应用JavaScript脚本语言可以创建XML的Document对象,并使用Document对象的相关属性和方法,读取XML文档中各节点包含的数据,同时还可以对数据进行分页控制,然后在ASP页面中通过CSS样式来规范读取到的XML数据的显示格式,最后应用打印技术按照显示的分页效果打印XML数据报表。

分页报表打印的流程图,如图5.30所示。

图

图5.30  分页报表打印的流程图

2.实施过程

01  实例位置光盘"mr"5"5.4"5.4.2

使用JavaScript脚本语言可以操纵XML文档中的数据,并可以将获取到的数据进行分页处理。在ASP页面中,应用CSS样式可以定义XML数据的显示格式。下面以校园管理系统的档案管理模块为例,介绍应用JavaScript脚本语言将读取到的XML数据进行分页显示,并对显示在页面中XML数据报表进行打印。运行效果如图5.31所示。

线形标注 2: 打印从XML文档中读取到的分页报表数据图

图5.31  分页报表打印

在运行本例程之前,需要建立有效的XML文档,代码如下:

例程5-19 代码位置:光盘"mr"5"5.4"5.4.2"resume.xml

<?xml version="1.0" encoding="gb2312"?>

<Persons>

   <Person>

       <Name>张三</Name>

       <Sex>男</Sex>

       <Grand>本科</Grand>

       <Tel>139565580</Tel>

       <Email>1@1.com</Email>

       <Like>计算机、英语</Like>

   </Person>

   <Person>

       <Name>李四</Name>

       <Sex>男</Sex>

       <Grand>本科</Grand>

       <Tel>133884580</Tel>

       <Email>2@1.com</Email>

       <Like>计算机、运动</Like>

   </Person>

   <Person>

       <Name>王元元</Name>

       <Sex>女</Sex>

       <Grand>专科</Grand>

       <Tel>135899680</Tel>

       <Email>3@1.com</Email>

       <Like>日语、英语</Like>

   </Person>

   <Person>

       <Name>赵明明</Name>

       <Sex>女</Sex>

       <Grand>本科</Grand>

       <Tel>139258880</Tel>

       <Email>4@1.com</Email>

       <Like>绘画、英语</Like>

   </Person>

</Persons>

在档案信息列表查看页面中,用户可以通过单击“前一页”或“后一页”超链接,进行分页查看信息的操作,也可以通过选择下拉列表框中的页码来分页查看数据信息。在此页面中,提供了“直接打印”、“页面属性”、“打印预览”和“打印”4个关于打印技术的超链接,用户可以根据实际需要进行相应的操作。

在程序处理页面编写的JavaScript脚本中,首先创建XML的Document对象实例,调用对象的load方法加载指定的XML文档;然后获取XML文档中指定元素的个数,以及元素中包含节点的数目,根据所设置的初始值,计算显示的页码总数;再定义执行翻页操作的相关函数,并在定义的显示XML文档内容的函数中包含显示分页状态的函数;最后调用显示XML文档内容的函数,实现分页显示XML数据报表的功能。代码如下:

例程5-20 代码位置:光盘"mr"5"5.4"5.4.2"index.asp

<script language="javascript">

var pagenum=2; //每页显示的记录数

var page=0; 

var BodyHTML="";

var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");

var mode="Person";

创建Document对象实例后,加载指定的XML文档。

xmlDoc.async=false;

xmlDoc.load("resume.xml");

header="<table align='center' width='500' cellspaceing='1' cellpadding='2' border='1' bgcolor='#FFFFEE'><caption>职工档案登记表</caption><tr align='center' class='title' bgcolor='#C1E6DB'><td>姓名</td><td>性别</td><td>学历</td><td>电话</td><td>Email</td><td>爱好</td></tr>";

获取XML文档中的记录条数,以及记录包含的字段数,并计算显示的总页码数。

recordNum=xmlDoc.getElementsByTagName(mode).length;

column=xmlDoc.getElementsByTagName(mode).item(0).childNodes;

colNum=column.length;

//计算总页数

pagesNumber=Math.ceil(recordNum/pagenum)-1;

自定义显示“前一页”超链接的函数。

function Up_Page(page)

{

thePage="<font class='input'>前一页</font>"

if(page+1 > 1) thePage="<a class='input' href='#' onclick='JavaScript:return UpPageGo()'>前一页</a>";

return thePage;

}

function UpPageGo()

{

if(page > 0) page--;

showContent();

BodyHTML="";

}

自定义显示“后一页”超链接的函数。

function Next_Page(page)

{

thePage="<font class='input'>后一页</font>"

if(page < pagesNumber) thePage="<a class='input' href='#' onclick='JavaScript:return NextPageGo()'>后一页</a>";

return thePage;

}

function NextPageGo()

{

if(page < pagesNumber) page++;

showContent();

BodyTex="";

}

自定义显示当前页码的函数。

function currentPage()//显示当前页码

{

var str;

str="<font class='input'>当前是第"+(page+1)+"页</font>";

return str;

}

自定义显示总页码的函数。

function totalPage()//显示总页码

{

var str;

str="<font class='input'>共有"+(pagesNumber+1)+"页</font>";

return str;

}

自定义显示“分页状态条”的函数。

function pageBar(page)//显示分页状态条

{

var str;

str="<br><center class='Noprint'>"+Up_Page(page)+" "+Next_Page(page)+" "+currentPage()+" "+totalPage()+selectPage()+"</center>";

return str;

}

自定义自动转换显示页的函数。

function changePage(tpage)

{

page=tpage;

if(page >= 0) page--;

if(page < pagesNumber) page++;

showContent();

BodyHTML="";

}

自定义具体显示页码功能的下拉列表框函数。

function selectPage()

{

var sp;

sp="<select name='sel_page' onChange='javascript:changePage(this.options[this.selectedIndex].value)'>";

sp=sp+"<option value=''></option>";

for(t=0;t<=pagesNumber;t++)

{

  sp=sp+"<option value='"+t+"'>"+(t+1)+"</option>";

}

sp=sp+"</select>";

return sp;

}

自定义显示XML文档内容的函数。

function showContent()//将XML中的数据显示到页面中

{

if(!page) page=0;

n=page*pagenum;

endNum=(page+1)*pagenum;

if(endNum > recordNum) endNum=recordNum;

BodyHTML=header+BodyHTML;

for(;n<endNum;n++)

{

  kn=n+1;

  BodyHTML=BodyHTML+"<tr>";

  for(mNum=0;mNum<=colNum-1;mNum++)

  {

    mName=column.item(mNum).tagName;

   BodyHTML=BodyHTML+("<td>"+xmlDoc.getElementsByTagName(mName).item(n).text+"</td>");

  }

  BodyHTML=BodyHTML+"</tr>";

}

document.all.showXML.innerHTML=BodyHTML+"</table>"+pageBar(page);

BodyHTML="";

}

调用自定义的showContent()函数,将XML文档中的数据信息显示到页面中指定的DIV标记中。

if(recordNum==0)

{

  document.Write("没有可以显示的数据!");

}

else

{

  showContent();

}

</script>

将XML文档中的内容显示到页面后,可以调用WebBrowser组件对报表进行打印,代码如下:

例程5-21 代码位置:光盘"mr"5"5.4"5.4.2"index.asp

<div id="showXML"></div>

<p class="Noprint">

<object id=WebBrowser classid=ClSID:8856F961-340A-11D0-A96B-00C04Fd705A2 width="0" height="0"></object>

<a href="#" onClick="document.all.WebBrowser.Execwb(6,6)">直接打印</a> <a href="#" onClick="document.all.WebBrowser.Execwb(8,1)">页面属性</a> <a href="#" onClick="document.all.WebBrowser.Execwb(7,1)">打印预览</a> <a href="#" onClick="document.all.WebBrowser.Execwb(6,1)">打印</a>

</p>

在页面中应用的CSS样式定义如下:

例程5-22 代码位置:光盘"mr"5"5.4"5.4.2"Include"css.css

body,td{font-size:9pt}

A:link{color:#0000FF; text-decoration:none;}

A:visited{color:#0000FF; text-decoration:none;}

A:active{color:#3333ff; text-decoration:none;}

A:hover{color:#FF0000; text-decoration:none;}

td{font-size:9pt; line-height:150%}

.title{font-size:10.8pt; font-weight:bold}

.alert{font-size:9pt; color:#990000; font-weight:bold}

.input{font-size:9pt}

3.补充说明

除了使用JavaScript脚本语言对XML文档中的数据进行分页操作,在ASP中也可以将XML数据分页显示到网页中。具体实现步骤如下:

(1)创建一个XML的FreeThreadedXMLDOM对象,并加载指定的XML文档,然后选取相关节点,代码如下:

<%

Set newXML=Server.CreateObject("Microsoft.FreeThreadedXMLDOM")

newXML.load(server. mappath("content.xml"))

Set newobj=newXML.documentElement.selectSingleNode("newxml")

%>

(2)通过以下代码实现对XML数据进行分页显示,代码如下:

<%

PageSize =5

'设置每页显示5条留言信息

newNum =newobj.childNodes.length-1

PageN=newNum"PageSize+1

'算出总页数

PNo=request.querystring("PageNo")

if PNo="" then

'确定每一页显示最新的留言

PNo=PageN

end if

Ends=PNo*PageSize-1

'获得起始节点

Strs=(PNo-1)*PageSize

'获得结束节点

if Strs<0 then

Strs=0

end if

if Ends>newNum then

Strs=Strs-(Ends-newNum)

Ends=newNum

end if

if Strs<0 then

Strs=0

end if

while Strs<=Ends

'从结束节点到起始节点之间读取节点数据

title=newobj.childNodes.item(Strs).childNodes.item(0).text

content = newobj.childNodes.item(Strs).childNodes.item(1).text

'取得留言内容

content = replace(content,chr(13),"<br>")

'应用replace函数替代回车符

content = replace(content,chr(32)," ")

'应用replace函数替代空格符

%>

<tr>

<td ><div align="center" class="STYLE2"><%=title%></div></td>

<td class="STYLE2"><div align="center"><%=content%></div></td>

</tr>

<%

Strs=Strs+1

wend

set newXML=nothing

%>  

</table><br>共有<<%=PageN%>>页

<%

'分页

if cint(PNo)<>1 then

response.write "<a href='index.asp?PageNo="&(PNo-1)&"'>上一页</a> "

end if

if cint(PNo)<>PageN then       

response.write "<a href='index.asp?PageNo="&(PNo+1)&"'>下一页</a>"

end if

%>

5.4.3  XSL浏览报表打印

XSL语言可以用于转换XML文档,也可以格式化XML文档。应用XSL语言可以定义XML文档的显示格式,即将XML文档转换成能被浏览器识别的HTML文件;应用XSL语言还可以向输出文件中添加新的元素、重新排列数据以及决定哪些元素显示哪些元素不显示等。

根据实际需要,可以通过XSL格式化XML文档,并使数据信息以一定的格式显示到ASP页面中,然后对报表数据执行打印操作。

1.方案分析

使用XSL语言可以灵活、快速地定义出XML文档的显示格式,使格式化后的XML文档数据以清晰的结构显示在用户面前。在ASP程序中,可以应用XSL浏览XML数据报表,并进行打印操作。

首先,用户需要建立有效的.xml文件和.xsl文件,然后在ASP程序中创建XML的DOMDocument对象实例,应用该对象的相关方法加载建立好的两个文件,并应用.xsl文件来格式化.xml文件,这样XML文档中的数据就能够以.xsl文件规定的格式进行显示了,再应用相关的打印技术打印显示在ASP页面中的数据报表。

XSL浏览报表打印的流程图,如图5.32所示。

图

图5.32  XSL浏览报表打印流程图

2.实施过程

01  实例位置光盘"mr"5"5.4"5.4.3

在实际应用中,不仅可以通过CSS样式来定义XML文档的显示格式,还可以应用XSL语言来转换或格式化XML文档,使浏览器可以识别XML文档中的数据结构,从而使数据以指定的格式显示在页面中。下面以企业绩效管理系统的员工考勤模块为例,介绍如何使用XSL格式化XML文档,并将XML文档中的数据以分页的形式显示在页面中,然后打印显示的报表。运行效果如图5.33所示。

线形标注 2: 打印以XSL格式化的XML文档中的数据报表图

图5.33  XSL浏览报表打印

在运行本例程之前,需要建立有效的XML文档,代码如下:

例程5-23  代码位置:光盘"mr"5"5.4"5.4.3"emp_work.xml

<?xml version="1.0" encoding="gb2312"?>

<Persons>

   <Person>

       <num>001</num>

       <date>2007年9月</date>

       <Name>张三</Name>

       <department>研发部</department>

       <count>10</count>

       <day>1</day>

   </Person>

   <Person>

       <num>002</num>

       <date>2007年9月</date>

       <Name>李四</Name>

       <department>销售部</department>

       <count>2</count>

       <day>0</day>

   </Person>

下面定义了两个<Person2>的标记,作为分页的标识。

   <Person2>

       <num>003</num>

       <date>2007年9月</date>

       <Name>杨林林</Name>

       <department>企划部</department>

       <count>0</count>

       <day>2</day>

   </Person2>

   <Person2>

       <num>004</num>

       <date>2007年9月</date>

       <Name>孙圆圆</Name>

       <department>广告部</department>

       <count>1</count>

       <day>0</day>

   </Person2>

</Persons>

建立了有效的XML文档后,为此XML文档建立.xsl文件,在.xsl文件中使用表格来规定数据的显示格式。代码如下:

例程5-24  代码位置:光盘"mr"5"5.4"5.4.3"emp_work.xsl

<?xml version="1.0" encoding="gb2312"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="/Persons">

首先在<p>标记中建立表格,此表格的作用是使XML文档中<Person>标记内的数据显示在指定的单元格中。

<p><table align="center" width="500" cellpadding="2" cellspacing="1" border="0" bgcolor="#666600" class="table_style">

<caption align="center">员工考勤记录表</caption>

  <tr align="center" class="title" bgcolor="#e5e5e5">

    <td width="25"><xsl:text disable-output-escaping="yes"></xsl:text></td>

   <td>序号</td>

   <td>日期</td>

   <td>姓名</td>

   <td>所属部门</td>

   <td>早退迟到次数</td>

   <td>缺席天数</td>

  </tr>

  <xsl:for-each select="Person">

  <tr bgcolor="#ffffff">

    <td align="right"><xsl:value-of select="position()"/></td>

   <td style="color:#990000" align="center"><xsl:value-of select="num"/></td>

   <td style="color:#990000" align="center"><xsl:value-of select="date"/></td>

   <td style="color:#990000" align="center"><xsl:value-of select="Name"/></td>

   <td style="color:#990000" align="center"><xsl:value-of select="department"/></td>

   <td style="color:#990000" align="center"><xsl:value-of select="count"/></td>

   <td style="color:#990000" align="center"><xsl:value-of select="day"/></td>

  </tr>

  </xsl:for-each>

</table></p>

再次在<p>标记中建立表格,此表格的作用是使XML文档中<Person2>标记内的数据显示在指定的单元格中。

<p><table align="center" width="500" cellpadding="2" cellspacing="1" border="0" bgcolor="#666600" class="table_style">

  <tr align="center" class="title" bgcolor="#e5e5e5">

    <td width="25"><xsl:text disable-output-escaping="yes"></xsl:text></td>

   <td>序号</td>

   <td>日期</td>

   <td>姓名</td>

   <td>所属部门</td>

   <td>早退迟到次数</td>

   <td>缺席天数</td>

  </tr>

  <xsl:for-each select="Person2">

  <tr bgcolor="#ffffff">

    <td align="right"><xsl:value-of select="position()"/></td>

   <td style="color:#990000" align="center"><xsl:value-of select="num"/></td>

   <td style="color:#990000" align="center"><xsl:value-of select="date"/></td>

   <td style="color:#990000" align="center"><xsl:value-of select="Name"/></td>

   <td style="color:#990000" align="center"><xsl:value-of select="department"/></td>

   <td style="color:#990000" align="center"><xsl:value-of select="count"/></td>

   <td style="color:#990000" align="center"><xsl:value-of select="day"/></td>

  </tr>

  </xsl:for-each>

</table></p>

</xsl:template>

</xsl:stylesheet>

建立了有效的.xml文件和.xsl文件后,自定义一个函数,此函数的作用是创建XML的DOMDocument对象实例,应用对象的load方法分别加载.xml文件和.xsl文件,然后调用DOMDocument对象的TransformNode方法使用.xsl文件格式化.xml文件。代码如下:

例程5-25  代码位置:光盘"mr"5"5.4"5.4.3"Include"formatxml.asp

<%

Function FormatXML(XMLfile,XSLfile)

Dim objXML,objXSL

strXMLfile=Server.MapPath(XMLfile)

strXSLfile=Server.MapPath(XSLfile)

Set objXML=Server.CreateObject("MSXML2.DOMDocument")

Set objXSL=Server.CreateObject("MSXML2.DOMDocument")

objXML.async=false

If objXML.Load(strXMLfile) Then

  objXSL.async=false

  objXSL.ValidateonParse=false

  If objXSL.Load(strXSLfile) Then

    On Error Resume Next

   FormatXML=objXML.transformNode(objXSL)'很重要

   If objXSL.parseError.errorCode <> 0 Then

     Response.Write("<br><hr>")

     Response.Write("Error Code: "&objXSL.parseError.errorCode)

     Response.Write("<br>Error Reason: "&objXSL.parseError.reason)

     Response.Write("<br>Error Line: "&objXSL.parseError.line)

     FormatXML="<span class=""alert"">格式化XML文件错误!</span>"

   End IF

  Else

     Response.Write("<br><hr>")

     Response.Write("Error Code: "&objXSL.parseError.errorCode)

     Response.Write("<br>Error Reason: "&objXSL.parseError.reason)

     Response.Write("<br>Error Line: "&objXSL.parseError.line)

     FormatXML="<span class=""alert"">格式化XML文件错误!</span>"

  End If

Else

     Response.Write("<br><hr>")

     Response.Write("Error Code: "&objXSL.parseError.errorCode)

     Response.Write("<br>Error Reason: "&objXSL.parseError.reason)

     Response.Write("<br>Error Line: "&objXSL.parseError.line)

     FormatXML="<span class=""alert"">格式化XML文件错误!</span>"

End If

Set objXML=Nothing

Set objXSL=Nothing

End Function

%>

做好前期准备之后,在首页面中包含Include文件夹中的formatxml.asp文件,调用自定义的FormatXML(XMLfile,XSLfile)函数显示XML文档中的数据信息,并引用WebBrowser组件打印页面中的XML数据报表。代码如下:

例程5-26  代码位置:光盘"mr"5"5.4"5.4.3"index.asp

<style media="print">

.Noprint{display:none;}

</style>

<!--#include file="Include/formatxml.asp"-->

<%=FormatXML("emp_work.xml","emp_work.xsl")%>

<object id=WebBrowser classid=ClSID:8856F961-340A-11D0-A96B-00C04Fd705A2 width="0" height="0">

</object>

<p> <a href="#" onclick="document.all.WebBrowser.Execwb(8,1)" class="Noprint">页面属性</a> <a href="#" onclick="document.all.WebBrowser.Execwb(7,1)" class="Noprint">打印预览</a> <a href="#" onclick="document.all.WebBrowser.Execwb(6,1)" class="Noprint">打印</a> </div></p>

3.补充说明

除了调用XML对象的相关方法使用.xsl文件格式化.xml文件,还可以在XML文档中直接链接指定的.xsl文件,从而实现转换XML文档格式的效果。代码如下:

XSL样式表文件xmlf.xsl。

<?xml version="1.0" encoding="gb2312"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

<xsl:template match="/">

   <html>

   <body>

   <center>

   <table width="300" height="30" border="10" cellspacing="0" cellpadding="0">

     <tr align="center">

       <td>书名</td>

       <td>页码</td>

     </tr>

<xsl:for-each select="PUBLICATION/BOOK">

     <tr align="center" height="30">

       <td><xsl:value-of select="TITLE"/></td>

       <td><xsl:value-of select="PAGES"/></td>

     </tr>

</xsl:for-each>     

   </table>

   </center>

   </body>

   </html>

</xsl:template>

</xsl:stylesheet>

XML文件index.xml。

<?xml version="1.0" encoding="gb2312"?>

<?xml-stylesheet type="text/xsl" href="xmlf.xsl"?>

<PUBLICATION>

   <BOOK>

       <TITLE>ASP技术</TITLE>

       <PAGES>760</PAGES>

   </BOOK>

   <BOOK>

       <TITLE>SQL技术</TITLE>

       <PAGES>520</PAGES>

   </BOOK>

</PUBLICATION>

在XML文档中如果链接了多个XSL样式表,浏览器将使用第一个XSL样式表而忽略其他XSL样式表;如果同时链接一个CSS样式表文件和一个XSL样式表,浏览器将只使用XSL样式表。

5.5  其他报表打印方案

除了以上介绍的Excel报表打印方案、XML技术报表打印方案和Crystal Report水晶报表打印方案,在ASP程序中还可以应用其他技术来实现报表打印的功能。本节将介绍Word报表打印、自定义ActiveX组件打印Access报表、图形报表打印以及套打报表。

5.5.1  Word报表打印

Microsoft Word是微软公司推出的Microsoft Office办公软件中的一个组件,它是一个功能强大的文字处理软件,可以进行文字输入、编辑、排版和打印操作等。在ASP程序中,可以创建Word的相关对象将网页中的内容导入到Word中,也可以调用Word中的数据报表,然后进行报表打印。

1.方案分析

在Web服务器上安装了Microsoft Word软件后,ASP就可以创建Word的相关对象,从而应用该对象的属性和方法对网页中的数据或者Word文档中的数据进行操作了。

网页上显示的数据一般都是从数据库中读取出来的,创建Word的Application对象可以将网页中具有一定显示格式的数据导入到Word文档中,然后进行报表打印的操作。

在一些实际工作中,用户可能会应用Word文档来存储一些数据报表(如:制作商务表格等),并进行排版工作等,为了方便用户查看Word文档中的内容,ASP可以编写动态代码打开指定的Word文档,然后再执行打印命令。

Word报表打印的流程图,如图5.34所示。

图

图5.34  Word报表打印的流程图

2.实施过程

Microsoft Word在文字编辑、打印方面的应用很广泛,ASP通过调用Word的相关对象可以访问Word文档中的数据内容。下面介绍两种在ASP程序中通过Word进行报表打印的方法,分别是将网页内容导入到Word和打印Word报表。

l          方法一  将网页内容导入到Word

01  实例位置光盘"mr"5"5.5"5.5.1"01

在本章的5.2节中介绍了Excel报表打印方案,在ASP中不仅可以将网页中的内容保存到Excel中,还可以将网页中指定的内容导入到Word中。下面以企业内部管理系统的库存管理模块为例,介绍将网页中显示的数据导入到Word,然后再进行打印操作的过程。运行结果如图5.35所示。

线形标注 2: 将从数据库中读取到的数据导入到Word中,再进行打印操作图

图5.35  将网页内容导入到Word

在库存商品信息查看页面中,可以浏览到从库存商品信息表中读取到的数据信息。代码如下:

例程5-27  代码位置:光盘"mr"5"5.5"5.5.1"01"index.asp

<%

    Set rs=Server.CreateObject("ADODB.Recordset")

   sqlstr="select * from tb_store"

   rs.open sqlstr,conn,1,1

   do while not rs.eof

%>

<tr align="center">

  <td height="26"><%=rs("Gname")%></td>

  <td height="26"><%=rs("Gunit")%></td>

  <td width="93" height="26"><%=rs("Gstd")%></td>

  <td width="167" height="26"> <%=rs("Gprovide")%></td>

  <td width="85" height="26"> <%=rs("Gconect")%></td>

</tr>

<%

    rs.movenext

   loop

   rs.close

   Set rs=Nothing

%>

<div align="center"><a href="vbscript:" onClick="vbscript:SaveDoc()">Word报表打印</a></div>

单击页面中的“Word报表打印”超链接,就可以将表格中的数据写入到Word文档中,同时生成的临时Word文档会自动打开。运行效果如图5.36所示。

图5.36  保存网页内容的Word文档

在程序处理页面的客户端VBScript脚本中,自定义一个子过程用于将网页中的表格数据写入到Word文档中。具体的实现步骤如下:

(1)创建一个Word的Application对象实例,再调用Word的Documents集合的Add方法建立一个新的文档,并将页面中的表格数据存储在一个数组中。

(2)将表格的标题写入到Word中,并增添一个空行。

(3)在Word文档中建立一个表格,并将数组中的内容填写在该表格中。

(4)保存新建立的Word文档。

代码如下:

例程5-28  代码位置:光盘"mr"5"5.5"5.5.1"01"index.asp

<script language="vbscript">

Sub SaveDoc

Dim Table1

Set table1=document.all.data

row=Table1.rows.length

set wdapp=CreateObject("Word.Application")  //创建Word应用程序

wdapp.visible=true

set wddoc=wdapp.documents.add  //添加新的文档

colnum =Table1.rows(1).cells.length

将页面中表格的内容存放在数组中。

reDim theArray(colnum,row)

For i=0 to row-1

   For j=0 to colnum-1

       thearray(j+1,i+1)=table1.rows(i).cells(j).innerHTML

   next

next

intNumrows=row

将表格的标题信息写入到Word文档中,并设置其字体样式。

wdapp.application.activedocument.paragraphs.add.range.insertbefore("库存商品记录表")

set rngpara=wdapp.application.activedocument.paragraphs.add.range

with rngpara

.paragraphformat.alignment=1

.font.name="arial"

.font.size=9

End with

Set rngPara=wdapp.Application.ActiveDocument.Paragraphs(1).Range

With rngPara

.Bold=True

.ParagraphFormat.Alignment=1

.Font.Name="Arial"

.Font.Size=12

End With

在文档的指定段落的区域内,添加一表格,将数组中的数据写入到表格中。

set rngcurrent=wdapp.application.activedocument.paragraphs(3).range

set tabCurent=wdapp.application.activedocument.tables.add(rngcurrent,intnumrows,colnum)

For i=1 To row

   For j=1 to colnum           wdapp.application.activeDocument.Tables(1).Rows(i).Cells(j).Range.InsertAfter theArray(j,i)         wdapp.application.activeDocument.Tables(1).Rows(i).Cells(j).Range.paragraphFormat.alignment=1

   next

next

保存建立的Word文档。

wdapp.application.activeDocument.SaveAs "NewDoc.doc",0,false,"",true,"",false,false,false,false,false

End sub

</script>

将网页中的内容导入到Word文档后,用户可以根据实际需要再对数据报表进行编辑操作,然后打印报表。

l          方法二  打印Word报表

01  实例位置光盘"mr"5"5.5"5.5.1"02

在ASP中不仅可以调用Word的相关对象将网页中的内容导入到Word,还可以打开Word文档直接进行打印操作。下面以企业营销管理系统的销售报表模块为例,介绍如何打开指定的Word报表文件,并进行打印操作。运行效果如图5.37所示。

图

图5.37  打印Word报表

在销售报表查看和打印页面中,首先选择相关的Word文档,然后单击“Word报表打印”按钮,这时选择的Word文档将自动打开,并处于打印的状态中。

为了便于读者理解,下面以列表的形式给出销售报表查看页面index.asp中所涉及到的表单及表单元素,如表5.8所示。

表5.8                 销售报表查看页面index.asp中的表单及表单元素

名称

元素类型

重要属性

含义

form

form

action="" method="post" enctype="multipart/form-data"

选择需要打印的Word文档

file1

input

type="file" id="file1" size="20"

确定Word文档的路径

print

input

type="submit" id="print" onClick="openWord(file1.value)"

Excel文件路径

在页面中单击“Word报表打印”按钮后的运行效果如图5.38所示。

图5.38  打开指定的Word文档

在程序处理页面中的客户端VBScript脚本中,自定义一个子过程用于打开并打印指定的Word文档。在该子过程中,首先创建Word的Application对象实例,再调用Documents集合的Open方法打开Word文档,最后调用Printout方法打印Word文档。代码如下:

例程5-29  代码位置:光盘"mr"5"5.5"5.5.1"02"index.asp

<script language="vbscript">

Sub openWord(filename) 

Set wrd=CreateObject("word.Application")

wrd.visible=true

wrd.Documents.Open(filename)

wrd.Application.Printout()

wrd=null

End Sub

</script>

3.补充说明

Microsoft Word是常用的文字编辑工具,使用Word可以进行记录会议内容、起草协议等工作。为了用户操作方便,在ASP中可以调用Word直接打印页面中的数据信息,即将用户在表单中输入的信息直接封装到Word中,然后再进行打印操作。如图5.39所示。

18-116

图5.39  调用Word进行Web打印

自定义一个VBScript脚本子过程,在该子过程中,首先获取页面中表单的数据信息,然后在客户端VBScript脚本中创建Word的Document对象,应用对象的相应方法将页面内容装入到Word文档中,并直接进行打印操作。代码如下:

<script language="vbscript">

Sub word_print

Set objWordDoc=CreateObject("Word.Document")

title=document.all.form1.txt_title.value&CHR(10)

nowtime=document.all.form1.txt_time.value&CHR(10)

table=title&nowtime&document.all.form1.txt_content.value

objWordDoc.Application.ActiveDocument.Paragraphs.Add.Range.InsertBefore(table)

objWordDoc.Application.ActiveDocument.Paragraphs.Add.Range.InsertBefore("")

Set rngPara=objworddoc.Application.ActiveDocument.Paragraphs(1).Range

objworddoc.Application.ActiveDocument.SaveAs "如何调用Word进行Web打印"

objWordDoc.application.printout()

End Sub

</script>

5.5.2  打印Access报表

在Microsoft Access数据库中,用户可以根据数据表创建Access报表,从而快速、准确地掌握数据信息。在ASP应用程序中,通过调用Access的相关对象可以打印指定的Access报表。

1.方案分析

Microsoft Access数据库不仅具有强大的数据存储功能,还拥有完善的报表功能,它支持子报、表、多栏报表、图形报表等多种复杂元素。在ASP中,调用Access的Application对象,可以开发直接打印Access报表的程序。

打印Access报表的流程图,如图5.40所示。

打印access报表6

图5.40  打印Access报表流程图

2.实施过程

01  实例位置光盘"mr"5"5.5"5.5.2

在ASP应用程序中直接打印Access报表,可以方便用户对数据库的一些相关操作。下面以新闻网站为例,介绍ASP调用Access的Application对象实现打印Access数据库中新闻报表的功能。运行效果如图5.41所示。

打印access报表7

图5.41  打印Access报表

在Microsoft Access数据库中,可以使用向导创建报表。下面介绍具体创建报表的步骤:

(1)打开Access数据库,单击左侧面板中的“报表”对象,在右侧选择“使用向导创建报表”的命令,打开“报表向导”窗口,在此窗口中选择表及字段名称,如图5.42所示。

图5.42  选择表及指定字段

(2)单击“下一步”按钮,可在打开的窗口中“确定是否添加分组类别”。再单击“下一步”按钮,在打开的窗口中可以确定记录所用的排序次序,如图5.43所示。

图5.43  确定记录所用的排序次序

(3)单击两次“下一步”按钮,分别确定报表的布局方式和所用样式。然后在下一个窗口中为报表指定标题,这里输入“打印新闻报表”,如图5.44所示。最后,单击“完成”按钮成功创建Access报表。

图5.44  定义报表标题

创建Access报表后,在ASP页面中建立表单。在表单中,用户通过选择所要操作的数据库文件以及输入Access数据库中报表的名称,来触发打印Access报表的程序。下面给出表单中关键元素的代码:

例程5-30  代码位置:光盘"mr"5"5.5"5.5.2"index.asp

<form action="" method="post" name="form1" onSubmit="PrintReport()">

Access数据库路径:<input name="txt_db" type="file" id="txt_db">

Access数据库中报表名称:<input name="txt_report" type="text" id="txt_report" title="Access数据库中报表名称">

<input type="submit" name="Submit" value="打印Access报表"  onClick="return Mycheck(this.form)">

<input type="reset" name="Submit2" value="重置表单内容"></td>

</form>

在ASP页面中,自定义一个客户端VBScript脚本的sub过程。在该过程中,首先创建Access的Application对象实例,然后调用对象的OpenCurrentDatabase方法连接所指定的Access数据库,再调用OpenReport方法打印指定名称的Access报表,最后给出打印成功的提示信息。代码如下:

例程5-31  代码位置:光盘"mr"5"5.5"5.5.2"index.asp

<script language="vbscript">

sub PrintReport()

Set pr = CreateObject("Access.Application")

pr.OpenCurrentDatabase document.all.txt_db.value

pr.DoCmd.OpenReport document.all.txt_report.value

pr.CloseCurrentDatabase

Set pr = Nothing

Msgbox "恭喜您,打印Access报表成功!"

end sub

</script>

3.补充说明

编写ASP应用程序所采用的VBScript语言是一种简单的脚本语言,只能实现有限的功能。而使用一些开发工具编写的组件,可以调用各种系统资源,实现较为复杂的功能。微软公司的ASP具有良好的可扩展性,而扩展ASP最有效的途径就是开发自定义的DLL组件,使用DLL组件的优势如下:

(1)实现代码封装技术。在开发程序时,ASP代码是嵌入在HTML语言中的,如果页面设计有变动,设计人员很难对嵌有代码的页面做改动,如果将代码封装在组件中,既方便设计人员进行页面布局,又增强程序的可读性。

(2)起到保护页面源码的作用。ASP程序是无须编译的,即它是以源码的形式存储在服务器上的,源程序很容易被他人获取。而组件是经过编译的,服务器端只有一个编译的DLL文件,保证源代码不被泄漏。

(3)编译好的组件可以重复使用,节约开发时间。

(4)用户将程序开发代码封装在组件中,可以申请知识产权保护其利益。

读者可以尝试使用Visual Basic软件来自定义ActiveX组件,然后调用该组件来实现特定的功能模块。

5.5.3  图形报表打印

图形报表是一种非常直观的数据表现形式,它是通过柱状图、饼型图、折线图等多种图表格式来统计数据的报表形式。在ASP中,可以利用图形报表来统计和处理数据,并进行打印操作等。

1.方案分析

在实际工作中,为了使用户能够以直观的方式查看到数据报表的内在结构,并能够明确报表所表达的含义,可以使用图形报表作为报表的表现形式。在ASP应用程序中,可以调用Visual Basic软件中内置的MSChart组件(MSChart组件是Microsoft提供的ActiveX组件之一,可以使用图形方式显示数据的图表),将数据库中的数据信息以图形的方式展现在页面中,从而实现图形报表打印的功能。

图形报表打印的流程图,如图5.45所示。

图

图5.45  图形报表打印流程图

2.实施过程

01  实例位置光盘"mr"5"5.5"5.5.3

在ASP中可以引用外部组件,使用柱状图、折线图等形式将统计数据展现在网页中。下面以网站的销售管理模块为例,介绍在选择查询条件并对商品销售情况进行统计核实时,利用图形报表显示查询结果的过程。运行效果如图5.46所示。

线形标注 2: 打印图形报表图

图5.46  图形报表打印

在商品销售统计页面中,提供了按月、按年或者按照具体日期进行销售统计的功能。在默认情况下,是针对所有商品进行销售统计的,用户也可以输入具体的商品编号只针对一种商品进行销售统计。

在程序处理页面中,首先根据选择的统计类型,确定对应的SQL查询语句;然后使用<object>标记嵌入MSChart组件;再通过JavaScript脚本语言设定MSChart组件的各属性值,使查询到的结果以图形方式显示在页面中。代码如下:

例程5-32  代码位置:光盘"mr"5"5.5"5.5.3"index.asp

<%

If Not Isempty(Request("btt_sell")) Then

  txt_Gnum=Request.Form("txt_Gnum")

  txt_type=Request.Form("txt_type")

  txt_amount=Request.Form("txt_amount")

  txt_start=Request.Form("txt_start")

  txt_end=Request.Form("txt_end")

如果用户在商品编号文本框中输入内容,则判断此商品编号是否存在。

  If txt_Gnum<>"" Then

    Set rs=Server.CreateObject("ADODB.Recordset")

    sqlstr="select Gnum from tb_sell where Gnum='"&txt_Gnum&"'"

    rs.open sqlstr,conn,1,1

    If rs.eof or rs.bof Then

      Response.Write("<script language='javascript'>alert('此商品没有销售信息,请重新输入!');history.back();</script>")     

    End If

   rs.close

   Set rs=Nothing

  End If

根据用户选择的统计类型,确定SQL查询语句。获取到的变量txt_type的值如果值为1,则按照商品的销售月份进行分组查询,并统计指定月份的销售金额;如果值为2,则按照商品的销售年份进行分组查询,并统计指定年份的销售金额。

  Select case txt_type

  case "1"

    fig="个月"

    If txt_Gnum<>"" Then

      sqlstr="select * from (select top "&txt_amount&" sum(Smoney) as totals,Month(Sdate) as IssueDate from tb_sell where Gnum='"&txt_Gnum&"' group by Month(Sdate) order by Month(Sdate) desc) as a order by a.IssueDate"

    Else

      sqlstr="select * from (select top "&txt_amount&" sum(Smoney) as totals,Month(Sdate) as IssueDate from tb_sell group by Month(Sdate) order by Month(Sdate) desc) as a order by a.IssueDate"

    End If

  case "2"

    fig="年"

    If txt_Gnum<>"" Then

      sqlstr="select * from (select top "&txt_amount&" sum(Smoney) as totals,Year(Sdate) as IssueDate from tb_sell where Gnum='"&txt_Gnum&"' group by Year(Sdate) order by Year(Sdate) desc) as a order by a.IssueDate"

    Else

      sqlstr="select * from (select top "&txt_amount&" sum(Smoney) as totals,Year(Sdate) as IssueDate from tb_sell group by Year(Sdate) order by Year(Sdate) desc) as a order by a.IssueDate"

    End If

  End Select

通过日期区间统计商品销售情况。

  If txt_start<>"" and txt_end<>"" Then

    If txt_Gnum<>"" Then

     sqlstr="select * from (select sum(Smoney) as totals,Sdate as IssueDate from tb_sell where Gnum='"&txt_Gnum&"' and Sdate between #"&txt_start&"# and #"&txt_end&"# group by Sdate order by Sdate desc) as a order by a.IssueDate"

   Else

      sqlstr="select * from (select sum(Smoney) as totals,Sdate as IssueDate from tb_sell where Sdate between #"&txt_start&"# and #"&txt_end&"# group by Sdate order by Sdate desc) as a order by a.IssueDate"

   End If

  End If

  Set rs=Server.CreateObject("ADODB.Recordset")

  rs.open sqlstr,conn,1,1

  counts=rs.recordcount

%>

使用<object>标记引用MSChart组件,并在JavaScript脚本中定义组件的各属性值,从而将查询到的结果以图表的形式显示在页面表格中。

<table width="600" border="1" align="center" cellpadding="0" cellspacing="0"   bordercolor="#FFFFFF" bordercolorlight="#9CA6C6" bordercolordark="#CCE3FF">

  <tr bgcolor="#FF9933">

    <td height="10" colspan="6" class="word_white">&nbsp; </td>

  </tr>

  <tr align="center" bgcolor="#C8E3FF">

    <td height="14">

<%

if counts>0 then

sum=0

%>

<object classid="clsid:3A2B370C-BA0A-11D1-B137-0000F8753F5D" name="chart" width="100%" height="300">

   <%'定义对象,该对象命名为chart%>

</object>

<% for i=1 to counts

  If txt_amount="" Then txt_amount=1

  If fig="" Then fig="企业"

%>

<script language="javascript">

chart.chartType=1;

chart.ColumnCount=1;   

chart.TitleText="最近 "+<%=txt_amount%>+"<%=fig%>"+" 商品销售情况显示图表 : ";  

chart.rowcount=<%=counts%>;           

chart.row=<%=i%>;                      

chart.rowlabel="<%=rs("IssueDate")%>(月/年/日期)";

chart.Data=<%=rs("totals")%>;         

chart.Footnote="注:纵坐标为销售金额";

</script>

<%sum=sum+rs("totals")

  rs.movenext     

  next           

%>

&nbsp;</td>

  </tr>

  <tr>

    <td height="30" colspan="6">&nbsp; 最近<%Response.Write(txt_amount&fig)%>的销售金额为 <%=sum%>元 </td>

  </tr>

</table>

<br>

引用WebBrowser组件,打印页面中的图形报表。

<object id=WebBrowser classid=ClSID:8856F961-340A-11D0-A96B-00C04Fd705A2 width="0" height="0"></object>

<div align="center"><a href="#" onClick="document.all.WebBrowser.Execwb(8,1)" class="Noprint">页面属性</a> <a href="#" onClick="document.all.WebBrowser.Execwb(7,1)" class="Noprint">打印预览</a> <a href="#" onClick="document.all.WebBrowser.Execwb(6,1)" class="Noprint">打印</a></div>

<%End IF

End IF

%>

3.补充说明

在网络应用程序中,经常会遇到由浏览者自己输入日期的情况,如注册页面中的生日、商品销售中售货日期等,如果输入的日期格式不正确,数据则不能正确保存。为了方便用户操作及保证输入日期格式的正确性,可以在需要输入日期的位置加入Visual Basic的日期拾取组件(Microsoft Date and Time Picker),由用户自己选择日期。如图5.47所示。

图

图5.47  调用Microsoft Date and Time Picker组件

DateTimePicker组件是Microsoft提供的ActiveX组件之一,可以返回格式化的日期字段,使得选择日期很容易。在使用DateTimePicker组件之前,应注册MSCOMCT2.OCX文件并安装Visual Basic软件。调用日历组件及获取选择的日期的关键代码如下:

<form name="myform" method="post" action="">

  <tr bgcolor="#FFFFFF">

    <td width="107" height="22" align="right">您选择的日期为:</td>

    <td width="286" height="22"><input name="Date_time" type="text" id="Date_time" onMouseOver="myevent()" onFocus="myevent()"></td>

  </tr> 

</form>

  <tr bgcolor="#FFFFFF">

    <td height="22" align="right">选择日期:</td>

    <td height="22">

<script language="javascript">

function myevent(){

var date=new Date(mydate.value) ;

year=date.getUTCFullYear();

month=date.getUTCMonth()+1;

day=date.getUTCDate();

myform.Date_time.value=year+"-"+month+"-"+day;

//myform.submit();

}

</script>

<object classid="clsid:20DD1B9E-87C4-11D1-8BE3-0000F8754DA1" name="mydate" width="110" height="20">

  <param name="format" value=1>

</object></td>

  </tr>

5.5.4  套打报表

套打是现在应用较为广范的一种打印方式,它是一种在印制有凭证、账簿、报表格式、证书等纸张上进行打印的打印方式,以这种方式进行打印时,无须打印表格的表格线及其他固定的格式内容,有利于加快打印速度、节约打印耗材、延长打印机的使用寿命等。

1.方案分析

在一些工作领域中(例如通信、邮政、商务洽谈、财务等),为了加快工作效率,并为用户提供方便,工作人员通常会将一些常用的业务事项或流程、凭证等事先打印出来,再由用户按照上面的提示进行填写、核实等。

使用ASP开发动态网站时,可以在页面中设计出所需要的格式,然后从数据库中读取所需要的数据,并将数据放置在页面指定的位置,从而实现套打报表的功能。套打报表的流程图,如图5.48所示。

图

图5.48  套打报表流程图

2.实施过程

01  实例位置光盘"mr"5"5.5"5.5.4

在生活和工作过程中,当人们邮寄一些快件时,首先要在快递单上填写邮件的基本信息。在开发动态网站时,为了满足用户需求,可以提供实时打印快递单的功能。下面以电子商务网站的订单信息管理模块为例,介绍套打快递单的实现过程。运行效果如图5.49所示。

线形标注 2: 套打快递单图

图5.49  套打快递单

在套打快递单页面中,用户可以通过填写寄件人或收件人的姓名来查询快递单的详细信息。程序处理页面根据获取到的表单数据,确定查询的SQL语句,然后将从数据库中读取到的数据添加到页面中指定位置,并应用打印技术执行套打操作。代码如下:

例程5-33  代码位置:光盘"mr"5"5.5"5.5.4"index.asp

<%

Dim SendTime,SendAddress,ReceiveAddress,SendTel,Sender,ReceiveTel,Receiver,ThingsName,PayMoney,ThingsNumber,ThingsWeight,ThingsPrice

sql_type=Trim(Request.Form("type"))

txt_name=Trim(Request.Form("txt_name"))

Set rs=Server.CreateObject("ADODB.Recordset")

sqlstr="select * from tb_info where 1=1"

根据用户填写的查询条件,确定SQL查询语句。

If txt_name<>"" then

   select case sql_type

   case "0"

   sqlstr=sqlstr&" and sender='"&txt_name&"'"

   case "1"

   sqlstr=sqlstr&" and receiver='"&txt_name&"'"

   end select

End If

rs.open sqlstr,conn,1,1

If rs.eof or rs.bof Then

    Response.Write("<p align=center>暂时不能提供任何信息!</p>")

   Response.End

End if

对查询到信息的进行分页处理。

rs.pagesize=1  '定义每页显示的记录数

pages=clng(Request("pages"))  '获得当前页数

If pages<1 Then pages=1

If pages>rs.recordcount Then pages=rs.recordcount

showpage rs,pages  '执行分页子程序showpage     

Sub showpage(rs,pages)  '分页子程序showpage(rs,pages)

rs.absolutepage=pages   '指定指针所在的当前位置

For i=1 to rs.pagesize  '循环显示记录集中的记录SendTime=Now()

SendAddress=rs("sendAddress")

ReceiveAddress=rs("ReceiveAddress")

SendTel=rs("SendTel")

Sender=rs("Sender")

ReceiveTel=rs("ReceiveTel")

Receiver=rs("Receiver")

ThingsName=rs("ThingsName")

PayMoney=rs("PayMoney")

ThingsNumber=rs("ThingsNumber")

ThingsWeight=rs("ThingsWeight")

ThingsPrice=rs("ThingsPrice")

SendTime=rs("sendTime")

%>

…略,表格信息

<%

  rs.movenext

  If rs.eof Then Exit For

  Next

  End Sub

%>

      <br>

      <table width="450" height="25"  border="0" align="center" cellpadding="-2" cellspacing="0" class="print">

        <tr valign="middle" bgcolor="#FFFFFF">

          <%If Not (rs.eof and rs.bof) Then%>

          <td width="280" height="28"><% if pages<>1 then %>

            <a href=?pages=1>第一页</a> <a href=?pages=<%=(pages-1)%>>上一页</a>

            <%end if

              if pages<>rs.pagecount then %>

            <a href=?pages=<%=(pages+1)%>>下一页</a> <a href=?pages=<%=rs.pagecount%>>最后一页</a>

            <%end if%></td>

          <%If not(rs.Eof and rs.Bof) Then%>

          <td width="220" height="28" align="right" class="word_grey">[<%=pages%>/<%=rs.PageCount%>]&nbsp;&nbsp;每页<%=rs.PageSize%>条&nbsp;&nbsp;共<%=rs.RecordCount%>条信息</td>

    <%End If

     rs.close

     Set rs=Nothing

    End If

   %>

        </tr>

        <tr bgcolor="#000000">

          <td colspan="2" valign="bottom" height="1"></td>

        </tr>

      </table>

      <br>

应用WebBrowser组件进行套打报表的操作。

<object id=WebBrowser classid=ClSID:8856F961-340A-11D0-A96B-00C04Fd705A2 width="0" height="0"> </object>

      <div align="center"><a href="#" onClick="document.all.WebBrowser.Execwb(8,1)" class="Noprint">页面设置</a> <a href="#" onClick="document.all.WebBrowser.Execwb(7,1)" class="Noprint">打印预览</a> <a href="#" onClick="document.all.WebBrowser.Execwb(6,1)" class="Noprint">打印</a></div>

3.补充说明

使用WebBrowser组件执行打印报表操作时,根据报表的实际结构,用户可以通过“页面设置”来定义打印选项,从而使打印能够顺利进行。例如,当纸张纵向打印不适合报表的宽度时,可以调整为“横向”打印;可以设置“页边距”,使报表在指定的纸张位置处进行打印;可以设置打印页面的页眉页脚等。

“页面设置”所包含的选项,如图5.50所示。

图5.50  页面设置窗口

 

在网络信息时代,人们对网络信息系统的依赖正逐渐增加,保证网络安全变得愈加重要。网络安全的本质就是需要保证网络上的信息安全,主要包括信息的保密性、完整性、可用性和准确性等。

网站属于计算机网络中的一部分,它用来向用户提供服务及相关信息。因此网络中的安全隐患都会映射到它的身上。如何更有效地保护重要的数据信息,提高网站的安全性已经成为Web程序开发中必须考虑和解决的一个重要问题。

本章将详细介绍在网络开发中的一些安全问题,及针对这些安全问题实施的各种策略和解决方案。读者通过本章的学习,可采用这些技术加强网站的安全,使网站的运行得到可靠的保障。

6.3  用户权限方案

为了提高网站的安全性,经常会为网站中的用户分配不同的权限,这样不仅可以有效的管理用户,而且可以在很大程度上提高网站的安全性。本节将对在开发和运营一个网站时,如何为不同级别的用户分配不同的权限做了具体、全面的分析。

6.3.1  默认用户权限

在一些企业管理系统中,经常会有多位管理人员对系统中的内部资源进行管理。为了提高系统的安全性,大多数情况下,系统中只有一位具有全局权限的管理员,并且该管理员具有添加普通管理员的权限,在添加这些普通管理员时,可以为新的管理员进行权限的分配。

1.方案分析

*  实例位置:光盘"mr"6"6.3"6.3.1

进入用户登录页面后,首先在登录表单中添加用户的登录信息,然后提交表单,这样该用户的所有登录信息将被提交的用户登录信息处理页。在用户信息处理页中,首先判断用户的用户名和密码是否正确,如果错误则返回登录页面,否则继续判断该用户所属级别,并根据用户级别为其分配不同的权限。例如,人力资源管理系统中的用户可以分为系统用户(或全局用户)、读写用户和只读用户,系统用户具有全局管理的权限,读写用户具有对常规数据进行修改、删除等权限,而只读用户只具有最基本的浏览权限。默认用户权限方案分析的示意图,如图6.16所示。

图6.16  默认用户权限的示意图

2.实施过程

*  实例位置:光盘"mr"6"6.3"6.3.1

运行网上企业办公自动化系统的用户信息修改页面,如图6.17所示,单击该页面中的用户“权限”下拉列表框,可以发现该系统中用户权限主要分为系统、读写和只读3种。当对用户权限进行修改时首先从用户权限下拉列表中为用户指定权限,然后单击“修改”按钮即可实现用户权限的修改。

图6.17  用户权限修改页面

在网上企业办公自动化系统管理页面中单击“人力资源”超链接,即可进入用户信息管理页面。在该页面中可以添加新用户信息、修改个人信息、修改其他用户信息、删除用户信息等操作。用户信息添加页面主要用于向数据库中添加新的用户信息。运行结果如图6.18所示。

图6.18  用户信息添加页面

制作添加用户信息的表单页面,该页面主要用于系统用户添加用户信息。在添加用户信息时,将应用JavaScript脚本验证输入信息是否合法。添加用户信息表单页面所涉及的重要表单元素如表6.1所示。

表6.1                  添加用户信息页面所涉及的重要表单元素

名称

元素类型

含义

重要属性

form1

form

表单

<form ACTION="personnel_add.asp" METHOD="POST" name="form1">

username

text

用户名

<input name="username" type="text" class="Sytle_text" id="username">

branch

select

部门

<select name="branch" id="select4"> <option value="开发部" selected>开发部</option> <option value="人事部">人事部</option> <option value="销售部">销售部</option> </select>

name

text

姓名

<input name="name" type="text" class="Sytle_text" id="name">

sex

select

性别

<select name="sex" id="sex"> <option value="男" selected>男</option><option value="女">女</option>

</select>

purview

select

权限

<select name="purview" id="select"> <option value="系统" selected>系统</option> <option value="读写">读写</option><option value="只读">只读</option>

</select>

Button

Button

“提交”按钮

<input name="Button" type="button" class="Style_button" value="提交" onClick="Mycheck()">

Submit2

reset

“重置”按钮

<input name="Submit2" type="reset" class="Style_button" value="重置">

myclose

button

“关闭”按钮

<input name="myclose" type="button" class="Style_button" id="myclose" value="关闭" onClick="javascrip:window.close()">

在实现用户信息添加时,首先判断客户端输入的用户信息是否合法,然后在将合法的用户信息保存到用户信息表中,通过以下代码实现用户信息的添加,代码如下:

例程6-15  代码位置:光盘"mr"6"6.3"6.3.2"personnel_add.asp

<!--#include file="../Connections/conn.asp" -->

<%

if request.Form("username")<>""then

'检测用户名是否存在

   Set rs= Server.CreateObject("ADODB.Recordset")

   sql="SELECT UserName FROM dbo.Tab_User WHERE UserName='" &Request.Form("UserName")&"'"

   rs.open sql,conn,1,3

   if rs.eof then

'保存员工信息

       username=request.Form("username")

       cname=request.Form("name")

       branch=request.Form("branch")

       PWD=request.Form("PWD")

       job=request.Form("job")

       tel=request.Form("tel")

       purview=request.Form("purview")

       sex=request.Form("sex")

       email=request.Form("email")

       address=request.Form("address")

       Ins="Insert into dbo.Tab_User (username,name,branch,PWD,job,tel,purview,sex,"&_

       "email,address) values('"&username&"','"&cname&"','"&branch&"','"&PWD&"','"&_

       job&"','"&tel&"','"&purview&"','"&sex&"','"&email&"','"&address&"')"

       conn.execute(Ins)

%>

       <script language="javascript">

       alert("员工信息添加成功!");

       opener.parent.location.reload();

       window.close();

       </script>

   <%

Else

%>

       <script language="javascript">

       alert("该员工信息已经存在!");

       </script>

   <%

   end if

end if

%>

<script language="javascript">

function Mycheck()

{

if (form1.username.value=="")

{ alert("请输入员工姓名!");form1.username.focus();return;}

if (form1.PWD.value=="")

{ alert("请输入密码!");form1.PWD.focus();return;}

if (form1.tel.value=="")

{

alert("请输入员工的联系电话!");

form1.tel.focus();return;

}

if(form1.email.value!="" && (form1.email.value.indexOf('@',0)==-1|| form1.email.value.indexOf('.',0)==-1))

{alert("您输入的E-mail地址不对!");form1.email.focus();return;}

if (form1.address.value=="")

{

alert("请输入员工的住址!");

form1.address.focus();return;

}

form1.submit();}

</script>

用户成功登录后,首先判断此用户是否是系统用户,如果该用户是系统用户,则可以通过“人力资源管理”模块,进行“添加新用户”、“修改个人信息”、“用户信息修改”和“用户信息删除”操作(可以对所有用户进行修改和删除操作);否则只可以对用户本身的密码进行修改。用户信息修改页面的运行结果如图6.19所示。

图6.19  用户信息修改页面

通过以下代码实现用户信息的修改,代码如下:

例程6-16  代码位置:光盘"mr"6"6.3"6.3.2"personnel_modify.asp

<!--#include file="../Connections/conn.asp" -->

<%

'查询员工信息

If Request.QueryString("ID")<>""then

session("ID")=Request.QueryString("ID")

end if

Set rs_personnel = Server.CreateObject("ADODB.Recordset")

sql_P="SELECT ID,UserName,name,PWD,purview,branch,job,sex,Email,Tel,Address"&_

" FROM dbo.Tab_User WHERE ID="&session("ID")&""

rs_personnel.open sql_p,conn,1,3

%>

<%

'修改员工信息

if request.Form("Name")<>"" then

   cname=request.Form("name")

   PWD=request.Form("PWD")

   purview=request.Form("purview")

   sex=request.Form("sex")

   tel=request.Form("tel")

   branch=request.Form("branch")

   job=request.Form("job")

   email=request.Form("email")

   address=request.Form("address")

   UP="Update dbo.Tab_User set name='"&cname&"',PWD='"&PWD&"',purview='"&_

   purview&"',sex='"&sex&"',tel='"&tel&"',branch='"&branch&"',job='"&job&_

   "',email='"&email&"',address='"&address&"' where ID='"&session("ID")&"'"

   conn.execute(UP)

%>

   <script language="javascript">

   alert("数据修改成功!");

   opener.parent.location.reload();

   window.close();

   </script>

<%

end if

%>

<script language="javascript">

function Mycheck()

{

if (form1.name.value=="")

{ alert("请输入员工姓名!");form1.name.focus();return;}

if (form1.PWD.value=="")

{ alert("请输入密码!");form1.PWD.focus();return;}

if (form1.tel.value=="")

{

alert("请输入员工的联系电话!");

form1.tel.focus();return;

}

if(form1.email.value!="" && (form1.email.value.indexOf('@',0)==-1|| form1.email.value.indexOf('.',0)==-1))

{

alert("您输入的E-mail地址不对!");

form1.email.focus();return;

}

if (form1.address.value=="")

{

alert("请输入员工的住址!");

form1.address.focus();return;

}

form1.submit();}

</script>

通过以下代码实现用户信息的删除,代码如下:

例程6-17  代码位置:光盘"mr"6"6.3"6.3.2"personnel_del.asp

<!--#include file="../Connections/conn.asp" -->

<%

if request.Form("UserName")<>"" then

   DEL="Delete From dbo.Tab_User where ID='"&session("ID")&"'"

   conn.execute(Del)

%>

   <script language="javascript">

   alert("员工信息已经删除!");

   opener.location.reload();

   window.close();

   </script>

<%end if%>

<%

if Request.QueryString("ID")<>""then

   session("ID")=Request.QueryString("ID")

end if

Set rs_personnel = Server.CreateObject("ADODB.Recordset")

sql_P="SELECT ID,UserName,Name,PWD,purview,branch,sex,Email,Tel,Address"&_

" FROM dbo.Tab_User WHERE ID="&session("ID")&""

rs_personnel.open sql_P,conn,1,3

%>

3.补充说明

为用户分配默认的权限,即可在添加用户信息时指定,也可以先注册用户信息,然后根据不同用户的职能为其分配不同的权限。为了提高网站的安全性,在为用户指定默认权限时,一定要根据用户的职能权限进行的合理分配,否则一旦非法用户登录系统将会给整个系统造成极大的损失。

6.3.2  简单自定义用户权限

简单自定义权限是指在添加新管理员时,根据该管理员的管理职责而为其分配的权限。例如,在为系统添加数据录入管理人员时,只需为其分配数据添加和数据删除的权限即可,为了提高整个系统的安全性,不必为其过多的分配其他权限。下面将以办公自化管理系统为例来讲解简单自定义用户权限的具体实现过程。

1.方案分析

一个网站管理系统的后台用户主要分为两种,一种是全局管理员,另一种是普通管理员。全局管理员具有整个后台的全局管理权限,除了具有对后台数据进行管理的所有权限外,还具有对普通管理员进行管理的权限;而普通管理员只具有对后台数据进行添加、修改和删除的权限以及对个人信息进行修改的权限。管理人员首先进入后台登录页面,然后在登录表单中输入个人的登录信息并提交表单,这样该管理员的登录信息将被提交到用户信息验证页,如果用户的个人信息填写错误则返回到登录页,否则对用户的级别进行判断,并根据用户的级别为其分配不同的权限。实现简单自定义用户权限的示意图,如图6.20所示。

图6.20  简单自定义用户权限的示意图

2.实施过程

*  实例位置:光盘"mr"6"6.3"6.3.2

下面将以办公自动化管理系统为例讲解如何实现简单自定义用户权限。当超级用户成功进入系统后,可以进行新用户的添加,如图6.21所示。首先在该页面的用户名和密码的文本框中输入合法的用户名和密码,然后从权限列表框中选择要为该用户分配的权限,最后单击“提交”按钮即可实现自定义权限的添加。

图6.21  添加超级用户信息页面

通过以下代码实现数据库的连接,代码如下:

例程6-18  代码位置:光盘"mr"6"6.3"6.3.2"data"conn.asp

<%

set conn=server.CreateObject("Adodb.Connection")

Path="driver={SQL Server};server=.;uid=sa;pwd=;database=db_safe"

conn.open path

function HTMLcode(fString)

if not isnull(fString) then

    fString = Replace(fString, CHR(13), "")

    fString = Replace(fString, CHR(10) & CHR(10), "</P><P>")

    fString = Replace(fString, CHR(10), "<BR>")

   fString = Replace(fString, CHR(32), "&nbsp;")

    HTMLcode = fString

end if

end function

%>

在用户管理模块中单击“用户添加”超链接,即可进入到用户添加页面。用户信息添加页面主要用于向数据库中添加新的用户信息。其运行结果如图6.22所示。

图6.22  用户信息添加页面的运行结果

制作添加用户信息的表单页面,该页面主要用于收集超级用户添加的用户信息和验证输入信息是否合法。添加用户信息表单页面所涉及的重要表单元素如表6.2所示。

表6.2                  添加用户信息页面所涉及的重要表单元素

名称

元素类型

含义

重要属性

form1

form

表单

action="" method="post" name="form1"

username

text

用户名

<input name="username" type="text" id="username" size="20">

post

hidden

隐藏域

<input name="post" type="hidden" id="post" value="1">

userpwd

password

密码

<input name="userpwd" type="password" id="userpwd" size="20">

menu1

select

文本域

<select name="menu1" size="3" onChange="MM_jumpMenu('nei',this,0)">

<% set rs2=server.CreateObject("adodb.recordset")

sql2="select * from renshi" rs2.open sql2,conn,1,1

if not rs2.eof then for i=1 to rs2.recordcount and not rs2.eof%> 

<option value=nei.asp?id=<%=rs2("id")%>>

<%=rs2("name")%></option>

<% rs2.movenext if rs2.eof then exit for

Next else response.Write("<option value='没有用户'>没有用户</option>")  end if          %></select>

Submit

Submit

“提交”按钮

<input type="submit" name="Submit" value="提交">

Submit2

reset

“重置”按钮

<input type="reset" name="Submit2" value="重置">

在实现用户信息添加时,首先判断客户端输入的用户信息是否合法,然后在将合法的用户信息保存到用户信息表中,通过以下代码实现用户信息的添加,代码如下:

例程6-19  代码位置:光盘"mr"6"6.3"6.3.2"adduser.asp

<!--#include file=data/conn.asp-->

<!--#include file=connfig.asp-->

<!--#include file=inc/yan.asp-->

<%

   '验证用户身份

   call case10

   if request("post")=1 then

     if request("username")="" or request("userpwd")="" then

   response.Write("<script language=JavaScript>" & "alert('用户名或者密码不能为空!');" & "history.back()" & "</script>")

   else

    if request("user")=0 then

         call wr1

       else

          call wr2

       end if

     end if

   end if

   '添加普通用户

   function wr1

   username=trim(replace(request("username"),"'",""))

   userpwd=trim(replace(request("userpwd"),"'",""))

   for i=1 to len(username)

     user=mid(username,i,1)

     if user="'" or user="%" or user="<" or user=">" or user="&" or user="|" then

       response.write "<script language=JavaScript>" & "alert('您的用户名含有非法字符,请重新输入!');" & "history.back()" & "</script>"

       response.end

     end if

   next

   for i=1 to len(userpwd)

     pass=mid(userpwd,i,1)

     if pass="'" or pass="%" or pass="<" or pass=">" or pass="&" or pass="|" then

        response.write "<script language=JavaScript>" & "alert('您的密码含有非法字符,请重新输入!');" & "history.back()" & "</script>"

        response.end

     end if

   next

        '判断用户名是否已经存在

        set rs1=server.CreateObject("adodb.recordset")

        sql1 = "Select * From users Where username='"&request("username")&"'"

        rs1.open sql1,conn,1,1

        If not rs1.EOF Then

        response.Write("<script language=JavaScript>" & "alert('用户名已经存在!');" & "window.location.href='adduser.asp';" & "</script>")

        response.End()

        end if

        rs1.close

   '添加用户权限

   set rs=server.CreateObject("adodb.recordset")

   sql="select * from users"

   rs.open sql,conn,1,3

   rs.addnew

   rs("username")=request("username")

   rs("userpwd")=request("userpwd")

   rs("shenhe")=request("shenhe")

   rs("huiyi")=request("huiyi")

   rs("gonggong")=request("gonggong")

   rs("geren")=request("geren")

   rs("renshi")=request("renshi")

   rs("name")=session("na")

   rs("time")=now()

   rs.update

   rs.close

   response.Write("<script language=JavaScript>" & "alert('添加成功!');" & "window.location.href='adduser.asp';" & "</script>")

   response.End()

   end function

    '添加超级用户

   function wr2

   username=trim(replace(request("username"),"'",""))

   userpwd=trim(replace(request("userpwd"),"'",""))

   for i=1 to len(username)

     user=mid(username,i,1)

     if user="'" or user="%" or user="<" or user=">" or user="&" or user="|" then

       response.write "<script language=JavaScript>" & "alert('您的用户名含有非法字符,请重新输入!');" & "history.back()" & "</script>"

       response.end

     end if

   next

   for i=1 to len(userpwd)

     pass=mid(userpwd,i,1)

     if pass="'" or pass="%" or pass="<" or pass=">" or pass="&" or pass="|" then

        response.write "<script language=JavaScript>" & "alert('您的密码含有非法字符,请重新输入!');" & "history.back()" & "</script>"

        response.end

     end if

   next

        set rs1=server.CreateObject("adodb.recordset")

        sql1 = "Select * From users Where username='"&request("username")&"'"

        rs1.open sql1,conn,1,1

        If not rs1.EOF Then

        response.Write("<script language=JavaScript>" & "alert('用户名已经存在!');" & "history.back()" & "</script>")

        end if

        rs1.close

   set rs=server.CreateObject("adodb.recordset")

   sql="select * from users"

   rs.open sql,conn,1,3

   rs.addnew

   rs("username")=request("username")

   rs("userpwd")=request("userpwd")

   rs("name")=session("na")

   rs("chaoji")=1

   rs("time")=now()

   rs.update

   rs.close

   response.Write("<script language=JavaScript>" & "alert('添加成功!');" & "history.back()" & "</script>")

   end function

%>

在进行用户登录时,首先判断此用户是否是超级用户,如果该用户是超级用户,则可以通过“用户管理”模块,进行“用户添加”、“用户修改”和“删除”操作(可以对所有用户进行修改和删除操作);否则只可以对用户本身的密码进行修改。用户信息修改页面的运行结果如图6.23所示。

图6.23  用户信息修改页面的运行结果

通过以下代码实现用户信息的修改,代码如下:

例程6-20  代码位置:光盘"mr"6"6.3"6.3.2"adduser1.asp

<!--#include file=data/conn.asp-->

<!--#include file=connfig.asp-->

<!--#include file=inc/yan.asp-->

<%

call case10

 set rs2=server.CreateObject("adodb.recordset")

    sql2="select * from users where id="&request("id")

    rs2.open sql2,conn,1,1

if request("post")=1 then

  if request("username")="" or request("userpwd")="" then

response.Write("<script language=JavaScript>" & "alert('用户名或者密码不能为空!');" & "history.back()" & "</script>")

else

 if request("user")=0 then

      call wr1

    else

       call wr2

    end if

  end if

end if

function wr1

if session("na")="" then

na=rs2("name")

else

na=session("na")

end if

username=trim(replace(request("username"),"'",""))

userpwd=trim(replace(request("userpwd"),"'",""))

for i=1 to len(username)

  user=mid(username,i,1)

  if user="'" or user="%" or user="<" or user=">" or user="&" or user="|" then

    response.write "<script language=JavaScript>" & "alert('您的用户名含有非法字符,请重新输入!');" & "history.back()" & "</script>"

    response.end

  end if

next

for i=1 to len(userpwd)

  pass=mid(userpwd,i,1)

  if pass="'" or pass="%" or pass="<" or pass=">" or pass="&" or pass="|" then

     response.write "<script language=JavaScript>" & "alert('您的密码含有非法字符,请重新输入!');" & "history.back()" & "</script>"

     response.end

  end if

next

set rs=server.CreateObject("adodb.recordset")

sql="select * from users where id="&session("id")

rs.open sql,conn,1,3

rs("username")=request("username")

rs("userpwd")=request("userpwd")

rs("shenhe")=request("shenhe")

rs("huiyi")=request("huiyi")

rs("gonggong")=request("gonggong")

rs("geren")=request("geren")

rs("renshi")=request("renshi")

rs("name")=na

rs("chaoji")=0

rs.update

rs.close

response.Write("<script language=JavaScript>" & "alert('修改成功!');" & "history.back()" & "</script>")

end function

 function wr2

 if session("na")="" then

na=rs2("name")

else

na=session("na")

end if

username=trim(replace(request("username"),"'",""))

userpwd=trim(replace(request("userpwd"),"'",""))

for i=1 to len(username)

  user=mid(username,i,1)

  if user="'" or user="%" or user="<" or user=">" or user="&" or user="|" then

    response.write "<script language=JavaScript>" & "alert('您的用户名含有非法字符,请重新输入!');" & "history.back()" & "</script>"

    response.end

  end if

next

for i=1 to len(userpwd)

  pass=mid(userpwd,i,1)

  if pass="'" or pass="%" or pass="<" or pass=">" or pass="&" or pass="|" then

     response.write "<script language=JavaScript>" & "alert('您的密码含有非法字符,请重新输入!');" & "history.back()" & "</script>"

     response.end

  end if

next

set rs=server.CreateObject("adodb.recordset")

sql="select * from users where id="&session("id")

rs.open sql,conn,1,3

rs("username")=request("username")

rs("userpwd")=request("userpwd")

rs("name")=na

rs("chaoji")=1

rs.update

rs.close

response.Write("<script language=JavaScript>" & "alert('修改成功!');" & "history.back()" & "</script>")

end function

%>

通过以下代码实现用户信息的删除,代码如下:

例程6-21  代码位置:光盘"mr"6"6.3"6.3.2"del.asp

<!--#include file=data/conn.asp-->

<!--#include file=connfig.asp-->

<!--#include file=inc/yan.asp-->

<%

   '验证用户权限

   call case10

   if request("del")<>"" and ps("chaoji")=1 then

   call del

   end if

   '删除用户

   function del

   sql2="delete from users where id="&request("del")

   conn.Execute(sql2)

   end function

%>

当登录的用户是普通用户时,只可以对用户本身的密码进行修改。通过以下代码实现普通用户密码的修改操作,代码如下:

例程6-22  代码位置:光盘"mr"6"6.3"6.3.2"yonghugai.asp

<!--#include file=data/conn.asp-->

<!--#include file=connfig.asp-->

<%

if request("post")<>"" then

call write1

end if

function write1

if request("userpwd1")<>"" and request("userpwd2")<>"" then

if request("userpwd1")<>request("userpwd2") then

response.Write("<script language=javascript>alert('两次输入密码不一致!!')</script>")

else

set rs=server.CreateObject("adodb.recordset")

sql="select * from users where username='"&session("admin_name")&"'"

rs.open sql,conn,1,3

rs("userpwd")=request("userpwd1")

rs.update

end if

else

response.Write("<script language=javascript>alert('密码不能为空!')</script>")

end if

if request("qq")<>"" then

set rs1=server.CreateObject("adodb.recordset")

sql1="select * from renshi where name='"&rs("name")&"'"

rs1.open sql1,conn,1,3

rs1("tel")=request("tel")

rs1("age")=request("age")

rs1("email")=request("email")

rs1("address")=request("address")

rs1.update

rs1.close

end if

response.Redirect("chenggong.htm")

end function

set rs3=server.CreateObject("adodb.recordset")

sql3="select * from users where username='"&session("admin_name")&"'"

rs3.open sql3,conn,1,3

set rs4=server.CreateObject("adodb.recordset")

sql4="select * from renshi where name='"&rs3("name")&"'"

rs4.open sql4,conn,1,3

%>

3.补充说明

在实现简单自定义用户权限时,也可以将普通用户权限和超级用户权限的选项放在下拉列表中,并在Dreamweaver中插入两个下拉列表框,同时将下拉列表的类型设置为“列表”类型,选择“允许多选”前面的复选框,设置完成后将相关的权限信息输入到下拉列表框中,此时可以按shift键进行用户权限的多选操作,即实现与复选框同样的功能。通过该方法同样可以实现简单自定义用户权限的设置,运行结果如图6.24所示。

图6.24  应用下拉列表实现简单自定义用户权限的设置

6.3.3  复杂自定义用户权限

在某些较大规模的管理系统中,为了有效合理的对系统信息进行管理,无论是全局管理员还是普通管理者的权限都是极其复杂的。那么如何在复杂的管理系统中定义及分配用户的权限呢?下面将以企业进销存管理系统为例来讲解复杂自定义用户权限的设计方案及具体实现过程。

1.方案分析

实现“复杂自定义用户权限”与实现“简单自定义用户权限”的实现方案大体类似,区别是在为用户指定权限时需要考虑更多的因素。管理人员首先进入后台登录页面,然后在登录表单中输入个人的登录信息并提交表单,这样该管理员的登录信息将被提交到用户信息验证页,如果用户的个人信息填写错误则返回到登录页,否则可以对用户的级别进行判断,并根据用户的级别为其分配不同的权限。实现复杂自定义用户权限的示意图,如图6.25所示

图6.25  复杂自定义用户权限的示意图

2.实施过程

*  实例位置:光盘"mr"6"6.3"6.3.3

全局管理员成功登录企业进销存管理系统的后台时,就可以进入该系统的“权限管理”模块,如图6.26所示。在“权限管理”模块中列出了所有管理员的用户名和该管理员的权限信息,如果预删除某管理员,可以直接单击该管理员所对应的“删除”超链接即可。如果对某用户的权限进行设置或重新分配时,可以单击该管理员后的“权限设置”超链接进入权限设置页面可以对该管理员的权限进行重新设定。

图6.26  复杂自定义用户权限管理页面

本系统后台数据库采用的是Access数据库,系统数据库名称为db_database.mdb。数据库db_database.mdb中包含两张数据表:分别为tb_use(管理员信息表)和tb_purview(权限信息表)。下面将分别给出这两个数据表的表结构。

(1)tb_use(管理员信息表)主要用于保存管理员的名称及密码信息,其表结构如表6.3所示。

表6.3                           表tb_use的结构

字段名称

数据类型

长度

默认值

描述

id

自动编号

管理员ID号

use

文本

50

管理员名称

pwd

文本

50

管理员密码

(2)tb_purview(权限信息表)主要用于保存管理员的权限信息,其表结构如表6.4所示。

表6.4                             tb_purview表

字段名称

数据类型

长度

默认值

描述

id

数字

长整型

0

管理员ID号

purviewSet

是/否

权限设置

basicSet

是/否

基本信息管理

stockSet

是/否

进货管理

sellSet

是/否

销售管理

storageSet

是/否

库存管理

querySet

是/否

查询统计

reportSet

是/否

报表管理

通过以下代码实现数据库的连接,代码如下:

例程6-23  代码位置:光盘"mr"6"6.3"6.3.3"Conn"conn.asp

<%

Set conn=Server.CreateObject("ADODB.Connection")

sql="Provider=Microsoft.jet.oledb.4.0;data source="&Server.MapPath("database/db_database.mdb")

conn.open(sql)

%>

在权限管理的主页中单击“添加管理员信息”超链接,即可进入到添加管理员信息页面。添加管理员信息页面主要用于向数据库中添加新的管理员。运行结果如图6.27所示。

图6.27  添加管理员信息页面的运行结果

制作添加管理员信息的表单页面,该页面主要用于收集管理员添加的管理员信息和验证输入信息是否合法。添加管理员信息表单页面所涉及的重要表单元素如表6.5所示。

表6.5                  添加管理员信息页面所涉及的重要表单元素

名称

元素类型

含义

重要属性

form1

form

表单

action="tjyg.asp" method="post" name="form1"

use

text

管理员名称

<input name="use" type="text" id="use" size="19">

pwd

password

管理员密码

<input name="pwd" type="password" id="pwd" size="20">

pwd1

password

确认密码

<input name="pwd1" type="password" id="pwd1" size="20">

Img1

Img

“保存”按钮

<img src="images/button2.gif" width="58" height="24" onClick="Mycheck1();">

Img2

img

“关闭”按钮

<img src="images/button3.gif" width="58" height="24" onClick="window.close();opener.location.reload();">

在实现管理员信息添加时,首先判断客户端输入的管理员信息是否合法,然后在将合法的管理员信息保存到管理员信息表中,并同时级联插入权限信息,级联插入权限信息主要通过获取Access数据库中插入记录的自动编号实现的。代码如下:

例程6-24  代码位置:光盘"mr"6"6.3"6.3.3"tjyg.asp

<!--#include file="conn/conn.asp"-->

<%

function filter_Str(InString)

'***********************************

'功能:过滤输入字符串中的危险符号

'调用方法:filter_Str("String")

'***********************************

   NewStr=Replace(InString,"'","''")

   NewStr=Replace(NewStr,"<","&lt;")

   NewStr=Replace(NewStr,">","&gt;")

   NewStr=Replace(NewStr,"chr(60)","&lt;")

   NewStr=Replace(NewStr,"chr(37)","&gt;")

   NewStr=Replace(NewStr,"""","&quot;")

   NewStr=Replace(NewStr,";",";;")

   NewStr=Replace(NewStr,"--","-")

   NewStr=Replace(NewStr,"/*"," ")

   NewStr=Replace(NewStr,"%"," ")

   filter_Str=NewStr

end function

if request.Form("use")<>"" then

   use=filter_Str(request.Form("use"))

   pwd=filter_Str(request.Form("pwd"))

   '检测输入的管理员是否已存在

   set rs=server.CreateObject("Adodb.recordset")

   sql="select * from tb_use where use='"&use&"'"

   rs.open sql,conn,1,3

   if rs.eof and rs.bof then

   '通过下面的程序代码来保存用户注册信息

   rs.addnew()

   rs("use")=use

   rs("pwd")=pwd

   rs.update

   '获取Access数据库中插入记录的自动编号

   temp=rs.bookmark

   rs.bookmark=temp

   id=rs("id")

   ins1="insert into tb_purview(id,purviewSet,basicSet,stockSet,sellSet,storageSet,querySet,reportSet)values("&id&","&false&","&false&","&false&","&false&","&false&","&false&","&false&")"

   conn.execute(ins1)

%>

   <script language="javascript">

   alert("管理员信息添加成功,继续添加!");

   window.location='tjyg.asp';

   </script>

   <%

Else

%>

   <script language="javascript">

   alert("该管理员信息已存在!");

   window.location='tjyg.asp';

   </script>

<%

end if

end if

%>

显示管理员列表页面即权限管理的主页面,在该页面中将显示所有管理员信息,其中管理员的权限是以复选框的形式进行显示,页面运行结果如图6.26所示,代码如下:

例程6-25  代码位置:光盘"mr"6"6.3"6.3.3"main.asp

<%

Set rs=Server.CreateObject("Adodb.RecordSet")

sql="select * from tb_use u inner join tb_purview p on u.id=p.id order by u.id asc"

rs.open sql,conn,1,3

if rs.bof and rs.eof then

response.Write("暂无管理员信息!")

else

%>

<table width="696" height="67" border="1" align="center" cellpadding="0" cellspacing="0" bordercolor="#6598CD">

<tr>

<td height="25" bgcolor="#99CDFF">

<div align="center" class="STYLE6">管理员名称</div>

</td>

<td bgcolor="#99CDFF"><div align="center" class="STYLE6">权限管理</div></td>

<td bgcolor="#99CDFF"><div align="center" class="STYLE6">基础信息管理</div></td>

<td bgcolor="#99CDFF"><div align="center" class="STYLE6">进货管理</div></td>

<td bgcolor="#99CDFF"><div align="center" class="STYLE6">销售管理</div></td>

<td bgcolor="#99CDFF"><div align="center" class="STYLE6">库存管理</div></td>

<td bgcolor="#99CDFF"><div align="center" class="STYLE6">查询统计</div></td>

<td bgcolor="#99CDFF"><div align="center" class="STYLE6">报表管理</div></td>

<td bgcolor="#99CDFF"><div align="center" class="STYLE6">权限设置</div></td>

<td bgcolor="#99CDFF"><div align="center" class="STYLE6">操作</div></td>

</tr>

<%

for i=1 to rs.recordcount

%>

<tr>

<td height="20" bgcolor="#FFFFFF">

<div align="center" class="STYLE6"><%=rs("use")%></div>

</td>

<td bgcolor="#FFFFFF">

<div align="center" class="STYLE6">

<input name="checkbox" type="checkbox" class="noborder" value="checkbox" disabled="disabled"

<%if rs("purviewSet") then response.write("checked") end if%>>

</div>

</td>

<td bgcolor="#FFFFFF">

<div align="center" class="STYLE6">

<input name="checkbox" type="checkbox" class="noborder" value="checkbox" disabled="disabled" <%if rs("basicSet") then response.write("checked") end if%>>

</div>

</td>

<td bgcolor="#FFFFFF">

<div align="center" class="STYLE6">

<input name="checkbox" type="checkbox" class="noborder" value="checkbox" disabled="disabled" <%if rs("stockSet") then response.write("checked") end if%>>

</div>

</td>

<td bgcolor="#FFFFFF">

<div align="center" class="STYLE6">

<input name="checkbox" type="checkbox" class="noborder" value="checkbox" disabled="disabled" <%if rs("sellSet") then response.write("checked") end if%>>

</div>

</td>

<td bgcolor="#FFFFFF">

<div align="center" class="STYLE6">

<input name="checkbox" type="checkbox" class="noborder" value="checkbox" disabled="disabled" <%if rs("storageSet") then response.write("checked") end if%>>

</div>

</td>

<td bgcolor="#FFFFFF">

<div align="center" class="STYLE6">

<input name="checkbox" type="checkbox" class="noborder" value="checkbox" disabled="disabled" <%if rs("querySet") then response.write("checked") end if%>>

</div>

</td>

<td bgcolor="#FFFFFF">

<div align="center" class="STYLE6">

<input name="checkbox" type="checkbox" class="noborder" value="checkbox" disabled="disabled" <%if rs("reportSet") then response.write("checked") end if%>>

</div>

</td>

<td bgcolor="#FFFFFF"><div align="center"><span class="STYLE6">

<%

if rs1("purviewSet")=true and rs("use")<>"mr" then

%>

<a href="#" onClick="window.open('qx.asp?id=<%=rs("u.id")%>','','width=292,height=175')"><span class="STYLE9">权限设置</span></a>

<%else%>

<span class="STYLE9"> &nbsp;</span>

<%end if%>

</td>

<td bgcolor="#FFFFFF">

<div align="center">

<%if rs1("purviewSet")=true and rs("use")<>"mr" then%> 

<a href="del.asp?id=<%=rs("u.id")%>"><span class="STYLE9">删除</span></a>

<%

Else

%>

<span class="STYLE9">&nbsp;</span>

<%

end if

%>

</div>

</td>

</tr>

<%

rs.movenext

if rs.eof then exit for

next

%>

</table>

<%

end if

%>

管理员在进行登录时,首先判断此管理员是否拥有权限管理的功能,如果有权限管理功能,则可以通过单击某条管理员信息右侧的“权限设置”超链接即可进入到管理员权限修改页面,在该页面中将显示该管理员的权限信息,设置相应的信息后,单击“保存”按钮即可将管理员的权限信息保存到数据表中;否则将不显示“权限设置”超链接。管理员权限修改页面的运行结果如图6.28所示。

图6.28  管理员权限修改页面的运行结果

通过以下代码实现管理员权限的修改,代码如下:

例程6-26  代码位置:光盘"mr"6"6.3"6.3.3"ok.asp

<!--#include file="conn/conn.asp"-->

<%

if request.Form("Button")="保存" then

   purviewSet=request.Form("purviewSet")

   if purviewSet="" then purviewSet=false

   basicSet=request.Form("basicSet")

   if basicSet="" then basicSet=false

   stockSet=request.Form("stockSet")

   if stockSet="" then stockSet=false

   sellSet=request.Form("sellSet")

   if sellSet="" then sellSet=false

   storageSet=request.Form("storageSet")

   if storageSet="" then storageSet=false

   querySet=request.Form("querySet")

   if querySet="" then querySet=false

   reportSet=request.Form("reportSet") 

   if reportSet="" then reportSet=false

   UP="Update tb_purview set purviewSet="&purviewSet&",basicSet="&basicSet&",stockSet="&stockSet&",sellSet="&sellSet&",storageSet="&storageSet&",querySet="&querySet&",reportSet="&reportSet&" where ID="&session("ID")&""

   conn.execute(UP)

end if

%>

通过以下代码实现管理员信息的删除,代码如下:

例程6-27  代码位置:光盘"mr"6"6.3"6.3.3"del.asp

<!--#include file="conn/conn.asp"-->

<%

if request.QueryString("id")<>"" then

   Del="Delete from tb_use where ID="&request.QueryString("id")&""

   conn.execute(Del)

%>

<script language="javascript">

window.location.href='main.asp';

</script>

<%

end if

%>

3.补充说明

在本方案中实现管理员信息添加时,首先需要将管理员信息添加到管理员信息数据表中,然后需要在权限信息表中也同时级联插入该管理员的权限信息,实现级联插入管理员权限信息主要通过获取Access数据库中插入记录的自动编号实现的。下面对该技术进行详细介绍。

本方案主要通过Bookmark属性使用户对Recordset中的记录进行标记,稍后再返回给它。使用Bookmark属性可以保存当前记录的位置并随时返回该记录。Bookmark属性只能在支持书签功能的Recordset对象中使用。

打开Recordset对象时,其每个记录都有唯一的书签。要保存当前记录的书签,请将Bookmark 属性的值赋给一个变量。移动到其他记录后要快速返回到该记录时,请将该Recordset对象的 Bookmark属性设置为该变量的值。

如果使用Clone方法创建Recordset对象的一个副本,则原始的和复制的Recordset对象Bookmark属性设置相同并可以替换使用。但是无法替换使用不同Recordset对象的书签,即使这些书签是通过同一数据源或命令创建的。

在客户端上使用Recordset对象时,Bookmark属性始终有效。例如以下代码:

temp=rs.bookmark

rs.bookmark=temp

为了使读者能够更好地理解和运用该技术,下面将给出一个具体的应用方案。在开发留言板程序时,应设置回复功能。本方案主要通过Recordset对象中的Bookmark属性使用户对Recordset 中的记录进行标记,稍后再返回给它。当对留言信息进行回复时,回复的信息将直接与留言信息依依相对应,就无须在指定回复留言的ID号。运行结果如图6.29所示。

图6.29  向Access数据库中插入记录

通过以下代码实现数据库的连接,代码如下:

<%

set conn=server.CreateObject("adodb.connection")

sql="Driver={Microsoft Access Driver (*.mdb)};DBQ=" &server.MapPath("Database/db_database.mdb")

conn.open(sql)

%>

添加表单、文本框和文本域,并设置其相关的属性值,代码如下:

<form method="post" name="form1">

<input name="title" type="text" class="text" id="title" size="32">

<textarea name="content" cols="30" rows="8" class="text" id="content">

</textarea>

<input name="Submit" type="submit" class="button" value="提交">

<input name="Submit2" type="reset" class="button" value="重置">

</form>

通过以下代码实现立即获取插入记录的自动编号,代码如下:

<%

if request.form("title")<>"" then

title=request.form("title")

content=request.form("content")

Set rs=Server.CreateObject("ADODB.Recordset")

sql="select * from tb_sml"

rs.open sql,conn,1,3

rs.addnew()

rs("title")=title

rs("content")=content

rs.update()

temp=rs.bookmark

rs.bookmark=temp

topicID=rs("ID")

ins="insert into tb_back (title_ID) values ("&topicID&")"

conn.execute(ins)

end if

%>

6.5  ASP文件安全技术方案

使用浏览器的“查看源文件”功能只可以查看IIS服务器编译后的HTML标签和JavaScript等客户端脚本,但使用迅雷等下载工具就可以将ASP源文件下载到本地,如果不对ASP文件加密,所有站点源文件将被窃取,这样不仅不利于维护网站的版权,而且会给站点的安全带来很大的隐患。本节将介绍如何对ASP文件进行加密。

6.5.1  应用Script Encoder加密工具

Script Encoder是Microsoft推出的一个script加密工具,它是一个简单的命令行工具,可以对html文件进行加密,只是对其中的VBscript部分进行加密处理,其他的文本部分均保持不变,加密后对script的功能并无影响,仅是其代码变成密文,用源文件方式查看只是一些乱码。该程序除了可对html文件加密外,也可以对asa、asp、cdx、js、sct、vbs文件进行加密。该程序很小只有64K,使用非常简单,在DOS命令行下执行,也可在Windows下带参数运行。

1.方案分析

应用Script Encoder对asp文件进行加密,首先依次单击“开始”→“程序”→“附件”→“命令提示符”,在MS-DOS命令行中输入以下命令,即可对某asp文件进行加密,加密格式如下:

SCRENC  [switches]  <要加密asp文件名>  <加密后的文件名>

在SRCENC命令中应用到了switches选项,该选项的常用参数如下所示,下面对常用的属性进行详细说明:

/s 可选。命令中带了该参数,加密过程中屏幕上就不会有输出。screnc /s lacl.sct ulacl.sct对当前目录中的脚本小程序lacl.sct加密,加密过程中屏幕不显示任何信息。

/f 可选。指定输出文件是否覆盖同名输入文件。忽略,将不执行覆盖。screnc /f lacl.asp对文件lacl.asp加密,并用编码后的同名文件覆盖原文件。

/xl 可选。是否在asp文件的顶部添加@Language指令。忽略,将添加。

/l defLanguage 可选。指定Script Encoder加密中选择的缺省脚本语言。文件中不包含这种脚本语言特性的脚本将被Script Encoder 忽略。

对于HTML文件,JScript为内置缺省脚本语言;对于ASP文件,VBScript为缺省脚本语言;对于扩展名为.vbs或.js的文件,Script Encoder也有适应能力。screnc /l vbscript lacl.htm ulacl.htm对文件lacl.htm加密,并生成输出文件ulacl.htm,确保没有指定语言属性的脚本使用VBScript。

/e defExtension 可选。指定待加密文件的文件扩展名。缺省状态下,Script Encoder能识别asa、asp、cdx、htm、html、js、sct和vbs文件。screnc /e asp 11\*.* f:\labxw-jm对11目录中的所有.ASP 文件进行加密,并把编码后的输出文件放在f:\labxw-jm目录中。

2.实施过程

*  实例位置:光盘\mr\6\6.5\6.5.1

Script Encoder加密工具可以对asp、html、asa、cdx、sct和vbs等文件进行加密。下面将使用Script Encoder加密工具对index.asp进行加密,其中index.asp加密前的内容如图6.40所示。

具体步骤如下:

(1)安装Script Encoder加密工具到目录c:\test下。

(2)把需要加密的ASP文件也拷到目录c:\test下。

(2)依次选择“开始”→“程序”→“附件”→“命令提示符”。

(3)在“命令提示符”对话框中,首先转换到目录c:\test(即输入命令 cd c:\test)下,然后再C盘中建立test1文件夹,文件夹建立完成后并输入以下代码即可:

screnc *.asp c:\test1

最后应该得到如下代码:

C:\test>screnc *.asp c:\test1

通过Script Encoder加密工具对index.asp文件进行加密后的结果如图6.41所示。

图6.40  加密前的文件

图6.41  加密后的文件

3.补充说明

通过本方案的学习,读者可以很轻松地对指定的ASP文件进行加密,还可以对html文件进行加密,但是不能对JavaScript脚本语言进行加密处理。

6.5.2  将ASP文件转换成HTML文件

对ASP文件进行加密,除了使用Script Encoder加密工具外,还可以将ASP文件转换为HTML格式的文件。下面将对ASP文件转换为HTML文件的具体实现过程进行分析和说明。

1.方案分析

首先通过Microsoft.XMLHTTP方法可以获取到asp文件中信息内容的二进制数据,然后再通过ADO的Stream对象将二进制数据转换为字符串,最后将获取到的数据写入到html文件中。

2.实施过程

*  实例位置:光盘\mr\6\6.5\6.5.2

在开发动态网站时,应考虑到随着网站访问量的不断增多,服务器的承载压力也会越来越大。如果将asp文件转换成html文件,既可以减轻服务器的承载压力和提高网站的浏览速度,又可以保证asp文件的源代码不被泄漏,从而达到提高asp文件安全性的目的,如图6.42所示。

图6.42  将ASP文件转换成HTML文件的运行结果

运行本实例,如图6.42所示,首先在图中的文本框中输入要转换成html格式的asp文件的地址,然后单击“提交”按钮即可实现将asp格式文件转换为html格式,实现该过程的关键代码如下:

例程6-29  代码位置:光盘\mr\6\6.5\6.5.2\index.asp

<%

Function GetContent(url) 

'获取文件内容

  Dim XMLObj

  Set XMLObj = CreateObject("Microsoft.XMLHTTP")

  With XMLObj

   .Open "Get", url, False

   .Send

   GetContent=BytesToBstr(.ResponseBody)

  End With 

End Function

Function BytesToBstr(info) 

'将二进制转换为字符串

 dim objstream

 set objstream = Server.CreateObject("adodb.stream")

 objstream.Type = 1

 objstream.Mode =3

 objstream.Open

 objstream.Write info

 objstream.Position = 0

 objstream.Type = 2

 objstream.Charset = "GB2312"

 BytesToBstr = objstream.ReadText

 objstream.Close

 set objstream = nothing

End Function

If Request.Form("url")<>"" Then

on error resume next

Url=Request.Form("url") 

'需要注意的是这里的URL指定为您要读取的页面地址

'开始获取/更新页面...

wstr = GetContent(Url)

'生成html文档

Set FSO=Server.CreateObject("Scripting.FileSystemObject")

htmPath=server.MapPath("index.htm")

If (FSO.FileExists(htmPath)) Then

  FSO.DeleteFile(htmPath)

End If

Set TSobj=FSO.CreateTextFile(htmPath)

TSobj.Writeline(wstr)

set TSobj=nothing

set FSO=nothing

If err<>0 Then

  Response.Write("<script language='javascript'>alert('操作失败,未能生成HTML文件!');window.location.href='index.asp';</script>")

  Response.End()

Else

  Response.Redirect("index.htm")

End If

End If

%>

3.补充说明

将asp格式的文件转换为html格式,即可以有效地提高服务器端的速度,而且还可以在很大程度上提高站点的安全性。

posted @ 2009-04-01 05:12  jiania  阅读(1375)  评论(0编辑  收藏  举报