汪亞菲
(湖南工業(yè)職業(yè)技術學院,湖南長沙,410208)
在線投票系統(tǒng)應用較普遍,難點在于怎樣避免重復投票和按照要求在指定日期及指定范圍內(nèi)進行投票的方法。
以asp和asp.net平臺為例,在常見的設計中,有一些應用Request對象的Cookies集合實現(xiàn)投票,可以限制多次投票;也有一些應用Request對象的Serve Variabrles集合獲取IP地址,通過查詢IP地址的方法實現(xiàn)一個IP在指定日期內(nèi)進行投票的方法。
本人在制作企業(yè)內(nèi)部網(wǎng)站的評選月度優(yōu)秀員工在線投票模塊設計中,要求員工根據(jù)每月確定的候選人在線進行差額投票評選優(yōu)秀員工,每月至多投票一次,且不能重復給同一人投票。上述利用Request對象的方法不能滿足設計要求,本人在Microsoft Visual Studio2010平臺下使用數(shù)據(jù)庫和vc#等組件編程完成了設計,網(wǎng)站及評選優(yōu)秀員工的模塊工作狀況良好。下面將介紹本模塊的設計和制作方法。
本系統(tǒng)數(shù)據(jù)庫名稱為db_OA.mdf,事務日志文件是db_OA_log.ldf。與評優(yōu)投票程序設計相關的數(shù)據(jù)表有系統(tǒng)用戶表sysUser和評優(yōu)表yx,具體內(nèi)容如下:
1.1.1 系統(tǒng)用戶表sys User
用于儲存具有登錄權用戶的信息及每月評優(yōu)投票日期。表結構定義如表1-1所示。
表1-1 系統(tǒng)用戶表sys User
1.1.2 評優(yōu)表yx
用于儲存月評優(yōu)秀員工侯選人信息。表結構定義如表1-2所示。
表1-2 評優(yōu)表yx
本網(wǎng)站將數(shù)據(jù)庫保存在網(wǎng)站的App_Data 文件夾中。其路徑存儲在配置文件Web.confi 的(connection Strings) 配置節(jié)中,內(nèi)容如下:
數(shù)據(jù)庫連接串定義在一個常量conStr 中,其值為:數(shù)據(jù)源來自本地Sql Server 2005 EXPRESS 數(shù)據(jù)庫服務器;數(shù)據(jù)庫保存在“|Data Directory|”,即默認的文件夾App_Data 中,數(shù)據(jù)庫名為db_OA.MDF,登錄用戶和密碼使用系統(tǒng)默認值,使用系統(tǒng)的“System.Data.Sql Client”命名空間。此時,數(shù)據(jù)庫路徑在網(wǎng)站已經(jīng)確定。
網(wǎng)站采用三層開發(fā)架構。將網(wǎng)站需經(jīng)常使用的代碼段定義為方法,保存在公共類文件Base Class.cs文件中,文件存放在系統(tǒng)文件夾App_Code中。Base Class.cs文件中定義了三個方法,前一個方法是調(diào)用JavaScript的alert方法彈出window風格消息框;后二個方法涉及有關ADO.NET訪問數(shù)據(jù)庫的操作。
1.3.1 Message Box方法:
#region彈出消息框
public string Message Box(string Txt Message)
{
string str;
str=("");
return str;
}
#endregion
定義一個全局字符串型的方法MessageBox,調(diào)用時的形參名為字符串類型的Txt Message,字符串變量str中包含使用JavaScript的alert方法的代碼,返回時在頁面彈出window風格消息框。定義方法后,在程序中可隨時調(diào)用。
1.3.2 Exec SELECTE方法:
定義一個全局整數(shù)型方法Exec SELECTE,形參名為字符串類型的sQuery String,用于執(zhí)行sQuery String表示的sql查詢語句,其中Command對象采用Execute Scalar方法,執(zhí)行單一結果的查詢。返回結果中第一行的第一列,將該列值轉換為一個int類型的值,用以判斷操作是否成功。
#region 執(zhí)行SQL 語句,select 讀取單一查詢結果,操作成功返回>0
public int ExecSELECTE(string sQueryString)
{
Sql Connection con = new Sql Connection(Configuration Manager.
Connection Strings["con Str"] .Connection String); // 使用new 運算符用來創(chuàng)建連接對象con
con.Open();
SqlCommand cmd=new Sql Command(sQuery String,con);
int Num=(int)cmd.Execute Scalar();//Execute Scalar方法
con.Close();
return Num;//返回第一行的第一列值}
#endregion
1.3.3 GetDataSet方法:
定義一個全局系統(tǒng)數(shù)據(jù)集類型(System.Data.DataSet)的方法GetDataSet,調(diào)用時有兩個字符串類型實參,一個是sQuery String,為輸入的SQL語句;另一個是Table Name,為輸入的數(shù)據(jù)表名稱。返回值為數(shù)據(jù)集類型,即返回一個表。
#region:帶二個參數(shù)執(zhí)行SQL語句,操作成功返回一個表
public System.Data.Data Set Get DataSet(strings Query String,string Table Name)
{
Sql Connection con=new Sql Connection(Configuration Manager.
Connection Strings["con Str"] .Connection String);//使用new運算符用來創(chuàng)建連接對象con
con.Open();
Sql Data Adapter db Adapter=new Sql Data Adapter(s Query String,con);//創(chuàng)建并實例化適配器
Data Setdataset=new Data Set();//創(chuàng)建數(shù)據(jù)集對象dataset
db Adapter.Fill(dataset,Table Name);//Fill填充
con.Close();
return dataset;//操作成功返回一個表
}
#endregion
在網(wǎng)頁中直接調(diào)用Base Class.cs文件所定義的方法的語句為:
Base Classbc=new Base Class();
語句使用new運算符創(chuàng)建類Base Class的對象bc,并調(diào)用Base Class()對該對象進行初始化,這表示對象bc可調(diào)用公共類文件BaseClass.cs中定義的所有方法。
網(wǎng)站頁面為母版頁結構,評選優(yōu)秀員工前臺頁yx-vote.aspx為一個內(nèi)容頁,使用asp.net的數(shù)據(jù)列表控件DataList,頁面截圖如圖2-1所示。在每個候選人的選項欄中設置一個投票按鈕,投票時若點擊某個候選人選項欄的投票按鈕,則觸發(fā)Data List控件的Edit Command事件,將執(zhí)行后臺設置的按鈕點擊事件代碼。
圖2-1 評優(yōu)投票頁yx-vote.aspx截圖
2.2.1 啟動評優(yōu)投票頁面時,系統(tǒng)打開用戶表sys User,查詢該用戶是否有本月的投票記錄,如果有則不能再投票,給出提示并返回上級頁面。
2.2.2 若無本月的投票記錄,則首先從評優(yōu)表yx中取出已知的侯選人數(shù),按一定的條件確定優(yōu)秀員工的人數(shù),確定的人數(shù)值也就是本輪投票的次數(shù)。將由員工進行差額不重復投票,評選出本月優(yōu)秀員工。
2.2.3 單擊“投票”按鈕開始投票,系統(tǒng)首先判斷本輪投票是否完成,如果已完成則退出;退出前應在sysUser表寫入當前日期,因為每個用戶每月至多只能進行一次評優(yōu)投票。下次投票時若在sys User表查詢出已有相同月份,表明已投過票,則不能再投票。這樣可有效阻止多次登錄重復投票。
2.2.4 如果本輪投票沒有完成,投票時應確定不重復投票,鼠標點擊某候選人所在行的主鍵值賦給變量str,將變量str與已存在數(shù)組中的str值比較,如果相同則表示重復投票給同一人,本票無效;直到投票選擇侯選人的str與數(shù)組中的str值不相同時,將不重復投票的主鍵值str存入數(shù)組中。
2.2.5 從yx表中找到與數(shù)組元素str相同主鍵所在記錄的票數(shù)字段qty值,賦給變量yxqty,給yxqty加1,然后更新表中投票值。每月投票后,yx表中票數(shù)較多的前幾人即為評選出的本月優(yōu)秀員工。
2.2.6 考慮到用戶可能在投票中途非正常退出,所以投票開始時對數(shù)組和下標清零。
圖2-2 評優(yōu)投票模塊設計流程圖
評優(yōu)投票模塊設計流程圖如圖2-2所示,評優(yōu)投票后臺頁yx-vote.aspx.cs代碼如下:
2.3.1 啟動時自動執(zhí)行開始部分的初始化,然后執(zhí)行Page_Load事件,從sysUser表中查詢用戶是否有本月投票記錄,有則退出評優(yōu)頁面,返回到y(tǒng)x-vote Result.aspx頁面顯示投票結果。
staticinti=0;//定義數(shù)組下標值i,必須為靜態(tài)變量,否則下標值i不遞增
staticintyxcoun=0;//定義yxcoun為優(yōu)秀員工人數(shù)
staticintrencoun;//定義rencoun為優(yōu)秀員工候選人數(shù)
staticint[] homestr=newint[8] ;//定義數(shù)組
Base Classbc=new BaseClass();//對象bc擁有類文件Base Class.cs中定義的所有方法
protectedvoid Page_Load(objectsender,Event Argse)
{
Stringcheckyx=("select*fromsysUserwhere(userName='"+Session["login Name"] .ToString()+"'andDatepart(yyyy,monthyx)='"+DateTime.Now.Year+"'and Datepart(mm,monthyx)='"+Date Time.Now.Month+"')");
intci;
ci=bc.ExecSELECTE(checkyx);//啟動時查詢
if(ci>0)
{
Response.Write(bc.MessageBox("每個用戶每月只能進行一次評優(yōu)投票,你本月已投過票!"));
Response.Write("");//返回
}
2.3.2 在Page_Load事件中引入Page對象屬性Page.IsPost Back,當網(wǎng)頁第一次啟動時,!Page.IsPost Back獲取回傳,即在第一次啟動時執(zhí)行以下初始化頁面操作:
首先從yx表求和,Exec SELECTE方法返回結果中第一行的第一列值,即為求和得到的優(yōu)秀員工的候選人數(shù)rencoun,然后按60%比例自動計算優(yōu)秀員工人數(shù)yxcoun,考慮到上一個用戶可能在投票中途非正常退出,所以投票開始時對數(shù)組和下標清零;
最后綁定DataList1控件并顯示候選人名單,啟動頁面如圖2-1所示:
if(!IsPost Back)
{
rencoun=bc.Exec SELECTE("select COUNT(*)fromyx");//返回結果中第一行的第一列,返回表的總行數(shù)即候選人數(shù)給變量
yxcoun=Convert.ToInt16(rencoun*0.60);//按60%比例選優(yōu)秀員工!
Response.Write("每個用戶每月只能進行一次評優(yōu)投票。共有"+rencoun.ToString()+"名候選人,可投票選出"+yxcoun.To String()+"名優(yōu)秀員工!"+"
");
for(intj=0;j<=yxcoun;j++)homestr[j] =0;//本次投票前數(shù)組清零
i=0;//投票前下標i清零(清零放在回傳中,只執(zhí)行一次;放在回傳外則每次清零)
}
Data List1.Data Source=bc.Get DataSet("select*fromyx","yx");
Data List1.Data Key Field="id";
Data List1.Data Bind();//顯示并綁定DataList1控件
}//Page_Load結束
2.4.1 單擊"投票 "按鈕,觸發(fā)DataList控件的EditCommand事件。首先判斷是否已投完票,投完票則在sysUser表寫入當前日期,以便下次投票時查詢是否已投過票,然后返回到y(tǒng)x-voteResult.aspx頁面顯示投票結果。投票時應確定不重復投票,投票結果存入yx表。代碼如下:
protectedvoid DataList1_Edit Command1(objectsource,DataList Command EventArgse)
{
If(i>=yxcoun)//首先判斷是否已投完票,其中i是投票次數(shù),yxcoun是優(yōu)秀員工數(shù)
{
for(intj=0;j<=yxcoun;j++)homestr[j] =0;//投票后數(shù)組清零
i=0;//i清0
Response.Write(bc.Message Box(“投票選出本月“+yxcoun+”名優(yōu)秀員工!,已完成投票。謝謝!”));
bc.Exec SELECTE("updatesys Usersetmonthyx='"+DateTime.Now+"'whereuserName='"+Session["loginName"] .ToString()+"'");//在sysUser表寫入當前日期
Response.Write("");//返回
}
//將投票的主鍵值(查sysUser表可知,即id號)預置到變量str中
intyxqty=0;//定義變量yxqty存放投票數(shù)
intstr=0;//定義變量str存放所選主鍵值
str=(int)Data List1.DataKeys[e.Item.Item Index] ;//鼠標點擊行主鍵值,即id賦給str
//將不重復投票的主鍵值str(即id號)存入數(shù)組中
foreach (int aa in homestr)
{
if(aa!=0)Response.Write("已投票="+aa.ToString()+"號,");//顯示投票信息,如圖2-3所示
圖2-3 投票正在進行中
圖2-4 阻止重復投票
if(aa==str)//新選行主鍵str與己存在數(shù)組中主鍵aa比較,相等則為重復
{
Response.Write("["+aa.ToString()+"="+str.ToString()+",重復投票!] ");//如圖2-4所示
Response.Write(bc.MessageBox1("不能重復投票給同一人。謝謝!!"));//如圖2-4所示
str=-1; //重復選擇的主鍵str無效,以-1為標記
i--; //下標減1
break;
}}
if(str!=-1)homestr[i] =str;//將不重復投票的主鍵str存入數(shù)組元素中
Response.Write("本次是第["+(i+1)+"] 票投票="+homestr[i] .ToString()+"號?
");//顯示投票信息,如圖2-3所示
2.4.2 最后利用Data Set行對象Data Row從yx表中找到主鍵值str所在行的投票數(shù)字段qty值并賦給變量yxqty,給yxqty加1,然后更新表中投票數(shù)字段值,步驟如下:
2.4.2.1 首先從表中找到原投票數(shù)qty并賦給變量yxqty。
Data Setds=bc.GetDataSet("select*fromyxwhereid='"+str+"'","yx");
Data Row[] row=ds.Tables[0] .Select();
foreach(Data Rowrsinrow)
{
yxqty=Convert.To Int16(rs["qty"] );//將yx表id=str行的qty值賦給變量yxqty
}
yxqty=yxqty+1;//原有票+1
2.4.2.2 將新的yxqty值寫入yx表,更新表中投票數(shù)字段值
intbi;
bi=bc.ExecSELECTE("updateyxsetqty='"+yxqty+"'where id='"+str+"'");
if(bi>0)
{
Response.Write(bc.MessageBox1("第"+(i+1)+"票投票完成?"));//如圖2-3所示
i++;//數(shù)組下標加1
}
}//DataList1_Edit Command1事件結束
后臺制作完畢,投票結果存入yx表的qty字段。網(wǎng)站啟動時,首頁文件Default.aspx將在表yx中找出票數(shù)高的員工為優(yōu)秀員工,然后在前臺的左側顯示優(yōu)秀員工的姓名、照片等資料。
[1] 明日科技.ASP.net2.0開發(fā)技術大全[M] .北京:人民郵電出版社,2008.
[2] 程不功.龍躍進.ASP.NET2.0動態(tài)網(wǎng)站開發(fā)教程[Z] .北京:清華大學出版社,2008.
[3] 祝紅濤.SQL Server2008數(shù)據(jù)庫應用簡明教程[Z] .北京:清華大學出版社,2010.
[4] 沈大林.SQL Server2005案例教程[Z] .北京:中國鐵道出版社,2010.
[5] 汪亞菲.網(wǎng)站建設實例教程[Z] .北京:清華大學出版社,2013.