专科软件专业毕业设计-在线考试及练习系统

在线考试及练习系统

开题报告

目标:

随着社会经济的发展,人们对教育越来越重视。考试是教育中的一个重要环节,近几年来考试的类型不断增加以及考试要求不断提高,传统的考试方式要求教师打印考卷,监考、批卷,使教师的工作量越来越大,并且这些环节由于全部由人工完成,非常容易出错。因此,本在线考试及练习系统通过为考生提供更全面、更灵活的服务,解决了管理成本和人力、物力的大量投入,同时。考生希望对自己的学习情况进行客观、科学的评价;教务人员希望有效地改进现有的考试模式,提高考试效率。为了满足考生和教务人员的需求,在线考试及练习系统应包含考试及练习、成绩查询等功能。

内容:

1、用户管理模块:登录,注册,修改信息,安全退出,用户统计。
2、资源模块:查看资源,上传资源,下载资源,资源统计。
3、考试及练习模块:进行考试及练习,新增考试及练习,修改考试及练习,查看结果,考试及练习统计。
4、试卷管理模块:试卷导入,试卷查看,试卷修改,试卷删除,试卷统计。

ps:第一版本,不代表最终效果

数据库设计
数据库设计

ps:第一版本,不代表最终效果

介绍

本项目采用NET MVC作为前后端开发框架,使用了SQL Server作为数据库做数据存储,Entity FramWork作为数据操作框架,Database First数据操作模式,bootstrap用于页面渲染,jQuery用于数据提交,echarts用于图表渲染及操作,多控制器多页面思想,面向对象思想,算法优化思想等等技术。
但是项目其中的算法以及数据处理和提交所用的技术方法尚未成熟,数据库设计思想较差,存在很大瑕疵,尤其是大数据量的操作,以及对各种设备的兼容仍存在较大缺陷,所以本项目仅能用作新手的一个项目参考,也希望广大网友能多多提出意见或建议。

脑图
脑图

大致就这么几个模块,一个模块一个控制器,每个控制器又有不同的页面。整个系统大致的设计就是这样。

项目

母版

<body>
    <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
        <div class="container-fluid">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#example-navbar-collapse">
                    <span class="sr-only">切换导航</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" onmouseover="this.style.color='#9c9c9c'" onmouseout="this.style.color='#000000'" href="~/Main/Home" style="color: #000000; font-weight: bold; ">在线考试及练习系统</a>
            </div>
            <div class="collapse navbar-collapse" id="example-navbar-collapse">
                <ul class="nav navbar-nav">
                    <li><a onmouseover="this.style.color='#9c9c9c'" onmouseout="this.style.color='#000000'" href="~/Main/Home" style="color: #000000; font-weight: bold; ">首页</a></li>
                    <li><a onmouseover="this.style.color='#9c9c9c'" onmouseout="this.style.color='#000000'" href="~/Home/Index" style="color: #000000; font-weight: bold; ">考试</a></li>
                    <li><a onmouseover="this.style.color='#9c9c9c'" onmouseout="this.style.color='#000000'" href="~/Reso/Index" style="color: #000000; font-weight: bold; ">资源大全</a></li>
                    <li><a onmouseover="this.style.color='#9c9c9c'" onmouseout="this.style.color='#000000'" href="~/Test/Index" style="color: #000000; font-weight: bold; ">试卷管理</a></li>
                </ul>
                <!--向右对齐-->
                <ul class="nav navbar-nav navbar-right" id="example-navbar-collapse">
                    <li class="dropdown" style="color:#000000;">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                            <b>我的 </b><b class="caret"></b>
                        </a>
                        <ul class="dropdown-menu">
                            <li><a href="~/My/RecordsInfo">我的成绩</a></li>
                            @*<li><a href="#">我的错题</a></li>*@
                            <li><a data-toggle="modal" data-target="#UpUser" onclick="getuser()">修改信息</a></li>
                            <li class="divider"></li>
                            <li><a href="~/Main/Index">安全退出</a></li>
                        </ul>
                    </li>
                </ul>
                @if (Session["name"] != null)
                {
                    <p class="navbar-text navbar-right" style="color:#000000;"><b>您好!@Session["name"]</b></p>
                }
            </div>
        </div>
    </div>
    <div class="container body-content">
        @RenderBody()
        <hr />
        <!-- 模态框(Modal) -->
        <div class="modal fade" id="UpUser" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                        <h4 class="modal-title" id="myModalLabel">个人信息修改</h4>
                    </div>
                    <form action="~/My/UpdateUser" method="post" class="bs-example bs-example-form" role="form">
                        <div class="modal-body">
                            <div class="input-group" style="margin:20px 0px;">
                                <span class="input-group-addon">昵称</span>
                                <input type="text" class="form-control" name="name" value="@Session["name"]" required placeholder="昵称">
                            </div>
                            <div class="input-group" style="margin:20px 0px;">
                                <span class="input-group-addon">账号</span>
                                <input type="text" class="form-control" name="id" value="@Session["id"]" required placeholder="账号">
                            </div>
                            <div class="input-group" style="margin:20px 0px;">
                                <span class="input-group-addon">密码</span>
                                <input type="text" class="form-control" name="pwd" value="@Session["pwd"]" required placeholder="密码">
                            </div>
                        </div>
                        <div class="modal-footer">
                            <a class="btn btn-default" data-dismiss="modal">关闭</a>
                            <input type="submit" value="提交更改" class="btn btn-primary">
                        </div>
                    </form>
                </div><!-- /.modal-content -->
            </div><!-- /.modal -->
        </div>
        <footer>
            <p>&copy; 在线考试及练习系统</p>
        </footer>
    </div>
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
</body>

