一个评分系统,用于对您的在线文章进行评分并以图形方式显示评分






3.94/5 (53投票s)
2004年10月15日
22分钟阅读

123429
本教程将引导您使用 ASP.NET 和 SQL Server 构建一个评分系统,该系统允许用户对文章进行评分,然后以图形方式在文章上显示评分。
目录
引言
本教程将引导您完成使用 ASP.NET、Visual Basic .NET 和 SQL Server 构建评分系统的过程,该系统允许您的用户对文章进行评分,然后以图形方式在文章上显示评分。
讨论
如果您在互联网上发布文章,您可能希望获取用户反馈,以了解文章对目标用户社区的有用性。您需要控制偏差,以防止同一个人多次评分,并且您可能希望向用户提供文章总体评分的视觉反馈。
在本教程中,您将学习如何使用 Visual Basic .NET 作为编程语言,在 ASP.NET 和 SQL Server 中开发和实现一个基本的内容评分系统。您将首先学习如何设置用于捕获用户评分的数据库表。接下来,您将学习如何构建显示文章评分的图形用户界面组件。最后,您将学习如何逐行构建必要的逻辑。您将学习的评分系统正是 StephanBren.Com 正在使用的系统。此系统中的代码是模块化的:它查找文章的唯一 ID。一旦您为一篇文章创建了它,您所需要做的就是将其复制并粘贴到每个后续文章中,只需更改文章 ID 变量。这是此评分系统的 1.0 版本。版本 2 将把评分系统实现为一个类模块,以进一步实现代码的紧凑性和可重用性。本文假设您熟悉 SQL Server,尽管此处讨论的数据库概念同样适用于 Oracle。
您还可以使用 Microsoft Access 后端实现此系统的版本 1。但是,从 ASP.NET 中打开 Access 数据库文件涉及某些安全问题,这些问题超出了本文的范围,将在后续文章中介绍。
任务 1:需求定义
在开始开发之前,您首先需要定义项目应满足的需求。对于此项目,需求分为三类:数据、界面和业务规则。数据需求是通过确定您想要捕获和显示哪些特定用户数据来定义的。界面需求是通过您希望如何让用户输入数据以及如何向用户显示数据输入结果来定义的。业务规则需求是通过您希望评分系统在不同用户场景下做什么来定义的。让我们从定义数据需求开始。
任务 1.a:数据
可以通过为您的文章创建识别系统来唯一识别文章。例如,您可能已经注意到 StephanBren.Com 上的每篇文章都有一个唯一的 ID 号。此数字作为变量存储在文章网页的服务器端副本中。文章 ID 系统从 100001 开始。接下来,您需要定义一个数字评分系统 - 本网站使用 1 到 5 的五位数字范围。使用奇数范围是为了允许中性评分,对于 1-5 的范围,中性评分为 3。最后,需要从用户那里捕获一个唯一识别该用户的数据项。您需要此数据项才能筛选并防止同一用户多次评分。尝试唯一识别通过互联网连接的匿名用户并非易事,并且没有万无一失的方法,除非您只希望注册用户能够对您的文章进行评分 - 注册用户根据定义具有唯一 ID。您可以获得的一个项目是用户的 IP 地址,您可以通过 HTTP 请求对象访问该地址。此数据元素也不是万无一失的,因为对于电话拨号用户,此 IP 在用户每次拨入其 ISP 并建立互联网连接时都会更改。您必须决定您希望如何严格控制和过滤用户评分。对于本网站,只捕获用户的 IP 地址。
因此,这个基本评分系统旨在捕获以下数据项
ArticleID
:一个唯一的标识,允许您正确识别被评分的文章。rating
:一个与文章评分(从 1 到 5)对应的数字。ip
:一个(在大多数情况下)唯一标识对文章进行评分的用户的数据项。
任务 1.b:用户界面
用户界面需求取决于您希望如何捕获和显示评分信息。最简单也是最常见的方法是使用一系列单选按钮捕获评分信息,每个单选按钮对应一个特定的评分数字。选择特定评分后,用户点击提交按钮将响应发布回 Web 服务器进行处理。由于我们确定了 5 的评分范围,因此每篇文章必须在单个组中显示一系列五个单选按钮以及一个提交按钮 - 此外,还必须向用户提供关于评分量表方向的指示,从差到好,或从好到差(从左到右阅读)。要显示评分数据,您基本上有两种选择:使用文本,例如实际数字,或使用图像。文本方法最简单,但吸引力最小。视觉方法最常见。在这两种方法中,您都需要让用户对正面评分与负面评分的相对比例有所了解。
例如,对于基于文本的方法,您可能希望显示文章的平均评分以及该文章迄今为止的总评分数。对于视觉方法,您可以显示一系列星形图形,其中五颗星(对应于我们的评分范围)是最高评分,一颗星是最低评分。或者,您可以显示一个条形图,条形图的长度与平均评分成比例。
这个文章评分系统使用两个条形图像表示平均评分,以及一个基于文本的数字表示文章迄今为止的总评分数。两个条形图像提供了总体评分的相对概念:一个条形图像表示正面评分,另一个表示负面评分。两个条形图像的总长度保持不变——只有单个长度会改变。这种方法提供了一种快速直观的方式向用户显示评分信息,并且是 stephanbren.com 使用的方法。您可能还希望向用户提供额外信息,例如提醒用户他可能是第一个评价该文章的人,或者他过去已经评价过该文章,因此无法再次评价该文章。
关于评分系统最后要考虑的是在哪里显示评分信息。如果将其显示在文章网页的顶部,您可以保证大多数用户会立即看到它,这使得用户可以方便地快速使用。通过将评分显示放在文章页面顶部,您可以为用户提供关于文章评分的快速、即时信息。如果将其放在文章网页的末尾,一些用户可能会错过它,并且评分系统使用起来会稍微不方便。您还可以决定将评分系统放在文章网页顶部和底部之间的某个位置。同样,您需要记住浏览器高度和平均显示器分辨率:这些限制可能导致用户最初连接到您的文章时无法看到您的评分显示。对于 stephanbren.com,所有评分显示都放在每个文章页面的顶部。这种放置确保了 stephanbren.com 用户对评分工具的即时可见性和可用性。
任务 1.c:业务规则
为了建立业务规则需求,我们需要仔细描述当用户连接到文章和/或尝试使用我们的评分系统对文章进行评分时,我们设想发生的过程。这可以通过构建评分系统的粗略用例来完成,如下所示:
- 用户连接到文章。
- 用户查看当前文章评分。
- 如果文章尚未被评分,用户会看到一条消息提醒他这一点,并可能鼓励他成为第一个评分这篇文章的人;评分系统显示相当于中性或未评分文章的内容。
- 如果文章已被评分,用户会看到评分系统显示迄今为止平均评分的视觉等效内容。
- 用户选择特定评分并点击提交。
- 文章评分已刷新;用户停留在同一页面(没有跳转到其他页面)。
- 如果用户以前评分过这篇文章,用户会看到一条消息提醒他这一点;并且他无法再次评分这篇文章。
- 如果用户以前没有评分过这篇文章,用户会看到显示更新以包含他的评分。
这描述了用户与评分系统交互时所经历的过程。此用例为构建评分系统的实际代码提供了框架。
这完成了定义我们的评分系统必须满足的初始需求的过程。现在让我们执行实际开发评分系统的任务。
任务 2:开发
至此,您已经有了开始开发的良好基础。在定义了评分系统必须满足的需求之后,接下来就是要实际实现它们。第一个开发任务是为评分系统设计后端或数据库。此评分系统的后端可以是您选择的任何数据存储。Stephanbren.com 使用 SQL Server 后端,因此我们的下一个任务涉及向现有的 stephanbren.com 数据库添加一个新表。一旦数据库开发完成,下一个任务将是识别我们需要从用户捕获并向用户显示文章评分信息的用户界面组件。最后,我们将执行开发支持评分系统所需的代码的任务。
任务 2.a:数据库
根据前面确定的数据需求,您首先需要在 SQL Server 中创建一个具有以下建议设计的表
该图片显示了 stephanbren.com 用于存储评分信息的实际表格设计。它包括前面定义的三个数据元素,并且包括一个主键,用于唯一标识表中输入的每个评分。
ratingID
:唯一标识每个评分的主键。每当向表中插入新记录时,此数字由数据库自动生成。rating
:用户提交给评分系统的数字评分,从 1 到 5。ip
:HTTP 请求对象提供给评分系统的用户 IP 地址。itemID
:文章的唯一 ID。
为了在用户首次连接时简单地检索和计算特定文章的评分,执行了一个 SQL 操作。此操作计算表中具有与用户连接到的文章 ID 相同的 itemID
的记录数
SELECT SUM(rating) As RatingSum, COUNT(*) As RatingCount FROM tbl_Rating
WHERE Itemid= [the article's ID]
要确定用户是否已经评价过某篇文章,将执行一个 SQL 操作。此操作会选择所有具有与用户所连接文章 ID 相同的 itemID
,并且 IP 地址与用户 IP 地址相同的记录
SELECT COUNT(*) As RatingCount FROM tbl_Rating
WHERE Itemid= [the article's ID] AND ip = [the user's ip]
最后,要向表中插入新评分,执行以下 SQL INSERT
操作
INSERT INTO tbl_rating (rating, ip, itemID)
VALUES ( [the user's rating], [the user's ip], [the article's ID]);
这三个 SQL 语句是评分系统获取显示评分信息、查明用户是否已评价过文章以及插入用户评分所需的全部内容。
任务 2.b:用户界面
下一个任务是为评分系统构建用户界面。如前所述,评分系统将需要五个单选按钮,一个用于将数据发布到 Web 服务器的命令按钮,一些图像以及一些用于显示文本信息的标签。这些界面项分别由 ASP.NET 的 radiobuttonlist、button、image 和 label 控件提供。
为了构建系统的用户界面,方便起见,可以将所有元素分组到一个表中,以实现最大的可移植性,如下所示
[视觉评分显示] / [评分计数标签] | |||
“差” | [单选按钮列表] | “棒!” | [按钮] |
[用户反馈标签] |
“[]”中的项表示需要添加到表中的 ASP.NET Web 控件,而“""”中的项表示简单文本。因此,Web 控件是
- 两个图像控件,
imgRatingApproval
和imgRatingBlank
。 - 两个标签控件,
lblRatingCount
和lblRating
。 - 一个 radiobuttonlist 控件,
rblRating
。 - 以及一个按钮控件,
btnRating
。
最终界面在设计时和运行时将类似于以下内容
![]() |
![]() |
界面的标记将如下所示
<table width="0%" border="0" class="basic11pt">
<tr>
<td colspan="4">Rating:
<asp:image ID="imgRatingApproval" runat="server"></asp:image>
<asp:image ID="imgRatingBlank" runat="server"></asp:image>
<asp:label ID="lblRatingCount" runat="server"></asp:label>
</td>
</tr>
<tr>
<td>poor</td>
<td><asp:radiobuttonlist RepeatLayout="Flow"
RepeatDirection="Horizontal"
ID="rblRating"
runat="server">
<asp:listitem Value="1">1</asp:listitem>
<asp:listitem Value="2">2</asp:listitem>
<asp:listitem Value="3" selected="True">3</asp:listitem>
<asp:listitem Value="4">4</asp:listitem>
<asp:listitem Value="5">5</asp:listitem>
</asp:radiobuttonlist></td>
<td>great</td>
<td><asp:button ID="btnRating"
OnClick="btnRating_Click"
runat="server"
Text="Rate It!" /></td>
</tr>
<tr>
<td colspan="4"><asp:label ID="lblRating"
runat="server"></asp:label></td>
</tr>
</table>
提示:为了确保您的两个评分图像 imgRatingApproval
和 imgRatingBlank
在浏览器中查看时紧密相邻,请确保这两个图像的 ASP.NET 标记也相邻。为了使页面看起来更美观,它们在上面分行显示。实际上,您需要将两个图像控件放在同一行,中间没有任何空格。
您会注意到,如前所述,所有界面元素都分组在一个表中。这使得标记可重复且易于通过剪切粘贴方法移植。您将对您希望实现评分系统的每篇文章使用相同的标记。
这完成了用户界面的所有开发,让我们继续构建业务逻辑。
任务 2.c:业务逻辑
最后的开发任务是为评分系统构建实现逻辑。为了构建此实现逻辑,让我们首先回顾前面开发的流程大纲,用一些伪代码填充大纲框架
- 用户连接到文章。
- 构建 SQL
SELECT
语句。 - 连接到数据库。
- 检索文章的评分总和和计数。
- 计算评分。
- 关闭连接。
- 构建 SQL
- 用户查看当前文章评分。
- 如果文章尚未被评分,用户会看到一条消息提醒他这一点,并可能鼓励他成为第一个评分这篇文章的人;评分系统显示相当于中性或未评分文章的内容。
- 将图像控制宽度属性设置为相同的宽度。
- 设置
lblRatingCount.text
以显示“ / 0”。 - 设置
lblRating.text
以显示“成为第一个评价这篇文章的人”。 - 相应地设置其他显示属性。
- 如果文章已被评分,用户会看到评分系统显示迄今为止平均评分的视觉等效内容。
- 设置
imgRatingApproval.width
为平均评分 x 某个乘数因子(以增加显示宽度)。 - 设置
imgRatingBlank.width
为总宽度 -imgRatingApproval.width
。 - 设置
lblRatingCount.text
为计数。 - 设置
lblRating.text
为空
- 设置
- 如果文章尚未被评分,用户会看到一条消息提醒他这一点,并可能鼓励他成为第一个评分这篇文章的人;评分系统显示相当于中性或未评分文章的内容。
- 用户选择特定评分并点击提交。
- 构建 SQL 语句以确定用户是否以前对文章进行过评分。
- 连接到数据库。
- 检索结果记录计数。
- 如果用户以前没有评价过文章,则构建 SQL
INSERT
语句并执行该语句。
- 如果用户以前没有评价过文章,则构建 SQL
- 关闭现有连接。
- 打开一个新连接。
- 检索文章的评分总和和计数。
- 计算评分。
- 设置
imgRatingApproval.width
为平均评分 x 某个乘数因子(以增加显示宽度)。 - 设置
imgRatingBlank.width
为总宽度 -imgRatingApproval.width
。 - 设置
lblRatingCount.text
为计数。 - 设置
lblRating.text
为空。 - 关闭连接。
- 文章评分已刷新;用户停留在同一页面(没有跳转到其他页面)。
- 如果用户以前评分过这篇文章,用户会看到一条消息提醒他这一点;并且他无法再次评分这篇文章。
- 设置
lblRating.text
为“您之前已评价过这篇文章” - 相应地设置其他控件属性。
- 设置
- 如果用户以前没有评分过这篇文章,用户会看到显示更新以包含他的评分。
- 如果用户以前评分过这篇文章,用户会看到一条消息提醒他这一点;并且他无法再次评分这篇文章。
此大纲现在已准备好进行开发。现在让我们将此大纲开发成代码。
当用户首次连接到网页时,会处理上述第 1 项和第 2 项。您希望此代码在用户连接到网页时运行,无论是通过引用、直接在浏览器中输入 URL 还是刷新页面。为了在用户连接到网页时运行代码,请使用文章网页的 Load
事件来驱动代码。因此,将以下代码插入到您的网页中
<script runat="server">
Private intPageID as Long = <your article ID here>
Sub Page_Load(Src As Object, E As EventArgs)
End Sub
</script>
intArticleID
变量包含分配给本文的唯一 ID。构建评分系统代码后,您可以将其复制并粘贴到您发布的每篇文章中,只需更改每个网页的文章 ID。现在,您只希望此代码在用户只是连接到页面时运行,即,用户没有尝试对文章进行评分并回发结果,这在 ASP.NET 中称为 PostBack。因此,您需要在运行代码之前检查 ASP.NET 页面对象的 IsPostback
属性。因此,代码修改如下
<script runat="server">
Private intPageID as Long = <your article ID here>
Sub Page_Load(Src As Object, E As EventArgs)
If Not IsPostback Then
End If
End Sub
</script>
现在我们来构建数据连接逻辑。对于您将反复使用的全局常量,ASP.NET 提供了一个可扩展的配置系统,允许您在部署时定义自定义应用程序配置设置,您以后可以轻松更改。这些配置设置方便地存储在应用程序根目录下的 *web.config* 文件中。配置信息以标准 XML 格式存储,您可以使用任何文本编辑器进行编辑,因为此文件不过是一个 ASCII 文本文件。一旦您定义了一个要在整个应用程序中使用的应用程序配置设置(这些设置的作用域为 Public
),您就可以使用 Configuration
对象的 ConfigurationSettings.AppSettings
属性从应用程序中访问它们,如下所示(在 Visual Basic .NET 中)
System.Data.SqlClient.sqlConnection(_
System.Configuration.ConfigurationSettings.AppSettings("<your key name>"))
要以这种方式创建应用程序设置,只需打开任何文本编辑器,然后添加以下文本
<!-- Web.Config Configuration File -->
<configuration>
<appSettings>
<add key="MyConnectionString" value="your SQL Server connection string "/>
</appSettings>
</configuration>
将此文件保存为 *web.config* 并将其放置在您网站的根文件夹中。您现在已为您的网站定义了一个基本的全局常量。请确保将 <your key name> 替换为您要分配给连接字符串的名称。
注意:您需要从您的 ISP 获取实际的连接字符串。典型的连接字符串将包括以下元素
- 数据源
- 初始目录
- 用户 ID
- 密码
- 持久安全信息
- 数据包大小
将所有这些元素放入一个字符串中,结果将类似于以下内容
value="data source=[the URL to your SQL Server database];
initial catalog=[your database name];user id=[your username];
password=[your password];persist security info=[set to True];
packet size=[default packet size is 4096, but use larger one
if your network supports it]"
现在,让我们构建数据访问逻辑。我们将需要 Connection
、Command
和 DataReader
对象。由于本演练使用的是 Microsoft SQL Server 后端,我们将分别使用这些对象的 sqlClient
变体,即 SqlConnection
、SqlCommand
和 SqlDataReader
。这些对象位于 System.Data.SqlClient
命名空间中。
回到您的 Page_Load
事件,并定义您的变量并实现您的数据逻辑,如下所示
<script runat="server">
Private intPageID As Long = [your article ID here]
Sub Page_Load(Src As Object, E As EventArgs)
Dim intApprovalWidth, intBlankWidth as Integer
Dim strQuery as string
Dim strCon As String
Dim conMyConnection as New System.Data.SqlClient.sqlConnection()
Dim cmdMyCommand as New System.Data.SqlClient.SqlCommand()
Dim dtrMyDataReader as System.Data.SqlClient.sqlDataReader
If Not IsPostback Then
strCon = System.Configuration.ConfigurationSettings.AppSettings(_
"MyConnectionString")
conMyConnection.ConnectionString = strCon
strQuery = "SELECT SUM(rating) As RatingSum, COUNT(*) As RatingCount "
strQuery += "FROM tblMyRatings WHERE Itemid=" & intArticleID
conMyConnection.Open()
cmdMyCommand.Connection = conSb
cmdMyCommand.CommandType = System.Data.CommandType.Text
cmdMyCommand.CommandText = strQuery
dtrMyDataReader = cmdMyCommand.ExecuteReader()
dtrMyDataReader.Read()
[code for building rating display goes here]
dtrMyDataReader.Close()
conMyConnection.Close()
End If
End Sub
</script>
请注意,DataReader
的 Read
方法被调用了一次——您需要这样做。当 DataReader
对象最初用从数据库返回的结果集填充时,其游标最初设置在第一条记录之前。调用 Read
方法一次会将游标移动到第一条记录。还要注意,在从 DataReader
读取所有数据之前,连接对象的 Close
方法不会被调用。这是因为数据访问方法是一种连接访问方法。如果您在从 DataReader
检索数据之前关闭连接,您将丢失 DataReader
中当前的所有数据。
下一个开发任务是实现一个决策结构,以确定要显示什么:文章是否已被评分。我们的决策结构将检查查询返回的 RatingCount
:如果为零,则表示尚未提交任何评分。否则,已提交评分。对于没有评分的情况,将图像设置为相同宽度,并向用户显示邀请消息,鼓励他们成为第一个对文章进行评分的人。否则,如果文章已被评分,则计算平均评分,然后相应地设置图像属性。
<script runat="server">
Private intPageID As Long = [your article ID here]
Sub Page_Load(Src As Object, E As EventArgs)
Dim intApprovalWidth, intBlankWidth as Integer
Dim strQuery as string
Dim strCon As String
Dim conMyConnection as New System.Data.SqlClient.sqlConnection()
Dim cmdMyCommand as New System.Data.SqlClient.SqlCommand()
Dim dtrMyDataReader as System.Data.SqlClient.sqlDataReader
If Not IsPostback Then
strCon = System.Configuration.ConfigurationSettings.AppSettings(_
"MyConnectionString")
conMyConnection.ConnectionString = strCon
strQuery = "SELECT SUM(rating) As RatingSum, COUNT(*) As RatingCount "
strQuery += "FROM tblMyRatings WHERE Itemid=" & intArticleID
conMyConnection.Open()
cmdMyCommand.Connection = conMyConnection
cmdMyCommand.CommandType = System.Data.CommandType.Text
cmdMyCommand.CommandText = strQuery
dtrMyDataReader = cmdMyCommand.ExecuteReader()
dtrMyDataReader.Read()
If dtrKb("RatingCount") = 0 Then
lblRatingCount.Text = " / " & dtrKb("RatingCount")
intApprovalWidth = dtrKb("RatingSum")/dtrKb("RatingCount")*15
intBlankWidth = 75 - intApprovalWidth
imgRatingApproval.Width = _
System.web.ui.webcontrols.unit.pixel(intApprovalWidth)
imgRatingBlank.Width = _
System.web.ui.webcontrols.unit.pixel(intBlankWidth)
Else
lblRatingCount.Text = "/0"
lblRating.Text = "Be the first to rate it!"
End If
dtrMyDataReader.Close()
conMyConnection.Close()
End If
End Sub
</script>
请注意用于增加评分数字的系数15。这样做是为了增加图像的宽度。否则,您的图像宽度不会超过5像素,这对应于评分系统返回的数字的1-5范围。认可图像的宽度设置为此乘积。空白图像(或不认可)的宽度设置为两个图像的总宽度减去认可宽度。两个图像的总宽度等于最大评分和系数的乘积,即75。无论评分如何,此总长度都保持不变。这样,我们的评分系统提供了关于文章的一致信息,即相对评分比率。这完成了我们上面代码大纲第1部分和第2部分的所有开发。此代码在用户首次连接到页面时运行。如果用户正在向网页回发评分,则不运行此代码。现在让我们开发允许用户发布新评分的业务逻辑。
此前,我们定义了用户界面,开发了构建和显示用户界面所需的标记。回想一下,其中一个用户界面元素就是按钮元素
<asp:button ID="btnRating" OnClick="btnRating_Click"
runat="server" Text="Rate It!" />
在包含 Page_Load
事件处理程序的脚本标签内,添加以下过程定义
<script runat="server">
.
.
.
Sub btnRating_Click(Src As Object, E As EventArgs)
End Sub
</script>
在此事件处理程序中,我们将需要重复我们之前开发的数据访问逻辑。带有三个代码块的按钮单击事件处理程序
- 在第一个块中,捕获用户的 IP 地址,然后查询评分表以确定用户是否以前评价过此文章。
- 只有当用户之前没有评价过文章时,才会执行第二个代码块。在此代码块中,将创建并针对数据库执行插入新评分的查询。
- 第三个也是最后一个代码块基本上重复了
Page_Load
代码的操作,更新显示屏以显示文章评分信息。
我们先来声明此过程中使用的变量
<script runat="server">
.
.
.
Sub btnRating_Click(Src As Object, E As EventArgs)
'Variable declarations...
Dim intApprovalWidth, intBlankWidth as Integer
Dim strQuery as string
Dim strCon As String
Dim conMyConnection as New System.Data.SqlClient.sqlConnection()
Dim cmdMyCommand as New System.Data.SqlClient.SqlCommand()
Dim dtrMyDataReader as System.Data.SqlClient.sqlDataReader
End Sub
</script>
然后构建第一个代码块的代码,该代码块确定用户是否之前评价过文章。为此,我们需要声明并设置一个新对象,该对象帮助我们从 HTTP 请求对象中检索用户的 IP 地址。我们还可以声明一些临时存储变量
<script runat="server">
.
.
.
Sub btnRating_Click(Src As Object, E As EventArgs)
'Variable declarations...
Dim intApprovalWidth, intBlankWidth as Integer
Dim strSelectQuery, strInsertQuery as string
Dim strCon As String
Dim conMyConnection as New System.Data.SqlClient.sqlConnection()
Dim cmdMyCommand as New System.Data.SqlClient.SqlCommand()
Dim dtrMyDataReader as System.Data.SqlClient.sqlDataReader
Dim MyHttpAppObject As System.Web.HttpContext = _
System.Web.HttpContext.Current
Dim strRemoteAddress as String
Dim intSelectedRating, intCount As Integer
'Get the user's ip address and cast its type to string...
strRemoteAddress = Cstr(MyHttpApp.Request.UserHostAddress)
'Build the query string...
strSelectQuery = "SELECT COUNT(*) As RatingCount "
strSelectQuery += "FROM tbl_Rating WHERE Itemid=" & intArticleID "
strSelectQuery += " AND ip = '" & strRemoteAddress & "'"
'Open the connection, and execute the query...
strCon = System.Configuration.ConfigurationSettings.AppSettings(_
"MyConnectionString")
conMyConnection.ConnectionString = strCon
conMyConnection.Open()
cmdMyCommand.Connection = conMyConnection
cmdMyCommand.CommandType = System.Data.CommandType.Text
cmdMyCommand.CommandText = strSelectQuery
intCount= cmdMyCommand.ExecuteScalar()
conMyConnection.Close() 'Close the connection to
'release these resources...
If intCount = 0 Then 'The user hasn't rated the article
'before, so perform the insert...
Else 'The user has rated the article
'before, so display a message...
End If
End Sub
</script>
此代码块现在能够(在大多数情况下)唯一标识用户,然后在数据库中查找此用户的 IP。如果找到与当前文章匹配的项,则不将用户的评分插入数据库。否则,插入。现在让我们插入此决策结构的代码
<script runat="server">
.
.
.
Sub btnRating_Click(Src As Object, E As EventArgs)
'Variable declarations...
Dim intApprovalWidth, intBlankWidth as Integer
Dim strSelectQuery, strInsertQuery as string
Dim strCon As String
Dim conMyConnection as New System.Data.SqlClient.sqlConnection()
Dim cmdMyCommand as New System.Data.SqlClient.SqlCommand()
Dim dtrMyDataReader as System.Data.SqlClient.sqlDataReader
Dim MyHttpAppObject As System.Web.HttpContext = _
System.Web.HttpContext.Current
Dim strRemoteAddress as String
Dim intSelectedRating, intCount As Integer
'Get the user's ip address and cast its type to string...
strRemoteAddress = Cstr(MyHttpApp.Request.UserHostAddress)
'Build the query string...
strSelectQuery = "SELECT COUNT(*) As RatingCount "
strSelectQuery += "FROM tbl_Rating WHERE Itemid=" & intArticleID "
strSelectQuery += " AND ip = '" & strRemoteAddress & "'"
'Open the connection, and execute the query...
strCon = System.Configuration.ConfigurationSettings.AppSettings(_
"MyConnectionString")
conMyConnection.ConnectionString = strCon
conMyConnection.Open()
cmdMyCommand.Connection = conMyConnection
cmdMyCommand.CommandType = System.Data.CommandType.Text
cmdMyCommand.CommandText = strSelectQuery
intCount= cmdMyCommand.ExecuteScalar()
conMyConnection.Close() 'Close the connection to
'release these resources..
If intCount = 0 Then 'The user hasn't rated the article before,
'so perform the insert...
strInsertQuery = "INSERT INTO tbl_rating (rating, ip, itemID) "
strInsertQuery += "VALUES ("
strInsertQuery += intSelectedRating & ", '"
strInsertQuery += strRemoteAddress & "', "
strInsertQuery += intArticleID & "); "
cmdMyCommand.CommandText = strInsertQuery
conMyConnection.Open()
cmdMyCommand.ExecuteNonQuery()
conMyConnection.Close()
Else 'The user has rated the article
'before, so display a message...
lblRating.Text = "You've already rated this article"
End If
End Sub
</script>
通过这段代码,我们的评分系统能够检测用户是否之前评价过这篇文章。对于最后一个代码块,我们只需重复 Page_Load
过程中的代码,因为它本质上只是刷新显示。最后一个代码列表显示了实现 btnRating_Click
过程所需的全部代码
<script runat="server">
.
.
.
Sub btnRating_Click(Src As Object, E As EventArgs)
'Variable declarations...
Dim intApprovalWidth, intBlankWidth as Integer
Dim strSelectQuery, strInsertQuery as string
Dim strCon As String
Dim conMyConnection as New System.Data.SqlClient.sqlConnection()
Dim cmdMyCommand as New System.Data.SqlClient.SqlCommand()
Dim dtrMyDataReader as System.Data.SqlClient.sqlDataReader
Dim MyHttpAppObject As System.Web.HttpContext = _
System.Web.HttpContext.Current
Dim strRemoteAddress as String
Dim intSelectedRating, intCount As Integer
'Get the user's ip address and cast its type to string...
strRemoteAddress = Cstr(MyHttpApp.Request.UserHostAddress)
'Build the query string...
strSelectQuery = "SELECT COUNT(*) As RatingCount "
strSelectQuery += "FROM tbl_Rating WHERE Itemid=" & intArticleID "
strSelectQuery += " AND ip = '" & strRemoteAddress & "'"
'Open the connection, and execute the query...
strCon = System.Configuration.ConfigurationSettings.AppSettings(_
"MyConnectionString")
conMyConnection.ConnectionString = strCon
conMyConnection.Open()
cmdMyCommand.Connection = conMyConnection
cmdMyCommand.CommandType = System.Data.CommandType.Text
cmdMyCommand.CommandText = strSelectQuery
intCount= cmdMyCommand.ExecuteScalar()
conMyConnection.Close() 'Close the connection to
'release these resources...
If intCount = 0 Then 'The user hasn't rated the article
'before, so perform the insert...
strInsertQuery = "INSERT INTO tbl_rating (rating, ip, itemID)"
strInsertQuery += "VALUES ("
strInsertQuery += intSelectedRating & ", '"
strInsertQuery += strRemoteAddress & "', "
strInsertQuery += intArticleID & "); "
cmdMyCommand.CommandText = strInsertQuery
conMyConnection.Open()
cmdMyCommand.ExecuteNonQuery()
conMyConnection.Close()
Else 'The user has rated the article
'before, so display a message...
lblRating.Text = "You've already rated this article"
End If
strSelectQuery = _
"SELECT SUM(rating) As RatingSum, COUNT(*) As RatingCount"
strSelectQuery += "FROM tbl_Rating WHERE Itemid=" & intPageID
conMyConnection.Open()
cmdMyCommand.CommandText = strSelectQuery
dtrMyDataReader = cmdMyCommand.ExecuteReader()
dtrMyDataReader.Read()
lblRatingCount.Text = " / " & dtrKb("RatingCount")
intApprovalWidth = _
dtrKb("RatingSum")/dtrKb("RatingCount")*15
dtrMyDataReader.Close()
conMyConnection.Close()
intBlankWidth = 75 - intApprovalWidth
imgRatingApproval.Width = _
System.web.ui.webcontrols.unit.pixel(intApprovalWidth)
imgRatingBlank.Width = _
System.web.ui.webcontrols.unit.pixel(intBlankWidth)
End Sub
</script>
任务 3:测试
在您的网页文章中首次实现此代码后,您需要进行测试以确保已清理了拼写错误和其他语法问题。实现此评分系统的最佳方法是分节进行,然后测试
- 首先添加用户界面标记,然后将文章网页保存到您的网络服务器,并连接到它。您应该会看到一个类似于本文前面所示的评分界面。搞定界面后,再转向数据库。
- 其次,在 SQL Server 中创建表,如上图所示。这将是一个简单的任务。您稍后将需要此表。在此表中输入一些测试数据,例如包含文章 ID、IP 和评分的几个评分。
- 第三,在您的网页中添加脚本标签,确保页面以 ASPX 文件结尾。在脚本标签中,添加页面加载事件处理程序及其所有代码。将您的测试重点放在此代码块上。一旦您使其正常工作,您所有剩余的开发工作都将更顺利地进行。这是因为,如果您能使一个代码块的数据访问逻辑正常工作,那么其余的大部分工作都是剪切粘贴。如果您能使此代码块正常工作,则表示您的代码与界面和数据库之间的链接已成功。一旦您使页面加载事件代码每次都能正常工作,就继续处理其余的代码。
结论
在本文中,您学习了如何使用 Visual Basic .NET 和 SQL Server 为 ASP.NET 网页实现一个简单的评分系统。该评分系统以图形方式显示正面和负面评分的相对比例,并以数字形式显示提交的关于文章的评分总数。用户只能对文章进行一次评分,并且实现了一些简单的筛选方法来防止同一用户多次评分。该评分系统可以使用您喜欢的 HTML 编辑器完全实现。但是,您需要访问 Microsoft SQL Server。
参考文献
- MSDN - .NET Framework 类库 - Page.IsPostBack 属性.
- MSDN - .NET Framework 开发人员指南:访问 ASP.NET 配置设置.
- 开发文章 - 带有 ASP 的文章评分系统.
修订历史
- 2004年3月20日:创建。
- 2004年3月24日:修订了总体讨论;改进了图片。
- 2004年4月17日:小幅重新排版。
- 2004年7月15日:添加了目录;小幅重新排版。
- 2004年7月22日:移除了外壳标记;迁移到 dotnetnuke 门户。
- 2004年8月24日:迁移到 DNN2.X。
祝您编码愉快!