<% ASP на блюдечке %>. Часть 14
Разработка системы электронного голосования
Электронное голосование — что это такое?
Электронное голосование — а зачем оно?
Создание и подготовка базы данных
Интеграция системы в уже готовый сайт
Главная страничка (файл Vindex.asp)
Введение
Рассмотренные нами в предыдущих частях настоящей статьи примеры в той или иной степени представляли собой разнообразные интерфейсы к базам данных. А такая задача как разработка системы электронного голосования, нами пока не рассматривалась. В настоящей статье представлен материал, который позволит самостоятельно разработать такую систему, а также рассмотрен вопрос об организации переносимых модулей, позволяющих обеспечить легкое и удобное встраивание такой системы практически в любой сайт независимо от его сложности.
Электронное голосование — что это такое?
Разумеется, речь идет о наиболее типичной системе электронного голосования. Прежде всего — это система, предлагающая пользователю вопрос и несколько наиболее типичных вариантов ответа на него. Кроме того, это система сбора данных (обработки пользовательского ввода) и выдачи интегральных результатов голосования как в численном, так и в графическом представлении.
Сама система выбора того или иного варианта ответа может быть представлена как посредством логики «или», так и логики «и». Другими словами, в зависимости от того, допустим выбор более чем одного варианта ответа на поставленный вопрос или нет, может применяться одна из двух схем анализа ответа и соответственно один из двух компонентов формы опроса («радиокнопки» или «чекбоксы»). Но об этом чуть позже, а для начала все-таки уясним, какую выгоду может дать организация системы электронного голосования на вашем сайте.
Электронное голосование — а зачем оно?
Этот тривиальный вопрос может возникнуть у многих читателей. Во-первых, система электронного голосования может пробудить интерес к вашему сайту (например, пользователи вашего сайта могут пригласить поучаствовать в голосовании своих знакомых или коллег). Здесь наиболее существенным является постановка самой задачи голосования. Нередки случаи, когда вопрос выбирается с таким расчетом, чтобы втянуть отвечающих на него в дискуссию на форуме или в чате на том же сайте. Это делается специально для повышения активности сайта. Представьте себе, что вопрос звучит, к примеру так: «Сотовым телефоном какого производителя вы пользуетесь?» или «Доверяете ли вы президенту?». Таким образом, правильная постановка и выбор самого вопроса является мощным инструментом привлечения внимания к тому или иному сайту и в удачном сочетании с другим функционалом может обеспечить реальный успех в его продвижении.
Что нам понадобится?
Разумеется, предполагается, что читатель знаком с основами ASP- и SQL-программирования (первых частей настоящей статьи для этого будет вполне достаточно). Кроме того, нам потребуется Microsoft SQL Server 7.0 или 2000, какой-нибудь HTML- или текстовый редактор (рекомендую использовать Macromedia Dreamweaver UltraDev 4.0) и немного терпения.
Создание и подготовка базы данных
Создадим две таблицы: таблицу вопросов (VQuestions) и таблицу ответов (VAnswers). В таблице ответов заведем поле (Total) для регистрации количества полученных ответов. Представим себе их взаимосвязь так, как показано на рисунке.
Ключевыми здесь являются столбцы ID. A взаимосвязь столбца QuestionID таблицы ответов с столбцом ID таблицы вопросов, по сути, отражает взаимосвязь вопросов и ответов.
Далее необходимо прописать нашу базу данных в соответствующем разделе источников данных системы. Для этого сделайте следующее:
- Запустите программу — конфигуратор источников данных (Data Sources ODBC) — Start->Settings->Control Panel->Administrative Tools->Data Sources ODBC.
- Перейдите во вкладку System DSN и создайте новый источник данных, нажав на Add…
- В появившемся списке драйверов выберите драйвер баз данных — Microsoft SQL Server и нажмите на Next.
- В строке Data Source Name задайте имя нашей базы данных — в нашем случае Voter (это имя, по которому мы в дальнейшем будем обращаться к ней).
- В строке Server укажите сервер, к которому будет осуществлено подключение, и нажмите на Next.
- Выберите режим аутентификации With SQL Server…, задайте имя пользователя и пароль для подключения к SQL-серверу, определите протокол связи с сервером (кнопка Client Configuration — TCP/IP) и два раза нажмите на Next, после чего нажмите на Finish.
- Вы увидите статистику о проделанных действиях, а для проверки источника данных можете воспользоваться кнопкой Test Data Source.
- Перед вами появится строка в списке источников данных в вашей системе:
Voter SQL Server
Теперь, когда база данных готова, можно переходить к созданию самой системы электронного голосования.
Однако сначала необходимо уяснить еще один вопрос. Каким именно образом будет выбираться тот или иной вопрос из базы данных, ведь в общем случае (а мы рассмотрим именно его) вопросов в базе может быть несколько.
Для этого мы будем каждый раз выбирать тот или иной вопрос из базы данных случайным образом (с помощью генератора случайных значений).
Интеграция системы в уже готовый сайт
Дело в том, что само по себе голосование не имеет смысла. Посудите сами, кому нужен сайт, предназначенный исключительно для системы электронного голосования. С другой стороны, интеграция его в уже готовый сайт «в чистом виде» может создать сложности — как для восприятия исходного текста, так и в дальнейшем, например, если потребуется временно отключить голосование. Поэтому попытаемся разработать систему таким образом, чтобы ее интеграция в уже готовый сайт не составила труда. Для этого необходимо сформировать независимый модуль системы и «включить» его в текст основного сайта там, где это необходимо. Так, к примеру, текст страницы вашего сайта может выглядеть следующим образом:
<head> <title>ASP на блюдечке (Часть - 14) - Разработка системы электронного голосования</title> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> </head> <body marginwidth="0" marginheight="0" leftmargin="0" topmargin="0" > … <!-- #include file="Vindex.asp"--> … </body> </html>
или
<!-- #include file="mainheader.inc"--> <!-- #include file="Vindex.asp"--> <!-- #include file="mainfooter.inc"-->
Как видите, в первом случае директива о включении странички с системой голосования (<!-- #include file="Vindex.asp"-->) указана в необходимом месте. Во втором случае страничка исходного сайта представлена в виде трех последовательно «включаемых» элементов: начала, странички с голосованием и конца. Использование того или иного способа организации структуры странички вашего сайта — дело вкуса и зависит от структуры исходного сайта, а также от степени его сложности.
Главная страничка (файл Vindex.asp)
Прежде всего необходимо разработать страничку, осуществляющую показ вопроса и вариантов ответов на него (здесь и далее мы будем использовать логическую схему «или» для получения ответа пользователей). Для этого сначала напишем пару функций для осуществления соединения с базой данных и отключения от нее:
<%
Sub Connect()
dsn = "DSN=Voter; UID=sa;PWD=;database=Voter"
Set conn = Server.createobject("adodb.connection")
Set rs = Server.createobject("adodb.recordset")
conn.open dsn
End Sub
Sub Close()
rs.close
set rs=nothing
conn.close
set conn=nothing
End Sub
%>
Далее нам потребуется функция извлечения ответов на данный вопрос. Она будет служить для выборки соответствующих ответов с последующим формированием элементов интерфейса пользовательской формы на их основе:
<% Sub FindAns(QID) call connect() sql="SELECT id, ansdesc FROM VAnswers WHERE QuestionID = " & QID & " ORDER BY id" rs.open sql,conn End Sub %>
Теперь установим опции «предзагрузки» пяти изображений, соответствующих пяти возможным вариантам ответов пользователей, которые будут служить для графической интерпретации ответов пользователей (изображения подготовим заранее).
<html> <head> <script> img1 = new Image(); img1.src = "images/Voter/char1.gif"; img2 = new Image(); img2.src ="images/Voter/char2.gif"; img3 = new Image(); img3.src = "images/Voter/char3.gif"; img4 = new Image(); img4.src = "images/Voter/char4.gif"; img5 = new Image(); img5.src = "images/Voter/char5.gif"; …
Определим функцию, которая будет перемещать пользователя на страничку просмотра результатов голосования, причем передадим ей в качестве параметра action значение view:
…
function gotoResults()
{
location.href="Voter.asp?action=view"
}
</script>
<title>
</title>
</head>
…
Далее создадим главную форму для пользовательского ввода, определим скрип-реакцию на нее и при этом передадим ей в качестве параметра action значение vote:
… <body> <form action="Voter.asp?action=vote" method="post"> <table border=0 border=0 cellpadding="0" cellspacing="0"> <tr> <td colspan=2> …
Теперь извлечем максимальное значение ключевого поля ID из таблицы вопросов, с тем чтобы получить предел генерации случайных чисел, которым мы будем руководствоваться для выработки псевдослучайного значения:
…
<%
Dim sSQL, Sql, Que, Rs, Rs1, Conn, Dsn, LastID, RndValue, I
Call Connect()
Sql = "SELECT MAX(ID) AS LastID FROM VQuestions"
Rs.open Sql, Conn
LastID = Rs("LastID")
Call Close()
…
Затем сгенерируем случайное значение в пределах от 1 до полученного максимального значения:
… RndValue = Int(LastID * Rnd + 1) …
И выберем из таблицы соответствующий вопрос:
…
Call Connect()
Sql = "select que from VQuestions where id = " & CStr(RndValue)
Rs.open Sql, Conn
que = rs("que")
Call Close()
Session ("QuestionID") = RndValue
%>
…
Покажем вопрос пользователю, извлечем (с помощью вышеупомянутой функции) значения его ответов и построим форму для регистрации ответа пользователя. Для этого в цикле будем формировать тег вида <input type=radio name="poll" value="Ответ">:
…
<b><font size="-2" color="black" face="verdana,arial,sans-serif">
Примите участие в нашем голосовании, ответьте на вопрос:<br>
<%= que %>
</font>
</b>
</tr></td>
</table>
<table border=0 border=0 cellpadding="0" cellspacing="0">
<tr>
<%
Call FindAns(RndValue)
I = 1
Do while not rs.eof
%>
<td>
<input type=radio name="poll" value='<%= rs("id") %>'
<% If I = 1 Then Response.Write "Checked"%> >
<i><font size="-3" color="black" face="verdana,arial,sans-serif">
<%=rs("ansdesc") %>
</font></i></td>
<%
I = I + 1
rs.movenext
Loop
call close()
%>
</tr>
<tr><td colspan=2>
<input type="hidden" name="quet" value='<%=que%>'>
<input type="Submit" name="submit" value="Голосовать" Style="font: 7pt 'Verdana'; Width: 65; Height: 18">
<input type="button" value="Результаты" onclick="gotoResults()" Style="font: 7pt 'Verdana'; Width: 68; Height: 18">
</td>
</tr>
</table>
</form>
</body>
</html>
Обработка результатов голосования (файл Voter.asp)
Для того чтобы результат формировался в той же страничке нашего основного сайта, можно по аналогии с вышеизложенной структурой «облечь» страничку обработки результатов голосования во «включения» файлов подстраничек заголовка вначале и концевика в конце соответственно:
<!-- #include file="mainheader.inc"-->
<%
dim dsn,conn,sql,rs
dim useraction,ansid,sql1
dim ansdesc,newtotal,total,iTotal,t,ImageWidth
dim sql_statement
dim ors,rs2,ans
dim final_total
dim ansimage
dim votetwice,already,msg,ansPercent
Sub Connect()
dsn = "DSN=Voter; UID=sa;PWD=;database=Voter"
Set conn=server.createobject("adodb.connection")
Set rs=server.createobject("adodb.recordset")
conn.open dsn
End Sub
Sub Close()
rs.close
set rs = nothing
conn.close
set conn = nothing
End Sub
…
Далее выясним, «каким путем» пользователь попал на данную страничку. Здесь возможны два значения: vote — пользователь проголосовал, и view — пользователь уже голосовал и необходимо показать ему результаты голосования:
…
useraction = request("action")
Select Case useraction
case "vote"
response.write request.form("quet") & "<br><br>"
…
Посредством булевой переменной voteTwice можно управлять процессом голосования. В частности, установив ее значение в false, можно разрешить пользователям голосовать свободно и независимо от того, голосовал данный пользователь ранее или нет. В противном случае система не будет позволять одному и тому же пользователю голосовать повторно.
В случае недопустимого повторного голосования переадресуем пользователя на ту же страничку (замкнем страничку на самой себе) с параметром action, равным view, и с дополнительным параметром, свидетельствующим об ошибке msg=1:
…
voteTwice = false
Select Case voteTwice
Case true
If Request.Cookies("poll_1")="" Then
Response.Cookies("poll_1")="already"
Response.Cookies("poll_1").Expires = Date + 365
Else
Response.Redirect "Voter.asp?action=view&msg=1"
End If
End Select
…
Далее прочитаем ответ пользователя и обновим общее количество ответов на данный вопрос в соответствии с выбранным пользователем вариантом:
…
ansid = Request("poll")
Call Connect()
sql = "SELECT * FROM VAnswers WHERE id = " & ansid
rs.open sql,conn
total = rs("total")
total = total + 1
sql1 = "UPDATE VAnswers SET total = " & total & " WHERE id = " & ansid
conn.execute(sql1)
rs.close
set rs = nothing
%>
…
Включим подстраничку показа результатов голосования:
… <!--#include file="VShowRes.asp"--> <% case "view" …
Обработаем параметр msg и в случае ошибки выдадим предупреждение пользователю о недопустимости повторного голосования:
…
msg = request("msg")
If msg <> "" Then
Response.Write "<font size='-2' color='red' face='verdana,arial,sans-serif'>"
Response.Write "<br><br><b>Повторное голосование недопустимо!</b></font><br><br>"
End If
Call Connect()
%>
<!--#include file="VShowRes.asp"-->
<%
conn.close
set conn = nothing
end select
%>
<!-- #include file="mainfooter.inc"-->
Как видите, процесс проверки повторного голосования пользователей довольно прост. Для этого используется механизм cookies («ключиков»).
Просмотр результатов голосования (файл VShowRes.asp)
Нам осталось подготовить страничку, формирующую результаты голосования в графической форме. Для этого сначала вычислим сумму всех количеств данных ответов на один и тот же вопрос (идентификатор вопроса будем читать из сессионной переменной):
…
<%
sql_statement = "SELECT SUM(total) FROM VAnswers WHERE QuestionID = " & Session ("QuestionID")
Set oRs = Server.CreateObject("ADODB.recordset")
oRs.Open sql_statement,Conn
final_total = oRs(0).value
ors.close
set ors = nothing
…
А теперь выберем все варианты ответов на данный вопрос и покажем их пользователю, предварительно задав ширину картинок со столбиками соответствующих ответов и сформировав процентное отношение ответов к их общему числу для каждого их варианта:
…
sql = "SELECT * FROM VAnswers WHERE QuestionID = " & Session ("QuestionID") & " ORDER BY id"
set Rs2 = conn.execute(sql)
Response.Write "<b><font size='-2' color='black' face='verdana,arial,sans-serif'>"
Response.Write "Результаты голосования</font></b><br>"
Response.Write "<table border=1 cellspacing='0'>"
t = 1
Do While Not rs2.eof
ans = rs2("total")
If ans = 0 Then
ansPercent = "0%"
Else
ansPercent = formatpercent(ans/final_total)
End If
ansImage = replace(ansPercent,"%","")
ansImage = ansImage*2
ansdesc = rs2("ansdesc")
Response.Write "<tr><td>"
Response.Write "<i><font size='-3' color='black' face='verdana,arial,sans-serif'>"
Response.Write ansdesc & "</font></i></td><td>"
Response.Write "<i><font size='-3' color='black' face='verdana,arial,sans-serif'>"
Response.Write ansPercent & "</font></i>"
Response.Write "</td><td>"
Response.Write "<img src = images/voter/char"& t &".gif width="& ansImage &" height=5></tr></td>"
rs2.movenext
t = t + 1
Loop
Response.Write "</tr></td><tr><td colspan=3>"
Response.Write "<b><font size='-2' color='black' face='verdana,arial,sans-serif'>"
Response.Write "Всего голосовало: " & final_total & " человек</table>"
Response.Write "</font></b>"
%>
Заключение
В заключение необходимо указать ряд упрощений, которые мы допустили. Во-первых, как читатель наверняка заметил, система разработана таким образом, что воспринимает не более пяти вариантов ответов на один и тот же вопрос. Мы не стали подробно останавливаться на механизме «ключиков», который использовался для регистрации уже ответившего пользователя. И еще, мы рассмотрели лишь один (частный) случай голосования по схеме «или» и опустили рассмотрение системы электронного голосования по схеме «и». Все эти и другие вопросы усовершенствования системы электронного голосования мы рассмотрим в одной из последующих публикаций настоящей статьи.
Однако разработанная нами система вполне приемлема для использования, а благодаря модульности ее реализации и описанному в статье подходу к ее внедрению в уже существующие сайты. Ее можно применить в качестве системы электронного голосования на сайте практически любой степени сложности.
С автором статьи можно связаться по адресу: rouben@iname.com.
КомпьютерПресс 10'2001