登录注册

<div class="dowebok" id="dowebok">
    <div class="form-container sign-up-container">
        <form action="~/Main/Enrolls" method="post">
            <h1>注册</h1>
            <span>或使用邮箱注册</span>
            <div style="height:10px;"></div>
            <input type="text" name="Name" placeholder="昵称" required />
            <input type="text" name="Id" placeholder="账号" required />
            <input type="password" name="Pwd" id="Pwd" placeholder="密码" required />
            <select id="selects" name="Postss" onchange="posts()">
                <option value="2">管理员</option>
                <option value="3">用户</option>
            </select>
            <div id="tests" style="display:none;">
                <input type="text" name="Test" id="lishu" placeholder="隶属人" />
            </div>
            <input type="submit" class="but" value="注册" style="color:#000;" />
        </form>
    </div>
    <div class="form-container sign-in-container">
        <form action="~/Main/login" method="post">
            <h1>登录</h1>
            <span>或使用您的帐号</span>
            <div class="social-container"></div>
            <input type="text" name="userid" placeholder="账号" value="@ViewBag.user" required />
            <input type="password" name="userpwd" placeholder="密码" value="@ViewBag.pwd" required />
            <label style="text-align: left; width: 250px; font-size: 13px; vertical-align: middle;">
                <input type="checkbox" name="jizhu" checked id="jizhu" style="width: 20px; vertical-align: middle;" /><label for="jizhu">记住密码</label>
            </label>
            <input class="but" type="submit" value="登录" style="color:#000;" />
        </form>
    </div>
    <div class="overlay-container" style="background-color:#fff;">
        <div class="overlay">
            <div class="overlay-panel overlay-left">
                <h1>&nbsp;&nbsp;已有帐号?</h1>
                <p>请使用您的帐号进行登录</p>
                <button class="ghost but" id="signIn">登录</button>
            </div>
            <div class="overlay-panel overlay-right">
                <h1>&nbsp;&nbsp;没有帐号?</h1>
                <p>立即加入我们!</p>
                <button class="ghost but" id="signUp">注册</button>
            </div>
        </div>
    </div>
</div>
<script>
    function posts() {
        if ($("#selects").val() == "3") {
            $("#tests").css('display', 'block');
            $("#lishu").attr('required', 'required');
        } else {
            $("#tests").css('display', 'none');
            $("#lishu").removeAttr('required');
        }
    }
</script>
if (!string.IsNullOrEmpty(userId))
            {
                ViewBag.user = userId;
            }
            else
            {
                HttpCookie cookie = Request.Cookies.Get("Example");
                if (cookie != null)
                {
                    ViewBag.user = cookie.Values["UserName"].ToString();
                    ViewBag.pwd = cookie.Values["UserPwd"].ToString();
                }
            }

