基于Node.js的在线考试系统

https://github.com/Gu-Miao/online-examination-system.git

开发背景

随着信息技术的日新月异,新兴技术逐渐走进人们的日常生活,改变着人们的工作和生活方式,传统纸质考试耗费大量人力物力资源,已经越来越不越能够满足教学的需要。开发一套在线考试的系统,使用数字化,信息化的方式对考试进行管理已经显得越来越必要。这不仅可以节省教学资源,减轻师生负担,更可以及时反馈考试信息,提高教学效率。

功能性需求

本系统的用户分为三类:学生,教师,系统管理员。

技术选型

功能实现

用户登录

用户登录页面

用户登录页面

用户管理

用户管理页面

用户管理页面

试题管理

试题管理页面

试题管理页面

新增试题页面

新增试题页面

试卷管理

试卷管理页面

试卷管理页面

修改试卷管理页面

修改试卷管理页面

考试管理

考试管理页面

考试管理页面

在线考试

在线考试页面

在线考试页面

成绩管理

阅卷页面

试题管理页面

成绩查询页面

成绩查询页面

项目总结

本设计基于 Node.js,使用 express 作为框架,MongoDB 作为数据库,结合前端技术,设计并实现了一款在线考试信息系统。完成了系统的用户登录、用户管理、试题管理、试卷管理、考试管理等功能模块,基本实现了系统的功能需求。

技术亮点

本系统的一部分页面需要根据后端返回的数据进行渲染,于是我需要动态渲染的 DOM 封装在 JS 函数中,然后在函数体内绑定事件函数或进行 DOM 操作,可以避免选择器滥用问题,之后在需要时进行调用组件函数,代码更加灵活。

下面是新增试卷页面中渲染单选题使用的组件函数:

// 单选题
function newSin($root) {

    let $dom = $(`
        <div class=" col-12">
            <div class="form-group col-12">
                <label>题干</label>
                <textarea class="content form-control"></textarea>
            </div>
            <div class="form-group col-6">
                <label>正确答案</label>
                <input type="number" class="answer form-control" min="1" step="1">
            </div>
            <div class="form-group col-12">
                <button class="addop btn btn-primary form-control w-100">添加选项</button>
            </div>
        </div>
    `);

    $dom.find('.addop').click(function () {
        let $dom1 = $(`
            <div class="form-group col-12">
                <label>选项${$dom.find('.op').length + 1}</label>
                <span class="badge badge-pill badge-danger float-right">删除</span>
                <input type="text" class="form-control op">
            </div>
        `);
        $dom1.find('.badge').click(function () {
            $dom1.remove();
            const op_count = $dom.find('.op').length;
            if ($dom.find('.answer').val() > op_count) $dom.find('.answer').val('');
            $dom.find('.answer').prop('max', op_count);
            for (let i = 0; i < op_count; ++i) {
                $dom.find('.op').eq(i).parent().find('label').html(`选项${i + 1}`);
            }
        });
        $dom.find('.addop').parent().before($dom1);
        const op_count = $dom.find('.op').length;
        if ($dom.find('.answer').val() > op_count) $dom.find('.answer').val('');
        $dom.find('.answer').prop('max', op_count);
    });
    $dom.find('.answer').blur(function () {
        const op_count = $dom.find('.op').length;
        console.log(op_count)
        if ($(this).val() > op_count) $(this).val('');
        $(this).prop('max', op_count);
    });

    $root.append($dom);
}

使用 Mongoose 需要定义 Schema 和 model,作者将每个 MongoDB 集合的数据模型定义好并使用 node.js 的 module.exports 暴露出来,再将它们集中放到一个文件夹中,之后在需要用到的时候再将其 require 到路由代码中。前端发起的每个求地址就是页面本身的 url,这样每一个路由只处理对应一个页面的 get, post, put, delete 等请求。这样就形成了一个页面对应一个路由,路由代码中需要操作数据库的哪个集合,就把对应的数据模型引入,很好的避免了数据模型重复定义,路由混乱等问题。

users 集合数据模型 users.js

// 引入 Mongoose
let mongoose = require('./connect');

// 定义学生集合数据结构
let UsersSchema = mongoose.Schema({
    name: { // 中文姓名
        type: String,
        trim: true,
        minlength: 2,
        maxlength: 20
    },
    uid: { // 学工号
        type: String,
        trim: true,
        minlength: 1
    },
    grade: { // 年级
        type: String,
        trim: true,
        minlength: 1
    },
    college: { // 所属学院
        type: String,
        trim: true,
        minlength: 1
    },
    major: { // 所属专业
        type: String,
        trim: true,
        minlength: 1
    },
    username: { // 登录账号
        type: String,
        trim: true,
        minlength: 1
    },
    password: { // 登录密码,6~16 位数字字母,符号只可以使用 “_” 和 “.”。
        type: String,
        trim: true,
        minlength: 6,
        maxlength: 16,
        match: /^[\w_.]{6,16}$/
    },
    type: { // 用户类型
        type: Number,
        trim: true,
        minlength: 1,
        maxlength: 2,
    }
}, { versionKey: false });

module.exports = mongoose.model('Users', UsersSchema, 'users');

用户管理页面的路由 userManagement.js

// 引入 express
let express = require('express');
let router = express.Router();

// 引入第三方库
let jsonParser = require('body-parser').json();
let app = express();
app.use(jsonParser);

// 引入数据库集合模型
let usersModel = require('../model/users');

router.get('/', function (req, res, next) {
    res.render('userManagement');
});

router.post('/', function (req, res, next) {
    var reqData = JSON.parse(JSON.stringify(req.body));
    if (reqData.search) {
        reqData = JSON.parse(reqData.search);
        console.log(reqData)
    }

    usersModel.find(reqData, (err, docs) => {
        if (err) {
            console.log('err: ', err);
        } else {
            // console.log(docs);
            res.json(docs);
        }
    });
});

router.delete('/', function (req, res, next) {
    // console.log(req.body, typeof req.body);
    usersModel.deleteOne({ uid: req.body.uid }, (err, docs) => {
        if (err) {
            throw err;
        } else {
            console.log(docs);
            res.json(docs);
        }
    });
});

module.exports = router;

不足