微信小程序|考试系统|基于微信小程序和SpringBoot+VUE的智能在线考试系统毕业设计
作者主页:编程千纸鹤
作者简介:Java、前端、Python开发多年,做过高程,项目经理,架构师
主要内容:Java项目开发、毕业设计开发、面试技术整理、最新技术分享
收藏点赞不迷路 关注作者有好处
文末获得源码
项目编号:JL
一,项目简介
随着计算机技术的不断发展,我们的日常生活和工作都与计算机技术的关系越来越密切。计算机技术的发展改变了我们日常的生活和工作习惯,也改变了社会的发展速度,使得我们的生活更加便利和高效。伴随着计算机技术发展起来的互联网技术将我们的生活带领进信息化时代,改变了我们的学习和工作环境,例如我们经常面对的考试也随着互联网技术的发展产生了改变,伴随着信息技术的发展,在线无纸化的考试系统应运而生,不仅彻底改变了传统纸质考试的习惯和环境,更是提高了考试效率,保证了考试效果,达到了考试目的[1]。传统的纸质考试具有很多局限性和不足,主要包括以下几点:
1.传统纸质考试需要较多的人力资源和时间资源进行题目的设定,同时题目的难易程度和考核价值水平很难达到基本的要求;
2.传统纸质考试的阅卷采用人工的方式,人工阅卷难免会出现阅卷差错或者分数合算差错,这也会对考试的效果造成影响;
3.传统纸质考试的人工阅卷模式也会浪费大量的人力资源和时间资源,不能保证工作效率和工作质量;
4.传统纸质考试对考试的总结能力较差,不能够全面具体的分析考试结果,教师也很难得到基本的考试结果分析的数据信息,而这些数据信息是提高教学质量和教学效果的关键因素;
5.传统纸质考试对考试时间以及考试纪律的要求不能达到统一,这也会影响到考试的公平性。根据以上分析的传统纸质考试的不足之处,新型的结合计算机技术以及互联网技术的在线考试系统应运而生,不仅通过一种新的技术解决了传统纸质考试的基本问题,还提供了一种新的考试思路和考试理念,纠正了传统纸质考试的弊端,提供更加合理有效的考试过程。
二,环境介绍
三,技术说明
后端系统 | 前端系统 | 微信小程序 |
---|---|---|
spring-boot 2.1.6.RELEASE | vue 采用新版,使用了vue-cli4搭建的系统 | iView 主题样式 |
spring-boot-security 用户登录验证 | element-ui 最流行的vue UI框架 | |
undertow web容器 | vue-element-admin 模版 | |
mybatis/mybatis_plus | echarts 图表统计 | |
hikari 速度最快的数据库连接池 | ueditor 题目编辑器 |
四,功能列表
4.1 学生系统功能
模块 | 介绍 |
---|---|
登录 | 用户名、密码 |
注册 | 年级、用户名、密码 |
任务中心 | 管理员发布的年级任务,每个学生只能做一次 |
考试 | 题干支持文本、图片、数学公式、表格等,学生答题支持:文本 |
固定试卷 | 可重复练习、自行批改的试卷 |
时段试卷 | 在时间限制内,可重复练习、自行批改的试卷 |
考试记录 | 查看答卷记录和试卷信息 |
错题本 | 答错题目会自动进入错题本,显示题目基本信息 |
个人信息 | 显示学生个人资料 |
更新信息 | 修改个人资料、头像 |
个人动态 | 显示用户最近的个人动态 |
消息中心 | 用于接收管理员发送的消息 |
4.2 管理系统功能
模块 | 介绍 |
---|---|
登录 | 用户名、密码 |
主页 | 试卷总数、题目总数、用户活跃度、题目月数量 |
学生列表 | 显示系统所有的学生,新增、修改、删除、禁用 |
管理员列表 | 显示系统所有的管理员,新增、修改、删除、禁用 |
学科列表 | 学科查询、修改、删除 |
学科创编 | 创建学科 |
试卷列表 | 试卷查询、修改、删除 |
试卷创编 | 创建的试卷为时段试卷、固定试卷、任务试卷 |
题目列表 | 题目查询、修改、删除 |
题目创建 | 题目支持单选题、多选题、判断题、填空题、简答题,题干支持文本、图片、表格、数学公式 |
任务列表 | 任务查询、修改、删除 |
消息列表 | 显示已发送的消息,消息已读人数等信息 |
消息发送 | 发送消息给多个用户 |
用户日志 | 显示所有用户日志 |
个人资料 | 显示管理员用户名、真实姓名 |
时间线 | 显示管理员创建时间 |
修改资料 | 修改姓名、手机号 |
4.3 小程序功能
模块 | 介绍 |
---|---|
登录 | 用户登录登出功能,登录会自动绑定微信账号,登出会解绑 |
注册 | 年级、用户名、密码 |
任务中心 | 管理员发布的年级任务,每个学生只能做一次 |
考试 | 题干支持文本、图片、数学公式、表格等,学生答题支持:文本 |
固定试卷 | 可重复练习、自行批改的试卷 |
时段试卷 | 在时间限制内,可重复练习、自行批改的试卷 |
考试记录 | 查看答卷记录和试卷信息 |
错题本 | 答错题目会自动进入错题本,显示题目基本信息 |
个人信息 | 显示学生个人资料 |
更新信息 | 修改个人资料、头像 |
个人动态 | 显示用户最近的个人动态 |
消息中心 | 用于接收管理员发送的消息 |
五,数据库设计
仅展示部分数据库字段设计
5.1 试卷表
字段名 | 类型 | 注释 |
---|---|---|
id | int | |
name | varchar | 试卷名称 |
subject_id | int | 学科 |
paper_type | int | 试卷类型( 1.固定试卷 4.时段试卷 6.任务试卷 ) |
grade_level | int | 年级 |
score | int | 试卷总分(千分制) |
question_count | int | 题目数量 |
suggest_time | int | 建议时长(分钟) |
limit_start_time | datetime | 时段试卷 开始时间 |
limit_end_time | datetime | 时段试卷 结束时间 |
frame_text_content_id | int | 试卷框架 内容为JSON |
create_user | int | |
create_time | datetime | |
deleted | bit | |
task_exam_id | int |
5.2 试卷答案表
字段名 | 类型 | 注释 |
---|---|---|
id | int | |
exam_paper_id | int | |
paper_name | varchar | 试卷名称 |
paper_type | int | 试卷类型( 1.固定试卷 4.时段试卷 6.任务试卷 ) |
subject_id | int | 学科 |
system_score | int | 系统判定得分 |
user_score | int | 最终得分(千分制) |
paper_score | int | 试卷总分 |
question_correct | int | 做对题目数量 |
question_count | int | 题目总数量 |
do_time | int | 做题时间(秒) |
status | int | 试卷状态(1待判分 2完成) |
create_user | int | 学生 |
create_time | datetime | 提交时间 |
task_exam_id | int |
5.3 题目表
字段名 | 类型 | 注释 |
---|---|---|
id | int | |
question_type | int | 1.单选题 2.多选题 3.判断题 4.填空题 5.简答题 |
subject_id | int | 学科 |
score | int | 题目总分(千分制) |
grade_level | int | 级别 |
difficult | int | 题目难度 |
correct | text | 正确答案 |
info_text_content_id | int | 题目 填空、 题干、解析、答案等信息 |
create_user | int | 创建人 |
status | int | 1.正常 |
create_time | datetime | 创建时间 |
deleted | bit |
5.4 学科表
字段名 | 类型 | 注释 |
---|---|---|
id | int | |
name | varchar | 语文 数学 英语 等 |
level | int | 年级 (1-12) 小学 初中 高中 大学 |
level_name | varchar | 一年级、二年级等 |
item_order | int | 排序 |
deleted | bit |
5.5 用户表
字段名 | 类型 | 注释 |
---|---|---|
id | int | |
user_uuid | varchar | |
user_name | varchar | 用户名 |
password | varchar | |
real_name | varchar | 真实姓名 |
age | int | |
sex | int | 1.男 2女 |
birth_day | datetime | |
user_level | int | 学生年级(1-12) |
phone | varchar | |
role | int | 1.学生 3.管理员 |
status | int | 1.启用 2禁用 |
image_path | varchar | 头像地址 |
create_time | datetime | |
modify_time | datetime | |
last_active_time | datetime | |
deleted | bit | 是否删除 |
wx_open_id | varchar | 微信openId |
5.6 用户日志表
字段名 | 类型 | 注释 |
---|---|---|
id | int | |
user_id | int | 用户id |
user_name | varchar | 用户名 |
real_name | varchar | 真实姓名 |
content | text | 内容 |
create_time | datetime | 时间 |
其他表的设计省略............
六,系统展示
6.1 后台管理
主页
用户管理
试卷管理
题目管理
添加题目
添加试卷
任务管理
教育管理
成绩管理
6.2 学生端
首页登录与注册
学生端首页
试卷中心
考试记录
错题本
个人中心
6.3 小程序端
登录与注册
首页
试卷考试
考试记录
我的
七,核心代码展示
@Service
public class TaskExamServiceImpl extends BaseServiceImpl<TaskExam> implements TaskExamService {protected final static ModelMapper modelMapper = ModelMapperSingle.Instance();private final TaskExamMapper taskExamMapper;private final TextContentService textContentService;private final ExamPaperMapper examPaperMapper;@Autowiredpublic TaskExamServiceImpl(TaskExamMapper taskExamMapper, TextContentService textContentService, ExamPaperMapper examPaperMapper) {super(taskExamMapper);this.taskExamMapper = taskExamMapper;this.textContentService = textContentService;this.examPaperMapper = examPaperMapper;}@Overridepublic PageInfo<TaskExam> page(TaskPageRequestVM requestVM) {return PageHelper.startPage(requestVM.getPageIndex(), requestVM.getPageSize(), "id desc").doSelectPageInfo(() ->taskExamMapper.page(requestVM));}@Override@Transactionalpublic void edit(TaskRequestVM model, User user) {ActionEnum actionEnum = (model.getId() == null) ? ActionEnum.ADD : ActionEnum.UPDATE;TaskExam taskExam = null;if (actionEnum == ActionEnum.ADD) {Date now = new Date();taskExam = modelMapper.map(model, TaskExam.class);taskExam.setCreateUser(user.getId());taskExam.setCreateUserName(user.getUserName());taskExam.setCreateTime(now);taskExam.setDeleted(false);//保存任务结构TextContent textContent = textContentService.jsonConvertInsert(model.getPaperItems(), now, p -> {TaskItemObject taskItemObject = new TaskItemObject();taskItemObject.setExamPaperId(p.getId());taskItemObject.setExamPaperName(p.getName());return taskItemObject;});textContentService.insertByFilter(textContent);taskExam.setFrameTextContentId(textContent.getId());taskExamMapper.insertSelective(taskExam);} else {taskExam = taskExamMapper.selectByPrimaryKey(model.getId());modelMapper.map(model, taskExam);TextContent textContent = textContentService.selectById(taskExam.getFrameTextContentId());//清空试卷任务的试卷Id,后面会统一设置List<Integer> paperIds = JsonUtil.toJsonListObject(textContent.getContent(), TaskItemObject.class).stream().map(d -> d.getExamPaperId()).collect(Collectors.toList());examPaperMapper.clearTaskPaper(paperIds);//更新任务结构textContentService.jsonConvertUpdate(textContent, model.getPaperItems(), p -> {TaskItemObject taskItemObject = new TaskItemObject();taskItemObject.setExamPaperId(p.getId());taskItemObject.setExamPaperName(p.getName());return taskItemObject;});textContentService.updateByIdFilter(textContent);taskExamMapper.updateByPrimaryKeySelective(taskExam);}//更新试卷的taskIdList<Integer> paperIds = model.getPaperItems().stream().map(d -> d.getId()).collect(Collectors.toList());examPaperMapper.updateTaskPaper(taskExam.getId(), paperIds);model.setId(taskExam.getId());}@Overridepublic TaskRequestVM taskExamToVM(Integer id) {TaskExam taskExam = taskExamMapper.selectByPrimaryKey(id);TaskRequestVM vm = modelMapper.map(taskExam, TaskRequestVM.class);TextContent textContent = textContentService.selectById(taskExam.getFrameTextContentId());List<ExamResponseVM> examResponseVMS = JsonUtil.toJsonListObject(textContent.getContent(), TaskItemObject.class).stream().map(tk -> {ExamPaper examPaper = examPaperMapper.selectByPrimaryKey(tk.getExamPaperId());ExamResponseVM examResponseVM = modelMapper.map(examPaper, ExamResponseVM.class);examResponseVM.setCreateTime(DateTimeUtil.dateFormat(examPaper.getCreateTime()));return examResponseVM;}).collect(Collectors.toList());vm.setPaperItems(examResponseVMS);return vm;}@Overridepublic List<TaskExam> getByGradeLevel(Integer gradeLevel) {return taskExamMapper.getByGradeLevel(gradeLevel);}
}
@Service
public class AuthenticationServiceImpl implements AuthenticationService {private final UserService userService;private final SystemConfig systemConfig;@Autowiredpublic AuthenticationServiceImpl(UserService userService, SystemConfig systemConfig) {this.userService = userService;this.systemConfig = systemConfig;}/*** @param username username* @param password password* @return boolean*/@Overridepublic boolean authUser(String username, String password) {User user = userService.getUserByUserName(username);return authUser(user, username, password);}@Overridepublic boolean authUser(User user, String username, String password) {if (user == null) {return false;}String encodePwd = user.getPassword();if (null == encodePwd || encodePwd.length() == 0) {return false;}String pwd = pwdDecode(encodePwd);return pwd.equals(password);}@Overridepublic String pwdEncode(String password) {return RsaUtil.rsaEncode(systemConfig.getPwdKey().getPublicKey(), password);}@Overridepublic String pwdDecode(String encodePwd) {return RsaUtil.rsaDecode(systemConfig.getPwdKey().getPrivateKey(), encodePwd);}}
<view class="exam-page"><view class="view-wrap"><view class="exam-count-down">{{remainTimeStr}}</view></view><view class="view-wrap-hidden"></view><view><view class="exam-name-title"><h1>{{form.name}}</h1></view><form bindsubmit='formSubmit'><i-panel title="{{titleItem.name}}" wx:for="{{form.titleItems}}" wx:for-item="titleItem" wx:key="{{titleItem.name}}" i-class="exam-panel-title"><i-cell-group i-class="exam-cell"><i-cell wx:for="{{titleItem.questionItems}}" wx:key="{{titleItem.id}}" wx:for-item="questionItem"><view wx:if="{{questionItem.questionType === 1}}"><rich-text nodes="{{questionItem.itemOrder}}. {{questionItem.title}}" /><radio-group class="radio-group" name="{{questionItem.itemOrder}}_{{questionItem.id}}_{{questionItem.questionType}}"><label class="radio" wx:for="{{questionItem.items}}" wx:key="{{questionItem.prefix}}" wx:for-item="radioItem" class="exam-radio-item-label"><radio color="#2d8cf0" value="{{radioItem.prefix}}" checked="{{radioItem.checked}}" class="exam-item-left" /><rich-text nodes="{{radioItem.prefix}}. {{radioItem.content}}" class="exam-item-left" /></label></radio-group></view><view wx:elif="{{questionItem.questionType === 2}}"><rich-text nodes="{{questionItem.itemOrder}}. {{questionItem.title}}" class="exam-item-left" style="line-height:35px" /><checkbox-group class="exam-item-left" style="margin-left:10px" name="{{questionItem.itemOrder}}_{{questionItem.id}}_{{questionItem.questionType}}"><label wx:for="{{questionItem.items}}" wx:key="{{questionItem.prefix}}" wx:for-item="radioItem" class="exam-radio-item-label"><checkbox color="#2d8cf0" value="{{radioItem.prefix}}" checked="{{radioItem.checked}}" class="exam-item-left" /><rich-text nodes="{{radioItem.prefix}}. {{radioItem.content}}" class="exam-item-left" /></label></checkbox-group></view><view wx:elif="{{questionItem.questionType === 3}}"><rich-text nodes="{{questionItem.itemOrder}}. {{questionItem.title}}" class="exam-item-left" style="line-height:35px" /><radio-group class="radio-group" class="exam-item-left" style="margin-left:10px" name="{{questionItem.itemOrder}}_{{questionItem.id}}_{{questionItem.questionType}}"><label class="radio" wx:for="{{questionItem.items}}" wx:key="{{questionItem.prefix}}" wx:for-item="radioItem" class="exam-radio-item-label"><radio color="#2d8cf0" value="{{radioItem.prefix}}" checked="{{radioItem.checked}}" class="exam-item-left" /><rich-text nodes="{{radioItem.content}}" class="exam-item-left" /></label></radio-group></view><view wx:elif="{{questionItem.questionType === 4}}"><rich-text nodes="{{questionItem.itemOrder}}. {{questionItem.title}}" /><view class="exam-input-contain" wx:for="{{questionItem.items}}" wx:key="{{questionItem.prefix}}" wx:for-item="inputItem" wx:for-index="idx"><view class="exam-input-contain-label">{{inputItem.prefix}}</view><input class="exam-input-contain-content" maxlength="-1" name="{{questionItem.itemOrder}}_{{questionItem.id}}_{{questionItem.questionType}}_{{idx}}" /></view></view><view wx:else><rich-text nodes="{{questionItem.itemOrder}}. {{questionItem.title}}" /><view class="exam-textarea-contain"><textarea placeholder="答案" maxlength="-1" name="{{questionItem.itemOrder}}_{{questionItem.id}}_{{questionItem.questionType}}"></textarea></view></view></i-cell></i-cell-group></i-panel><view><button class="i-btn i-btn-primary i-btn-square" form-type='submit'>提交</button></view><i-action-sheet visible="true" visible="{{timeOutShow}}" mask-closable="{{ false }}"><view slot="header" style="padding: 16px"><view class="exam-timeout-title">考试试卷结束,请提交试卷!</view><button class="i-btn i-btn-primary i-btn-square" form-type='submit'>提交</button></view></i-action-sheet></form><i-modal title="考试结果" visible="{{modalShow}}" bind:ok="returnRecord" bind:cancel="returnRecord"><view>得分:{{result}}</view></i-modal><i-spin size="large" fix wx:if="{{ spinShow }}"></i-spin><i-message id="message" /></view>
</view>
八,项目部署
8.1 目录结构
获取到源码进行解压后,文件列表如下:
8.2 导入数据库
打开Navicat(或者其他数据库连接工具也可),导入资料中的sql文件。
8.3 后端源码部署
8.3.1 导入源码
打开idea,新建工程【可以任意目录】。把解压后的xzs目录复制到创建好的idea工程中。进行导入。
导入进来之后,idea会进行编译。编译之后没有出现错误说明导入成功。
8.3.2 修改配置文件
修改数据库连接配置,在application-dev.yml配置文件中修改成自己的数据库名和自己的密码。
8.3.3 启动项目
SpringBoot的程序启动类,相信大部分小伙伴们都知道该怎么启动。不过在这里还是要写一下,以防个别小伙伴不知道。在src下找到XzsApplication启动类,在该类中进行右键运行即可。最后查看控制台有没有报错信息。没有报错信息,启动成功。
上面说明启动成功
8.4 管理员端和学生端部署
管理员端和学生端部署操作都是一样的,在这里以管理员端为例进行演示。
打开vscode【用其他前端开发工具打开也可】,导入资料中的vue目录下的xzs-admin工程,学生端是xzs-student。打开vscode的终端,进行安装依赖和启动项目。
8.4.1 安装依赖
命令:npm install
8.4.2 启动项目
命令:npm run serve
运行成功,端口号8002
8.5 小程序端部署
8.5.1 微信小程序开发工具下载与安装
开发工具的官方下载地址为:https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html。
不支持Windows XP和Windows 7系统,建议使用WIN10。我这里选择Windows 64版本的安装包。
安装过程比较简单,不用设置什么,按照提示来就行了。下面是每一步详细截图
8.5.2 项目部署
打开微信开发工具---> 选择导入--->找到资料中的wx目录,导入xzs_student
到这一步会提示,输入appId,如果自己有就写自己的,没有的话,点击测试,使用测试号
导入进来之后,会自动提示是否运行,选择【信任并运行】
运行成功 。到此整个项目部署就已经完成了
九,项目总结
该项目是PC端+小程序端。Java做为后端支持。代码结构规整,源码容易阅读,功能完善,非常适合做为毕设来使用。
微信小程序|考试系统|基于微信小程序和SpringBoot+VUE的智能在线考试系统毕业设计相关推荐
- 【项目实战】springboot+vue舞蹈课程在线学习系统-java舞蹈课程学习打卡系统的设计与实现
注意:该项目只展示部分功能,如需了解,评论区咨询即可. 本文目录 1.开发环境 2 系统设计 2.1 背景意义 2.2 技术路线 2.3 主要研究内容 3 系统页面展示 3.1 学生 3.2 教师页面 ...
- springboot vue黑板檫在线教育系统
博主介绍:✌在职Java研发工程师.专注于程序设计.源码分享.技术交流.专注于Java技术领域和毕业设计✌ 项目名称 springboot vue黑板檫在线教育系统 演示视频 springboot ...
- java基于springboot+vue的大学生在线答疑系统 elementui
社会的发展和科学技术的进步,互联网技术越来越受欢迎.网络计算机的生活方式逐渐受到广大师生的喜爱,也逐渐进入了每个学生的使用.互联网具有便利性,速度快,效率高,成本低等优点. 因此,构建符合自己要求的操 ...
- java计算机毕业设计springboot+vue青少年编程在线考试系统
项目介绍 21世纪的今天,随着社会的不断发展与进步,人们对于信息科学化的认识,已由低层次向高层次发展,由原来的感性认识向理性认识提高,管理工作的重要性已逐渐被人们所认识,科学化的管理,使信息存储达到准 ...
- 基于 SpringBoot + Vue 的智能停车场项目
下载地址:https://download.csdn.net/download/ouyangxiaobai123/20722107 项目介绍 基于 SpringBoot + Vue 的智能停车场项目 ...
- java毕业设计——基于java+JSP+sqlserver的智能在线考试信息管理系统设计与实现(毕业论文+程序源码)——智能在线考试信息管理系统
基于java+JSP+sqlserver的智能在线考试信息管理系统设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于java+JSP+sqlserver的智能在线考试信息管理系统设计与实现, ...
- 基于SpringBoot和React的在线考试平台
基于SpringBoot和React的在线考试平台-项目设计与分析 项目实战详细分析!!! 文章目录 1 系统背景和意义 1.1 系统背景 1.2 系统意义 2 系统分析 2.1 功能性需求 2.1. ...
- SSM+基于Vue框架的在线投票系统的设计与实现 毕业设计-附源码221604
基于Vue框架的在线投票系统的设计与实现 摘 要 21世纪时信息化的时代,几乎任何一个行业都离不开计算机,将计算机运用于在线投票系统也是十分常见的.过去使用手工的管理方式对在线投票系统进行管理,造成了 ...
- SSM+基于Vue框架的在线投票系统的设计与实现 毕业设计-附源码
基于Vue框架的在线投票系统的设计与实现 摘 要 21世纪时信息化的时代,几乎任何一个行业都离不开计算机,将计算机运用于在线投票系统也是十分常见的.过去使用手工的管理方式对在线投票系统进行管理,造成了 ...
最新文章
- WPF ComboBox_SelectionChange事件中获取当前文本的方法
- 生成模型与判别模型区别
- 【四重优化,速看】剑指 Offer 13. 机器人的运动范围
- Angular zone学习笔记
- P5283-[十二省联考2019]异或粽子【可持久化Trie,堆】
- 第12篇:Flowable-BPMN操作流程之用户任务UserTask
- mysql教程datetime_Mysql中的Datetime与Timestamp不同之处
- Palantir:野心贼大,想做世界的创新引擎(附纪要)| 国君计算机李沐华
- 计算机五笔教案ppt,计算机基础课件五笔打字.ppt
- 基于python的大数据分析基础及实战pdf下载_Cloudera Hadoop大数据平台实战指南 PDF 下载...
- python加粗线宽代码_python-增加matplotlib中图例行的线宽
- 使用excel分类汇总数据生成饼图
- nabcd分析解谜类rpg游戏
- python建立ARIMA模型进行时间序列分析(氵论文)
- VS2013之error C3130 内部编译器错误的解决
- 2-14-Multiple Exemplars-based Hallucination for Face Super-resolution and Editing(ACCV2020)
- 51单片机节日彩灯控制c语言,采用AT89C51单片机设计的可编程彩灯控制
- 1-甲基-3-丁基咪唑四卤化铁([C4mim]FeX4,X=Cl,Br)磁性离子液体
- open /data/prometheus: too many open files
- fastTEXT入门自然语言处理NLP