获取及保存账号

            if (jizhu!=null)
            {
                HttpCookie hc = new HttpCookie("Example");
                hc["UserName"] = userid;
                hc["UserPwd"] = userpwd;
                hc.Expires = DateTime.Now.AddDays(3);
                Response.Cookies.Add(hc);
            }
            else
            {
                HttpCookie hc = Request.Cookies.Get("Example"); ;
                if (hc != null)
                {
                    hc.Expires = DateTime.Now.AddDays(-1);
                    Response.Cookies.Add(hc);                         
                }
            }
            Users u = DAL.GetUser(userid,userpwd);
            if (u.userName__userName.Equals("0x80004005"))
            {
                Response.Write("<script>alert('数据库连接失败!');window.history.go(-1);</script>");
            }
            if (u!=null)
            {
                NowUser.nowUser = u;
                Session["name"] = u.userName__userName;
                Session["id"] = u.userAccount;
                Session["pwd"] = u.userPassword;
                Response.Write("<script>window.location.href='Home';</script>");
            }
            else
            {
                Response.Write("<script>alert('账号或密码错误!');window.history.go(-1);</script>");
            }

登录实现

            //账号查重
            if (DAL.GetUserByAct(Id)!=null)
            {
                Response.Write("<script>alert('账号重复!');window.history.go(-1);</script>");
                return;
            }
            Users u = new Users();
            u.userName__userName = Name;
            u.userAccount = Id;
            u.userPassword = Pwd;
            u.postsID = int.Parse(Postss);
            if (!string.IsNullOrEmpty(Test))
            {
                u.TestUser = DAL.GetUserByAct(Test).userID;
            }
            if (DAL.AddUsers(u))
            {
                Response.Write("<script>alert('注册成功!');window.location.href='Index?userId="+Id+"';</script>");
            }
            else
            {
                Response.Write("<script>alert('注册失败!');window.history.go(-1);</script>");
            }

注册实现

首页

首页主要是页面的跳转以及跳转路径标签的装饰渲染,没有数据操作的功能,仅有一个时间显示的js

<script>
    var div = document.getElementById("showtime");
    var divs = document.getElementById("showtimes");
    setInterval(function () {
        var nowdate = new Date();
        var year = nowdate.getFullYear(),
            month = nowdate.getMonth() + 1,
            date = nowdate.getDate(),
            day = nowdate.getDay(),
            week = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
            h = nowdate.getHours(),
            m = nowdate.getMinutes(),
            s = nowdate.getSeconds(),
            h = checkTime(h),
            m = checkTime(m),
            s = checkTime(s);
        div.innerHTML = year + "年" + month + "月" + date + "日" + week[day];
        divs.innerHTML = h + ":" + m + ":" + s;
    }, 1000);
    var checkTime = function (i) {
        if (i < 10) {
            i = "0" + i;
        }
        return i;

    }
</script>

考试

考试主界面就是一个所有试卷的查询显示,单个试卷的信息查询,以及根据id跳转到考试页面或练习界面,没有什么主要功能。

考试页面和练习页面主要是就所有题目的遍历,所有选项的遍历,以及根据题目编号的跳转等等,其中所有题目和选项并不能使用数据库查出来的顺序列表,而是需要中间操作一下,对其顺序进行随机打乱,做到题目无序,选项无序,保证考试的安全性和公平性。题目的遍历则使用for循环,这里其实可以有更好地选择,比如vue的v-for以及双向绑定和数据提交,会比单纯的for循环和jQuery的ajax优秀很多。

提交

$.ajax({
            type: "post",
            url: "Judging",
            data: "xuanze=" + cho + "&panduan=" + jud + "&tiankong=" + fil + "&jianda=" + ans,
            success: function (data) {
                document.write(data);
                setTimeout(function () {
                    history.back(-1);
                }, 10000);
            },
            error: function (e) {
                alert("交卷失败" + e);
            }
        });

这里写的提交是使用合并字符串和拆解字符串的方式,属于是最下下层的一种方式,现在看来真是太拉了,这里仅做参考,不建议使用这种方式,比较好的方式还是vue的双向绑定提交方式。

