1
OWC简介
OWC(Office Web Components)是微软公司随Office提供的绘图组件,使用它能够绘制大部分的图形。OWC是随着Microsoft
Office 2003软件一起安装的一组ActiveX组件。使用OWC组件就必须保证本机上已安装了Microsoft
Office 2003软件。OWC组件可以很方便地在浏览器中或在传统的编程环境中进行数据分析,例如电子表格、图表、数据透视表等。在使用OWC组件之前还需要添加引用using
Microsoft.Office.Interop.Owc11。
2 数据库设计
本系统采用Microsoft SQL Server 2008作为系统的DBMS,利用存储过程,能实现较快的执行速度,减少网络流量,提高系统性能。多选题和填空题表结构与单选题基本差不多,主要表的设计和存储过程如下:
2.1 数据库表的设计
1) 学生信息表(id,学号,班级,姓名,IP地址,场次);2) 单选题题库表(id,题号,题目内容,选项A,选项B,选项C,选项D,标准答案);3)
单选题正式考试表(id,题号,场次);4) 单选题考生答案表(id,题号,学号,考生答案,场次,时间);5)
填空题成绩表(id,学号,填空题得分)。
2.2 数据库存储过程
根据传入的考试场次和题型参数,查询出当前场次的考题。
CREATE PROCEDURE [dbo].[Proc_TestContent]
(@cc [int],
@Type [varchar](10))
AS
begin
declare @sql nvarchar(100)
if @Type='s'//单选题danxttkb(单选题题库表)danxtzsksb(单选题正式考试表)
cc(场次)
begin
set @sql='select tmnr,xxa,xxb,xxc,xxd,th from danxttkb,danxtzsksb
where danxttkb.th=danxtzsksb.th and [cc]='+Cast(@cc
AS varchar(10))
exec sp_executesql @sql
end
else if @Type='m'//多选题
begin
set @sql='select tmnr,xxa,xxb,xxc,xxd,th from duoxttkb,duoxtzsksb
where duoxttkb.th=duoxtzsksb.th and [cc]='+Cast(@cc
AS varchar(10))
exec sp_executesql @sql
end
else
begin //填空题
set @sql='select tmnr,th from tktkb,tktzsksb
where tktkb.th=tktzsksb.th and [cc]='+Cast(@cc AS
varchar(10))
exec sp_executesql @sql
end
end
GO
3 前台考试系统功能
这个模块主要是学生在考试时使用,是考试系统的核心部分,也是程序设计的重点,主要解决如何满足大量学生同时操作时的并发问题,学生首先需登陆进行身份认证,认证通过后开始考试。单选题、多选题、填空题答案分别进行提交,提交之后系统将把考生答案传送到数据库中进行保存。
1) 登陆考试系统:在登陆界面输入学号和姓名用来验证考生信息,如果验证通过,并且查询考生计算机的IP地址和考试场次不存在,也就是第一次登陆时,系统会记录考生计算机的IP地址和考试场次。如果考试场次大于零则开始当前场次的考试,等于零则没开始考试。
考生可以二次登陆该系统,登陆时验证考生信息和所在计算机的IP地址还有当前考试场次,如果与数据库中存储的第一次登陆信息一致则验证通过,利用其它考生信息登陆会验证失败,也就是说,在一个考试场次,一台计算机上,无法用第二个考生信息登陆系统,这样可以保证不会替别的考生答题。计算机故障时,考生可以用备用机继续考试。
2) 单选题测试:从数据库单选题正式考试表中读出当前考试场次的试题,并在单选题页面中随机显示,考生保存试卷后,将答案、场次、学号、题号保存到单选题答案表中。
3) 多选题测试:从数据库多选题正式考试表中读出当前考试场次的试题,并在多选题页面中随机显示,考生保存试卷后,将答案、场次、学号、题号保存到多选题答案表中。
4) 填空题测试:从数据库填空题正式考试表中读出当前考试场次的试题,并在填空题页面中随机显示,考生保存试卷后,将答案、场次、学号、题号保存到填空题答案表中。
5) 成绩查询:为了使考生考试后可以及时了解自已的考试分数,方便考生操作,所以本功能集成在登陆界面进行查询,考生可以在局域网环境或INTERNET环境查询成绩。
4 后台管理系统功能
4.1 登陆管理系统
对输入的用户名、密码、随机验证码、验证通过后即可进入管理系统,对各项系统功能能进行操作。
4.2 考试参数设置
此项功能主要完成对当前考试场次、是否允许学生查询成绩、考试功能关闭、单选题分值、多选题分值、填空题分值等的设置。
4.3 学生信息管理
根据学号、姓名、班级进行查询,完成对学生信息的添加、修改、删除操作。
4.4 用户管理
完成对后台管理用户的添加、修改、删除、查询、密码修改操作
4.5 试卷出题与维护
1)人工出题:通过GridView控件把单选题、多先题或填空题信息显示出来,然后选择CheckBox复选框,将复选框被选中的那行试题信息,插入到正式考试表中,完成出题。
2)随机出题:利用SQL语句和newid()数据库函数,根据输入的考题数量和场次,从单选题、多选题或填空题题库表中,随机读取试题,然后插入到正式考试表中,完成出题。
3)试卷维护:查看或删除生成的各个场次的单选题、多先题、填空题正式考题。
4.6 试卷评阅
1)计算机自动评分
在提交单选题或多选题时,将答案保存在单选题或多选题答案表中,利用视图功能自动评分。以单选题为例如下:
①建立单选题视图,查询出考生学号、单选题答案、试题标准答案。
②建立单选题判断视图,并添加①建立的视图,在考生答案行的筛选器栏输入answer=bzda(answer为考生答案字段,bzda为题库标准答案字段)
③建立单选题得分视图,并添加②建立的视图,在学号所在行的分组依据栏选择Count,在别名栏中输入一个别名作为查询结果集的字段,这样将视图作为一个表进行查询即可得出考生答对的题数。在显示考生成绩时乘以单选题分值即可得出单选题总分。
2)计算机辅助评分
计算机对主观试题可以准确的评分,但对客观试题可以把考生答案和题库标准答案显示出来,通过选择复选框来评分,提交时计算出被选中的复选框个数即可得出该考生答对的题数。
4.7 题库管理
题库管理主要完成对单选题、多选题、填空题题库的添加、修改、删除、将EXCEL文件存储的题库导入到SQL
SERVER数据库的题库表中。
4.8 成绩查询统计
主要查询每个学生的成绩,可以按班级查询,也可以按学号、姓名查询。利用OWC(Office Web Components)组件绘制柱型图,统计班级的总人数、班级的平均分、及格率等。通过扩展功能,也可以计算出正态分布所需的数据。如图1。
5 系统实现的关键技术
5.1 学生登陆模块
cip = Request.UserHostAddress;
string tempxh;
if (con.State.Equals(ConnectionState.Closed))
{con.Open();}
SqlCommand cmd = new SqlCommand("select xh,xm
from stuinfo where xh='" + TextBox1.Text + "'
and xm='" + TextBox2.Text+"'", con);
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataSet dataset = new DataSet();
adapter.Fill(dataset);
if (dataset.Tables[0].Rows.Count > 0)//查询是否存在这个学生
{ SqlCommand cmd2 = new SqlCommand("select cc
from cc", con);
SqlDataAdapter adapter2 = new SqlDataAdapter(cmd2);
DataSet ds = new DataSet();
adapter2.Fill(ds);
if (int.Parse(ds.Tables[0].Rows[0]["cc"].ToString())
> 0)//考试场次大于0则开始考试小于0则没开始考试
{ Session["xh"] = TextBox1.Text;
Session["xm"] = TextBox2.Text.Trim();
Session["cc"] = ds.Tables[0].Rows[0]["cc"].ToString();
cc = int.Parse(ds.Tables[0].Rows[0]["cc"].ToString());
SqlCommand cmd3 = new SqlCommand("select xh from
stuinfo where ip='" + cip + "' and cc="
+ cc, con);
SqlDataAdapter adapter3 = new SqlDataAdapter(cmd3);
DataSet ds3 = new DataSet();
adapter3.Fill(ds3);
if (ds3.Tables[0].Rows.Count > 0)//在当前考试场次中已存在登陆电脑的IP地址
{ tempxh = ds3.Tables[0].Rows[0]["xh"].ToString().Trim();
if (tempxh == TextBox1.Text)
{ //身份验证成功转向考试页面
Response.Redirect("Main.aspx");}
else
{ //此用户用别人的学号登陆或在当前考试场次本机已有考生登陆过
Label1.Text = "请不要用别人的学号登陆";}}
else
{ //此用户第一次登陆考试系统,记录登陆电脑的IP地址
SqlCommand cmd4 = new SqlCommand("update stuinfo
set ip='" + cip + "',cc=" + cc + "
where xh='" + TextBox1.Text + "'", con);
cmd4.ExecuteNonQuery();
Response.Redirect("Main.aspx");}}
else
{Label1.Text = "考试没开始";}}
else
{Label1.Text = "学号或姓名不正确";}
if (con.State.Equals(ConnectionState.Open))
{con.Close();}
5.2 EXCEL文件存储的单选题题库导入到SQL SERVER单选题题库表中
string XlsString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=" + FileUpload1.PostedFile.FileName + ";Extended
Properties=Excel 8.0;";
OleDbConnection cnnxls = new OleDbConnection(XlsString);
OleDbDataAdapter XlsDa = new OleDbDataAdapter("select*from
[Sheet1$]",cnnxls);
DataSet XlsDs = new DataSet();
XlsDa.Fill(XlsDs);
if (XlsDs.Tables[0].Rows.Count > 0)
{ string strSql = "";
string CnnString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
SqlConnection conn = new SqlConnection(CnnString);
conn.Open();
SqlCommand Cmd = null;
try
{ for (int i = 0; i < XlsDs.Tables[0].Rows.Count;
i++)
{ strSql = "insert into danxttkb(tmnr,xx1,xx2,xx3,xx4,bzda)
values ('";
strSql += XlsDs.Tables[0].Rows[i].ItemArray[0].ToString()
+ "','";
strSql += XlsDs.Tables[0].Rows[i].ItemArray[1].ToString()
+ "','";
strSql += XlsDs.Tables[0].Rows[i].ItemArray[2].ToString()
+ "','";
strSql += XlsDs.Tables[0].Rows[i].ItemArray[3].ToString()
+ "','";
strSql += XlsDs.Tables[0].Rows[i].ItemArray[4].ToString()
+ "','";
strSql += XlsDs.Tables[0].Rows[i].ItemArray[5].ToString()
+ "')";
Cmd = new SqlCommand(strSql, conn);
Cmd.ExecuteNonQuery();}
Label1.Text = " ";}
catch
{Label1.Text = " ";}
finally
{conn.Close();}}
5.3 OWC组件绘制柱形图
//保存各分数段名称
string[] monNum = new string[10];
//保存各分数段人数
string[] monCount = new string[10];
int[] stucount=new int[10];
float jgrs = 0, pjf = 0, zf = 0, jgl;
int zrs=0;//jgrs(及格人数) pjf(平均分) zf(总分) jgl(及格率) zrs(总人数)
ds存储的是班级每个学生的总分
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{for (int j = 0; j < ds.Tables[0].Columns.Count;
j++)
{zf+=Convert.ToInt16(ds.Tables[0].Rows[i][j]);
if (Convert.ToInt16(ds.Tables[0].Rows[i][j]) >=
90)
{stucount[9] += 1; jgrs += 1;}
else
{if (Convert.ToInt16(ds.Tables[0].Rows[i][j]) >=
80)
{stucount[8] += 1; jgrs += 1;}
else
{if (Convert.ToInt16(ds.Tables[0].Rows[i][j]) >=
70)
{stucount[7] += 1; jgrs += 1;}
else
{if (Convert.ToInt16(ds.Tables[0].Rows[i][j]) >=
60)
{stucount[6] += 1; jgrs += 1;}
else
{if (Convert.ToInt16(ds.Tables[0].Rows[i][j]) >=
50)
{stucount[5] += 1;}
else
{if (Convert.ToInt16(ds.Tables[0].Rows[i][j]) >=
40)
{stucount[4] += 1;}
else
{if (Convert.ToInt16(ds.Tables[0].Rows[i][j]) >=
30)
{stucount[3] += 1;}
else
{if (Convert.ToInt16(ds.Tables[0].Rows[i][j]) >=
20)
{stucount[2] += 1;}
else
{if (Convert.ToInt16(ds.Tables[0].Rows[i][j]) >=
10)
{stucount[1] += 1;}
else
{stucount[0] += 1; }}}}}}}}}}}
zrs = ds.Tables[0].Rows.Count;
pjf = zf / zrs;
jgl = jgrs / zrs * 100;
//使用for循环赋值
for (int i = 0; i < 10; i++)
{monNum[i] = Convert.ToString(i + 1);
monCount[i] = (stucount[i]).ToString();}
//保存各分数段名称
string strXdata = string.Empty;
strXdata += "0-10" + "\t";
strXdata += "10-20" + "\t";
strXdata += "20-30" + "\t";
strXdata += "30-40" + "\t";
strXdata += "40-50" + "\t";
strXdata += "50-60" + "\t";
strXdata += "60-70" + "\t";
strXdata += "70-80" + "\t";
strXdata += "80-90" + "\t";
strXdata += "90-100" + "\t";
//保存各分数段人数
string strYdata = string.Empty;
foreach (string strValue in monCount)
{strYdata += strValue + "\t";}
ChartSpace laySpace = new ChartSpaceClass();//创建图表工作区
ChChart InsertChart = laySpace.Charts.Add(0); //在图表工作区中添加一个图表
InsertChart.Type = ChartChartTypeEnum.chChartTypeColumnClustered;//设置图表类型为柱型图
InsertChart.HasTitle = true;//设置图表是否具有标题
//设置标题内容
InsertChart.Title.Caption = DropDownList1.Text.Trim()
+ "班各分数段人数";
InsertChart.Axes[0].HasTitle = true;
InsertChart.Axes[0].Title.Caption = "分数段"+"
总人数:"+zrs+"平均分:"+CRound(pjf,2)+"及格率:"+CRound(jgl,2)+"%";
InsertChart.Axes[1].HasTitle = true;
InsertChart.Axes[1].Title.Caption = "人数";
InsertChart.Axes[1].Scaling.Maximum = 30;
InsertChart.SeriesCollection.Add(0);//指定新图表的位置
//设置分类的值
InsertChart.SeriesCollection[0].SetData(ChartDimensionsEnum.chDimCategories,
(int)ChartSpecialDataSourcesEnum.chDataLiteral, strXdata);
//设置图表的值
InsertChart.SeriesCollection[0].SetData(ChartDimensionsEnum.chDimValues,
(int)ChartSpecialDataSourcesEnum.chDataLiteral, strYdata);
//显示图表中所有标志
ChDataLabels dls = InsertChart.SeriesCollection[0].DataLabelsCollection.Add();
dls.Font.Size = 10;//设置标志大小
dls.Font.Color = "red";//设置标志颜色
dls.Font.Bold = true; //设置标志为粗体
//字符串变量用来保存生成图片的路径
string strAbsolutePath = Server.MapPath(".")
+ "\\"+DropDownList1.Text.Trim()+".gif";
//将图表保存为图片文件
laySpace.ExportPicture(strAbsolutePath, "GIF",
600, 350);
strAbsolutePath = DropDownList1.Text.Trim() + ".gif";//创建图像标记
string strImageTag = "";
//将图像显示在页面中
this.PlaceHolder1.Controls.Add(new LiteralControl(strImageTag));
6 结束语
通过本文的设计与实现,可以满足计算机应用基础课的考试,系统运行稳定,性能良好。
本文只实现了单选题、多选题、填空题的数据库设计与程序实现,通过扩展还可以实现问答题和操作题的考试。问答题与填空题的实现差不多,只是在评分时直接在问答题旁边的文本框中输入得分即可。操作题有两种实现方法,一种是将WORD、EXCEL、图片等经过压缩的资源文件下载到本地,答题完成后,再用FileUpload控件以压缩文件的形式上传到服务器上。另一种方法是用WinForm编程实现,首先需要在服务器上安装FTP服务器,用以接收WinForm上传到服务器的文件,然后用WinForm形式编程实现,将FTP服务器的考试资源文件下载到本地,答完题后再上传到FTP服务器上,上传时以学号和姓名命名文件,这种方法性能较好,对服务器的资源占用较少。
|