在线考试系统提供了老师在线批阅试卷的功能。并提供了客观题的自动改卷功能。下面介绍一般的改卷功能是如何实现的。首先还是要把学生的Paper显示给老师。但是老师想看到的试卷和学生看到的试卷肯定是不同的。学生的试卷是不会有标准答案的。老师的试卷为了简单只想显示每个题目的标准答案和学生的答案。我们知道学生的Paper显示是通过将Paper的XML格式转换成html来实现的。老师的当然也是了。用一个Paper显示给老师和学生的视图是不一样的。这也充分的体现了MVC架构在本系统中的应用。我们显示给老师的试卷用到的xslt文件是PaperForTeacher.xsl。显示给学生xslt文件是PaperForStudent.xsl。这样充分说明了应用XML+xslt给系统带来的灵活性。具体代码太长这里就不演示了。请参考源代码。
下面介绍老师改卷功能中浏览器和服务器是如何交互。和在线考试模块一样。我们同样不想老师每改一题就重新为老师生成一次试卷。解决方案还是利用Ajax不过这次用的服务器端相应程序不再是Handler而是web服务。下面给出web服务PaperWebService.asmx的实现代码
{
[ScriptService]
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class PaperWebService : System.Web.Services.WebService
{ [WebMethod]
public void SetScore(long questionId, int score)
{ Question question = new QuestionService().GetById(questionId);
question.Score = score;
question.IsScored = true;
new QuestionService().Update(question);
}
}
}
该服务只有一个方法,方法接收Question对象的id号和得分。并通过QuestionService取得Question对象并设定得分然后将是否批改属性IsScored设为true。下面看看客户端是如何向服务器发送SetScore请求的。因为我们使用了Ajax.net框架所以客户端的Ajax类库可以很好的和服务器端的Web服务整合使用。ExaminationSystem.WebService.PaperWebService.SetScore(questionId,score,OnSucceeded,OnFailed,statusDiv);
代码展示了客户端是如何调用服务器端的Web服务的。一行代码就是完成了一次异步请求并指定了成功调用后的回调函数OnSucceeded,调用失败后的回调函数OnFailed。statusDiv是一个div标签的引用,作为上下文对象提供给上面两个回调函数用于显示信息。因为每一个Question对象都会有一个用来打分的文本框和一个提交打分的按钮。下图4-18是打分页面的显示效果。
图4-18 打分页面
打分的同时还要验证打的分数是否合法。即必须小于分值。这就出现了一个很棘手的问题因为html都是通过xslt转换生成的。又不能将javascript写到xslt文件中。所以只能通过使用外部的js文件来为改卷html页面添加行为。这样符合web开发提倡的内容(html),样式(css),行为(javascript)三者之间的分离。但是如何在外部的js文件中操作html的dom对象呢?这里使用了叫Jquery的javascript类库。Jquery使用了类似css选择器的语法表达式来获取html中的Dom引用,并提供了链式表达式。使用起来非常方便。下面看看如何使用Jquery给页面上的每个打分按钮注册打分事件处理函数。
//绑定打分按钮事件处理函数
function()
{
scoreTextBox=this.previousSibling ;
statusDiv=this.nextSibling;
questionId=scoreTextBox.id;
scoreValue=scoreTextBox.scorevalue;
score=scoreTextBox.value;
if(score>scoreValue)
{
alert("得分不能超过分值!");
scoreTextBox.value=0;
}
else
{
ExaminationSystem.WebService.PaperWebService.SetScore(
questionId,score,OnSucceeded,OnFailed,statusDiv);
}
}
);
}
function OnSucceeded(result,context,methodName)
{
alert("打分成功!");
$(context).text("已批改").css("color","green");
}
function OnFailed(error,context,methodName)
{
alert("打分失败!");
}
$(":button")
表示获取所有的按钮的引用
$(":button").click()
接着是为所以的按钮添加click事件处理函数。
$(":button").click(function() {….})
匿名处理函数可以直接作为参数传递给click事件。
在处理函数中this引用的就是触发click事件的按钮。
scoreTextBox=this.previousSibling ;
因为文本框在按钮的前面。所以上面表达式就获得了触发click事件按钮前面文本框的引用。因为我们将每个题的分值作为一个属性添加到了文本框标签内。所以当用户输入了得分时候我们能从同一个文本框中得到分值和得分。
questionId=scoreTextBox.id;
scoreValue=scoreTextBox.scorevalue;
score=scoreTextBox.value;
<input type=”text” id=”1” scorevalue=”2” />
上面代码标签部分是每个试题生成的文本框的标签。这里Question的id号是1,分值是2。scorevalue作为自定义的属性来记录分值。打过分的题目会用绿色的来标记。没有打分的用红色来标记这样方便老师确定那个没有打分。上面介绍完了一般的打分实现。下面介绍自动打分的实现。自动打分也十分的简单。下面是自动打分按钮的处理函数
{
PaperService service = new PaperService();
Paper paper = service.GetById(long.Parse(Request.Form["PaperId"]));
paper.AutoScore();
service.Update(paper);
BindPaperHtml(paper);
}
只要调用Paper类的AutoScore方法即实现自动给客观题打分。然后重新为老师生成试卷的html。
下面来看下AutoScore方法的实现。
{
foreach (QuestionContainer container in QuestionContainers)
{
foreach (Question quesiton in container.Questions)
{
if (quesiton.Content is DanXuanContent || quesiton.Content is DuoXuanContent || quesiton.Content is PanDuanContent)
{
if (quesiton.Content.Answer == quesiton.StudentAnswer)
{
quesiton.Score = quesiton.ScoreValue;
}
else
{
quesiton.Score = 0;
}
quesiton.IsScored = true;
}
}
}
}
该方法遍历Paper中的所有Question对象。如果Question对象引用的是单选。多选,或者是判断。就根据标准答案和学生答案是否相等来打分。并将打过分的Question对象IsScored设为true。