打乱算法

        Random ran = new Random();
        /// <summary>
        /// 试题随机打乱算法
        /// </summary>
        /// <param name="l"></param>
        /// <returns></returns>
        public List<Chooses> Dischooses(List<Chooses> l)
        {
            int[] nums = new int[l.Count];
            for (int i = 0; i < l.Count; i++)
            {
                nums[i] = i+1;
            }
            
            byte[] b = new byte[l.Count];
            ran.NextBytes(b);
            Array.Sort(b,nums);
            List<Chooses> temp = new List<Chooses>();
            for (int i = 0; i < nums.Length; i++)
            {
                Chooses c = l[nums[i]-1];
                temp.Add(DisType(c));
            }
            return temp;
        }
        /// <summary>
        /// 选项随机打乱算法
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        public Chooses DisType(Chooses c)
        {
            //选项
            char[] answer = c.Answer.ToLower().Trim().ToArray();
            //保存答案值
            string[] ans = new string[answer.Length];
            for (int i = 0; i < answer.Length; i++)
            {
                switch (answer[i])
                {
                    case 'a':
                        ans[i] = c.TypeA;
                        break;
                    case 'b':
                        ans[i] = c.TypeB;
                        break;
                    case 'c':
                        ans[i] = c.TypeC;
                        break;
                    case 'd':
                        ans[i] = c.TypeD;
                        break;
                    case 'e':
                        ans[i] = c.TypeE;
                        break;
                    default:
                        break;
                }
            }
            //选项值
            List<string> l = new List<string>();
            if (c.TypeA != null)
            {
                l.Add(c.TypeA);
            }
            if (c.TypeB != null)
            {
                l.Add(c.TypeB);
            }
            if (c.TypeC != null)
            {
                l.Add(c.TypeC);
            }
            if (c.TypeD != null)
            {
                l.Add(c.TypeD);
            }
            if (c.TypeE != null)
            {
                l.Add(c.TypeE);
            }

            //1-1+1 1-1+2 1+1-1+2 5-5+1 5-5+2 5+1-5+2

            //打乱
            for (int i = 0; i < l.Count; i++)
            {
                int lift = 0;
                int right = l.Count-1;
                string item = "";
                switch (ran.Next(6))
                {
                    case 0:
                        item = l[lift];
                        l[lift] = l[lift+1];
                        l[lift+1] = item;
                        break;
                    case 1:
                        item = l[lift];
                        l[lift] = l[lift + 2];
                        l[lift + 2] = item;
                        break;
                    case 2:
                        item = l[lift+2];
                        l[lift+2] = l[lift + 1];
                        l[lift + 1] = item;
                        break;
                    case 3:
                        item = l[right];
                        l[right] = l[right - 1];
                        l[right - 1] = item;
                        break;
                    case 4:
                        item = l[right];
                        l[right] = l[right - 2];
                        l[right - 2] = item;
                        break;
                    case 5:
                        item = l[right-2];
                        l[right-2] = l[right - 1];
                        l[right - 1] = item;
                        break;
                    default:
                        break;
                }
            }

            string zans = "";
            //寻找答案
            for (int i = 0; i < ans.Length; i++)
            {
                for (int j = 0; j < l.Count; j++)
                {
                    if (ans[i].Equals(l[j]))
                    {
                        zans += (char)(97 + j);
                        break;
                    }
                }
            }
            char[] ch = zans.ToArray();
            Array.Sort(ch);
            string da = new string(ch);
            c.Answer = da.ToUpper();

            //赋值
            if (l.Count>0)
            {
                c.TypeA = l[0];
            }
            if (l.Count > 1)
            {
                c.TypeB = l[1];
            }
            if (l.Count > 2)
            {
                c.TypeC = l[2];
            }
            if (l.Count > 3)
            {
                c.TypeD = l[3];
            }
            if (l.Count > 4)
            {
                c.TypeE = l[4];
            }
            return c;
        }

判卷算法

            string[] cho = xuanze.Split(' ');
            //索引
            int i = 0;
            //错题数量
            int sum = 0;
            foreach (var item in cho)
            {
                //去空选项
                if (!item.Equals(""))
                {
                    //比对
                    //多选
                    if (item.Length>1)
                    {
                        char[] t = item.ToCharArray();
                        Array.Sort(t);
                        string temp = new string(t);
                        if (!(daan[i].ToLower()).Equals(temp.ToLower()))
                        {
                            sum++;
                        }
                    }
                    else
                    {
                        if (!(daan[i].ToLower()).Equals(item.ToLower()))
                        {
                            sum++;
                        }
                    }
                    i++;
                }
            }
            string[] jud = panduan.Split(' ');
            foreach (var item in jud)
            {
                if (!item.Equals(""))
                {
                    //比对
                    if (!(daan[i].ToLower()).Equals(item.ToLower()))
                    {
                        sum++;
                    }
                    i++;
                }
            }
            string[] fil = tiankong.Split(' ');
            foreach (var item in fil)
            {
                if (!item.Equals(""))
                {
                    //比对
                    if (!daan[i].Equals(item.ToLower()))
                    {
                        sum++;
                    }
                    i++;
                }
            }
            string[] ans = jianda.Split(' ');
            foreach (var item in ans)
            {
                if (!item.Equals(""))
                {
                    if (!daan[i].Equals(item.ToLower()))
                    {
                        sum++;
                    }
                    i++;
                }
            }

