美文网首页前端社团
Node.js在线考试系统——服务器与客户端的交互

Node.js在线考试系统——服务器与客户端的交互

作者: 折柳画马 | 来源:发表于2016-12-24 21:51 被阅读984次

    Node.js在线考试系统

    1. 系统结构

    系统考虑使用Nodejs和SocketIo实现服务器端逻辑,前端使用HTML5,数据库使用MongoDB

    2.数据结构

    用户表

    var userSchema = new Schema({
        userId:String,          //用户ID
        username: String,       //用户名称
        password: String,       //账户密码,初始化为a
        status:String,          //用户状态,分为四个状态,在线landing,离线offline,提交完毕submited,考试中testing
        identity:String,        //用户身份,分别为student和teacher
    });
    

    科目表

    var subjectsSchema = new Schema({
        course:String,      //考试科目名称
        startTime:Date,     //考试开始时间
        lastTime:Number,    //考试持续时间,单位为分
        numOfQuestions:Number,//问题总数
        questions:[{        //问题
            index:Number,   //当前问题序号
            question:String,//问题内容
            score:Number    //问题分值
        }]
    });
    

    答题表

    var answersSchema = new Schema({
        user:{type:Schema.Types.ObjectId, ref:'User' },//用户表引用
        subject:{type:Schema.Types.ObjectId,ref:'Subjects'},//科目表引用
        questions:[{
            index:Number,//当前问题序号
            content:String,//答案
            score:Number //后期打分分值
        }]
    });
    

    3.系统模块设计

    3.1前端
    3.1.1学生模块

    • 绘制倒计时界面
    * 提示学生还有多少时间开始考试
    * 如果考试时间未到,学生点击开始考试会弹出"未到考试时间"提示框
    * 开始考试,学生点击开始考试按钮,进入考试界面并且发送消息给服务器,服务器转发给教师端,更新教师端当前学生状态
    
    准备界面.jpg
    • 绘制答题界面
      • 绘制题目下标、题目标题、题目内容
      • 绘制答题框
      • 绑定上一题、提交答案、下一题三个按钮点击事件
    • 存储数据


      答题界面.jpg
    • 提交答案
      • 发送学生ID、题目序号、题目答案到服务器,服务器存入数据库

    3.1.2教师模块

    • 绘制学生状态界面
    * 将每一个学生的名字与学生ID作为一个单位,有序的排列在界面上
    * 绑定点击学生信息单元,进入对应学生的打分界面
    * 通过socket实时更新学生状态
    
    学生状态界面
    • 绘制打分界面
      • 主要调用学生模块的绘制答题界面函数
      • 添加打分栏
      • 更改提交答案按钮为打分按钮=


        改成绩界面
    • 存储数据
      3.1.3客户端socket模块
    • 发送数据模块
    * 向服务器提交学生考试答案(学生端)
    * 向服务器提交教师所改学生答卷题目分数(教师端)
    * 向服务器提交开始考试信息(学生端)
    * 向服务器提交结束考试信息(学生端)
    
    • 接受数据模块
      • 接受来自服务器发送的确认登录消息(学生端、教师端)
      • 接受来自服务器发送的状态改变消息(教师端)

    3.2后台
    3.2.1数据库操作模块

    • 向登录的学生发送数据(考试开始时间,考试内容)
    • 向登录的教师发送数据(学生列表,学生考试答案)
    • 更改用户状态(在线、进行考试、结束考试、离线)
    • 存储学生考卷答案
    • 存储学生考卷题目得分

    3.2.2服务器socket模块

    • 接收来自客户端所提交的学生考试答案,并调用数据库模块存储学生考卷答案
    • 接收来自客户端提交的教师所改学生答卷题目分数,并调用数据库模块存储学生考卷得分
      。。。。。。
      服务器socket模块实现的功能与客户端socket模块相对应

    4.功能分析

    学生模块与教师模块中的界面绘制之前已有文章提及,这里略去
    学生模块的本地数据存储功能

    学生登录->
    后台路由发送数据data->

    router.get('/student', function(req, res, next) {
      dbHelper.findUsrInfo(req, function (success, data) {
        //console.log(data.friends);
        //data.identify身份,data.subject考试题目,data.answer考试答案
        res.render('student', {
          scriptData:JSON.stringify(data),
          data:data
        });
      })
    });
    

    因为服务器应用express模块,data数据用于渲染前端页面,但无法被js文件获取到,所以需要经过处理,data数据被转换为json格式,并存入window.scriptData->

    <script>
        window.scriptData = JSON.stringify({{{scriptData}}});
        window.scriptData=eval("("+window.scriptData+")");//转换为json对象
    </script>
    

    学生成功登录后,进入准备开始考试界面,运行modalBox.init()函数,并将modalBox对象并赋值给STUDENT,default存储本地数据,window.scriptData.subject.questions即为服务器所发考试相关数据中的题目对象->

    var STUDENT;
    new modal_student();
    var modal_student = function () {
         var modalBox = {
            default:{
                  questions:[],//题目对象
                  answers:[],//学生所写答案
                  index:0//当前题目编号,
            },
            init:function () {
                ptrThis = this;
                ptrThis.setQuestions();
            },
            setQuestions:function () {
                ptrThis.default.questions = window.scriptData.subject.questions;
                console.log(ptrThis.default.questions);
            },
         }
        STUDENT = modalBox;
        return modalBox.init();
    }
    

    今后学生切换题目时只需要从本地获取数据,而不需要多次与服务器进行请求

    教师模块的本地数据存储功能

    教师登录->
    后台发送数据data->

    router.get('/teacher', function(req, res, next) {
      dbHelper.findStudentsInfo(req, function (success, data) {
        //console.log(data.friends);
        //data.students学生信息,data.subject课程信息
        res.render('teacher', {
          students:data.students,
          scriptData:JSON.stringify(data)
        });
      })
    });
    

    与上同->

    <script>
        window.scriptData = JSON.stringify({{{scriptData}}});
        window.scriptData=eval("("+window.scriptData+")");//转换为json对象
    </script>
    

    教师成功登录后,进入浏览学生名单界面,运行modalBox.init()函数,并将modalBox对象并赋值给TEACHER->

    var TEACHER;
    new modal_teacher();
    var modal_teacher = function () {
        var ptrThis;
         var modalBox = {
             default:{
                 studentIndex:0,//当前正在进行批改的学生的下标
                 studentsList:[]
             },
            init:function () {
                ptrThis = this;
                ptrThis.default.studentsList = window.scriptData.students;
            }
        }
        TEACHER = modalBox;
        return modalBox.init();
    }
    

    studentsList存储学生信息列表,包含学生姓名、学号、状态,以及学生每道题目的答案
    studentsList格式

    var studentList = [{
          user:{
              username:String,//学生姓名
              userId:String,//学生ID
              status:String,//学生状态
          },
          questions:[{
              content:String,//答案
              index:Number//当前题目下标
          }]
    }]
    

    学生交卷

    modalBox.bindEnd()绑定了结束考试button的点击事件->

           bindEnd:function () {
                var end = document.getElementById("end");
                end.addEventListener("click",function () {
                   ptrThis.saveAnswer();//将当前答案保存到本地文件
                   socketFun.end();//调用客户端socket模块的end()函数
                });
            },
    

    点击事件触发,调用客户端socket模块的end()函数->

    var socket = io.connect('http://localhost:3000');
    var X = window.scriptData;                          //截取服务器发送过来的数据
    var socketFun = {
        //省略
        end:function () {
            var obj = {
                userId:X.userId,
                indentify:X.identify
            }
            obj ["answers"] = STUDENT.default.answers;
            if(X.status=="submited"){
                alert("你已经提交过答案!");
            }else {
                socket.emit("end", obj );
            }
        }
    }
    

    客户端socket模块将学生学号userId、学生身份identify、学生答案answers发送到服务器->

            socket.on("end",function (result) {
                User.update({userId:result.userId},{status:"submited"}).exec(function (err,doc) {//更新数据库中的学生状态为submited(提交答案)
                    User.findOne({userId:result.userId}).exec(function (err,doc) {//根据学生ID查询该条学生记录
                        var change = {
                            studentId:result.userId,
                            status:"submited"
                        };
                        if(teacherOnline){//如果教师在线,则向其发送学生状态改变的消息
                            teacher.emit("statusChange",change);
                        }
                        Answers.findOne({user:doc._id}).exec(function (err,answer) {//答题表根据学生记录的_id查询到对应记录,更新答案
                            answer.questions = result.answers;
                            answer.save(function (err) {})
                        })
                    });
                })
            }),
    

    教师模块通过socket实时更新学生状态

    客户端socket模块接收到来自服务器的学生状态改变信息->

    var socket = io.connect('http://localhost:3000');
    socket.on("statusChange",function (change) {
        TEACHER.changeStatus(change);
    })
    

    调用教师模块的changeStatus函数,以change为参数->

             changeStatus:function (change) {
                 console.log(ptrThis.default.studentsList);
                for(var i = 0;i<ptrThis.default.studentsList.length;++i){//遍历当前学生列表
                    console.log(ptrThis.default.studentsList[i].user.userId+"与"+change.studentId);
                    if(ptrThis.default.studentsList[i].user.userId==change.studentId){//重新设置status
                        ptrThis.default.studentsList[i].user.status = change.status;
                        var studentInfo = document.getElementsByClassName("studentInfo");
                        studentInfo[i].setAttribute("class","studentInfo "+change.status);//修改界面上学生列表中对应的学生的状态(改变颜色以提示教师有学生状态改变)
                        break;
                    }
                }
             },
    

    5.具体代码见

    github下的onlineTest项目

    相关文章

      网友评论

      • 3080ccd953ce:你好 我在你GitHub下没找见这个项目 有具体地址么 谢谢

      本文标题:Node.js在线考试系统——服务器与客户端的交互

      本文链接:https://www.haomeiwen.com/subject/yefrvttx.html