正因为使用了字符串提交的方式,造成无论前端数据处理还是后端数据匹配,复杂度都比较高。不如vue方便简洁。

试卷

这一块呢主要是试卷的导入和Excel的读取,其余操作均是对数据库数据的增删改查。导入就是文件的上传以及保存。

Excel读取

            string connstring = "Provider = Microsoft.ACE.OLEDB.12.0; Data Source = " + path + "; Extended Properties = 'Excel 8.0;';";
            using (OleDbConnection conn = new OleDbConnection(connstring))
            {
                conn.Open();
                DataTable sheetsName = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "Table" }); //得到所有sheet的名字
                string firstSheetName = sheetsName.Rows[0][2].ToString(); //得到第一个sheet的名字
                string sql = string.Format("SELECT * FROM [{0}]", firstSheetName); //查询字符串
                OleDbDataAdapter ada = new OleDbDataAdapter(sql, connstring);
                DataSet set = new DataSet();
                ada.Fill(set);
                conn.Close();
                conn.Dispose();
                return set.Tables[0];
            }

资源

资源主要就是文件上传与下载,以及页面的展示,展示也是使用for循环方式。

上传

        [HttpPost]
        public void AddReso(HttpPostedFileBase files, string txtname, string txtintro)
        {
            if (files == null || string.IsNullOrEmpty(txtname) || string.IsNullOrEmpty(txtintro))
            {
                Response.Write("<script>alert('资源不允许为空!');window.location.href='Index';</script>");
                return;
            }
            string fileName = files.FileName;
            string exten = Path.GetExtension(fileName).ToLower();
            string testName = System.Guid.NewGuid().ToString("N");
            string url = Server.MapPath("~/Resource/") + testName + exten;
            files.SaveAs(url);
            //插入数据库
            Resources r = new Resources();
            r.ResourceName = txtname;
            r.ResourceIntro = txtintro;
            r.ResourceSize = (files.ContentLength/1024).ToString() + "KB";
            r.DownloadCount = 0;
            r.UserID = NowUser.nowUser.userID;
            r.ResourceCode = testName + exten;
            if (DAL.AddResources(r))
            {
                Response.Write("<script>alert('上传成功!');window.location.href='Index';</script>");
            }
        }

下载

        public FileStreamResult Download(string fileName,string fileid)
        {
            string filePath = Server.MapPath("~/Resource/"+fileName);
            FileStream fs = new FileStream(filePath, FileMode.Open);
            //修改下载次数
            DAL.SetResoCount(int.Parse(fileid));
            return File(fs, "text/plain", fileName);
        }

我的

此模块的个人信息转移到了母版里边,其中也是数据操作,主要是应用了echarts图表

<div id="main" style="width:100%;height:400px;margin:40px 0px;"></div>
@section Scripts{

    <script>

        $.ajax({
            url: "Echart",
            type: "get",
            data: {},
            dataType: 'json',
            async: false,
            success: function (res) {
                var myChart = echarts.init(document.getElementById('main'));
                myChart.setOption({
                    title: {
                        text: '我的成绩',
                        left: 'center'
                    },
                    tooltip: {},
                    xAxis: {
                        name: '日期',
                        data: res.RecordTime
                    },
                    yAxis: {
                        type: 'value',
                        name: '成绩'
                    },
                    series: [{
                        name: '成绩',
                        type: 'line',
                        data: res.Score,
                        areaStyle: {
                            normal: {
                                color: 'skyblue'
                            }
                        },
                        itemStyle: {
                            normal: {
                                color: 'skyblue',
                                lineStyle: {
                                    color: 'skyblue'
                                }
                            }
                        },
                        // 最大最小值
                        markPoint: {
                            data: [
                                {
                                    type: 'max',
                                    name: '最高成绩'
                                },
                                {
                                    type: 'min',
                                    name: '最低成绩'
                                }
                            ]
                        },
                        // 平均值
                        markLine: {
                            data: [
                                {
                                    type: 'average',
                                    name: '平均成绩'
                                }
                            ]
                        }
                    }]
                })
            }
        });

    </script>
}

大概的功能就是这些,各位大佬有什么意见或者建议都欢迎提出!

资源

暂无,或联系我q+2698666037。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PROBIE_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值