基于SpringBoot+Vue的智能在线考试系统的设计与实现

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 基于SpringBoot+Vue的智能在线考试系统的设计与实现

项目编号:BS-GX-064

前言:

随着计算机及网络技术的飞速发展,Intranet应用在全球范围内日益普及,当今社会正快速向信息化社会前进,信息自动化的作用也越来越大。目前存在各级各类的考试,而它们的各种工作主要还是依赖于手工完成,比如考试的报名,需要考生到指定的地点按照先后顺序完成,不仅手续复杂麻烦,而且工作效率很低,还会受到天气、交通等等各种因素的影响。手工管理还存在这许多弊端,由于不可避免的人为因素,造成数据的遗漏、误报。计算机信息化管理有着储存量大,速度快等许多优点,提供给我们的处理信息及时快捷。

本系统基于SpringBoot框架,采用B/S模式进行设计,前端页面使用Vue.js开发,使用MySQL作为数据库。使用IDEA作为前后端开发工具,使用mybatis对数据库进行交互操作,作为数据库管理工具。

在线考试可以省去试卷印刷的费用,减轻老师阅卷、成绩统计的负担,节约了教育资源,加快了考试进程,还可以充分发挥计算机在信息处理方面的优势,例如建立海量的题库随机出题,对试题、考试结果进行分析等等,既节省了人力、物力、财力,提高了劳动效率。在线考试系统远远超越了传统考试的固定时间,固定地点的考试模式的限制,将给学生和老师带来极大的便利。在线考试可以省去试卷印刷的费用,减轻老师阅卷、成绩统计的负担,节约了教育资源,加快了考试进程,还可以充分发挥计算机在信息处理方面的优势,例如建立海量的题库随机出题,对试题、考试结果进行分析等等,既节省了人力、物力、财力,提高了劳动效率。

一,环境介绍

语言环境:Java:  jdk1.8

数据库:Mysql: mysql5.7

应用服务器:Tomcat:  tomcat8.5.31

开发工具:IDEA或eclipse

开发技术:Springboot+Vue

二,项目简介

随着计算机技术、网络技术的不断发展,利用计算机来辅助教学提高教育质量是未来发展的必然趋势。计算机深入到日常工作和生活的方方面面,是我们学习和工作的得力助手。各行各业的人们都在使用计算机完成许许多多复杂的工作。今天,我们使用计算机研究智能在线考试系统,为许多高校学子和老师搭建一个便利的平台。考试系统是一个教育单位不可缺少的部分,但一直以来人们使用传统人工纸质的方式来考试测评,这种考试测评方式存在着许多弊端,如:效率低、保密性差,时间过长,将产生大量的文件和数据,这对于批改、查找、更新和维护考试试卷都带来了不少困难。而使用计算机对学生考试,具有纸质考试不能达到的优势。查找方便、可靠性高、保密性好、寿命长等等这些优点能够极大的提高学生考试的效率。当然,考试系统使用计算机也存在一些弊端,研究教考分离的考试系统开发和设计过程中,我们也需要尽可能减少弊端所带来的影响。

本课题的研究内容是开发设计一个用于高等院校的教考分离考试系统,使得老师和学生可以通过网络进行在线考试、进行学习评价。

本文旨在设计与开发一套基于Springboot的智能在线考试系统,详细分析了智能在线考试系统的架构,确立了各个模块之间的关系,对题库管理、科目管理、组卷管理、考试功能、判卷功能、成绩管理等功能模块进行的分析、设计、实现、测试完成了一整套的智能在线考试系统。

本系统设计了两种用户角色:管理员(老师)角色和考生(学生)角色。管理员可以进入后台管理界面对其后台进行用用户管理、卷题管理、任务管理,学科管理、成绩管理、消息中心的发送、日志中心的管理等,学生自然就是进入学生界面,进行相应的考试、在线答题、查看错题集等操作。该系统的功能模块图如图3-1所示。

图3-1系统功能模块图

考生可以使用进行试卷的答题,可以做练习、可以查看试卷、可以考完之后翻阅自己的考试成绩,也就是相关的考试记录、系统收集了该学生的错题集,学生也可以进行错题的查看,用户功能用例图如图3-2所示。

图3-2 用户功能用例图

管理员通过系统内置的账户登录,管理员账户对后台可以进行用户管理、卷题管理、任务管理、教育管理、成绩管理、消息中心的发送和日志中心的查看等。管理员功能用例图如图3-3所示。

图3-3 管理员功能用例图

本系统有用户模块、登录注册模块、考试功能模块、存储模块、消息推送模块、搜索模块与后台管理模块等7个功能模块,其主要功能分析如下:

1.用户模块功能

表3-1 用户模块功能描述

功能名称

功能描述

用户注册

用户进该考试系统先注册

查看个人信息

用户对自己信息的修改,如头像修改等

修改密码

修改用户的登录密码

查看消息

显示其他用户发来的一系列消息

2.登录注册模块

表3-2 登录注册模块功能描述

功能名称

功能描述

角色登录

用户登录进入前台界面,管理员登录进入后台

注册

用户需要注册,管理有特定的账号

3.考试功能模块

表3-3 考试功能模块功能描述

功能名称

功能描述

发布试卷

管理员发布考试试卷

学科列表

发布考试学科种类,如数学或英语

考试种类

平常练习试卷与定期发布试卷

考生考试

考生收到消息进行考试

考生练习

考生可以练习老师平常发的练习试卷

4.存储模块

表3-4 存储模块功能描述

功能名称

功能描述

在线存储

利用七牛云在线存储

5.消息推送模块

表3-5 消息推送模块功能描述

功能名称

功能描述

消息发送

管理员发布消息给用户,进行考试信息的通知

消息接收

用户能接收到管理员发来的信息通知

6.搜索模块

表3-6 搜索模块功能描述

功能名称

功能描述

关键字搜索

以分析贴标题为关键词搜索对应内容

7.后台管理模块

表3-7 后台管理模块功能描述

功能名称

功能描述

角色管理

对学生和管理员列表信息进行修改与管理

组卷管理

对试卷进行发布

任务管理

可以对任务列表进行修改,也可以进行任务创建

科目管理

对学科列表信息进行修改与管理

成绩管理

可以对考生成绩的查询

题库管理

可以出题,查询题目分类,题目发布

消息中心

对消息列表进行修改,可以进行消息发送

8.推荐模块

表3-8 后台管理模块功能描述

功能名称

功能描述

用户管理

用户信息管理。查询,修改以及禁用用户

分享帖管理

查找并修改、或者删除平台中的分享帖

通知管理

用于发布新通知,修改以及删除现有通知

举报管理

查看并处理用户提交的举报信息

3.2.2 性能需求

本系统基于B/S架构,用户通过浏览器访问获取服务,为了保证用户体验,需要较为稳定的性能。

1.数据精确度

后端程序在执行数据的增加、删除、修改操作时,不支持因为程序原因导致操作失败;

后端程序在进行数据增加时,不支持发生多增加或重复增加的情况;

后端程序在进行数据删除时,不支持发生多删除数据;

后端程序在进行数据删除时,对有关联的数据要求删除完全,如不能删除,请给予提示;

后端程序在执行数据修改时,也需要保持对应的准确性。

时间特性:

执行增加删除等操作时,数据库响应时间要求在2秒之内;

登录注册响应时间<=3秒;

网页刷新响应时间<=2秒;

数据渲染响应时间<=0.5秒;

数据刷新响应时间<=0.5秒;

查询分享帖响应时间<=1秒;

热门推荐响应时间<=1秒;

2.安全性

后端服务器要求建立安全可靠的防火墙;

确保后端服务器服务的安全性,禁止匿名访问服务;

对于数据库中的考生(学生)或管理员(老师)的密码数据,需要进行MD5加密。

3.支持软件

(1)客户端软件:

操作系统:Linux、Windows 7/10;

浏览器:Chrome、Fire Fox、Edge。

(2)服务端软件:

操作系统:Windows Server 2012/2016、Windows 7/10、Linux;

Java版本: 1.8;

数据库版本:MySQL5.7以上版本;

功能与服务:七牛云存储服务。

三,系统展示

5.1 用户模块

5.1.1 注册与登录

前端登录与注册页面由login.vue实现,用户信息由userInfo.vue实现。用户首先需要输入用户名和邮箱,之后点击发送验证码,前端会将用户名和邮箱通过/api/sendCode提交到后端。后端接受到数据之后,首先会验证邮箱是否符合格式,邮箱是否已经被注册,如果条件成立,则返回相关提示信息。否则将生成验证码,通过邮件发送至用户邮箱,同时将邮箱和验证码存储于session中。之后用户需要将其他信息填写完毕,并且输入验证码,点击注册,前端会通过/api/register接口将数据提交到后端。后端收到数据后,首先会通过提交信息的邮箱从session中读取之前存储的验证码并进行对比,如果不一致,则返回验证码无效提示信息,否则继续业务。之后会验证邮箱是否符合规范,以及是否被注册,如果验证通过,则后端调用服务层类userService的register方法添加用户,register方法首先会将用户的密码进行MD5加密,填充注册时间,用户状态等信息,然后通过持久层类userMapper的方法将用户信息提交至数据库。提交成功之将创建用户的文件仓库,通过调用fileStoreService的 createFileStore方法创建对应用户的文件仓库并提交到数据库。界面实现效果如图5-1所示。

完成注册之后用户就可以登录了。输入用户名和密码之后点击登录,前端会将携带用户名与密码通过/api/login接口提交至后端,后端调用服务层类userService的login方法来处理数据。首先会将用户的明文密码使用MD5加密,之后通过持久层类userMapper的方法去数据库中查询是否存在对应用户名的用户,然后对比密码是否正确,并返回相应结果至控制层。如果账户密码正确,则将查询到的用户数据存储于session中,并且生成token提交至数据库中。之后将提示信息与token返回至前端,前端会将token存储于cookie中,以保持登录状态。界面实现效果如图5-2所示。

用户完成登录之后,将跳转至网盘界面,同时通过/api/getTokenVerity接口验证token是否有效,然后通过/api/getLoggedUser接口向后端的session中获取当前登录用户信息,并存储于cookie中。

图5-1 注册界面

图5-2 登录界面

5.1.2 个人信息

用户信息页面由userinfo.vue实现。登入系统之后,用户可以通过右上角下拉菜单进入用户信息页面。前端会携带登录用户信息,通过/api/u/getUser接口向后端请求当前用户信息,前端返回信息之后会将用户信息渲染至页面上。界面实现效果如图5-3所示。

图5-3 个人信息界面

5.1.3 查看消息

修改密码需要输入原密码和新密码,点击确定之后前端会通过/api/u/ resetPass接口向后端发送请求,携带用户ID和新旧密码。后端收到请求之后会调用服务层类userService的resetPass方法来处理业务。首先会判断原密码是否正确,然后检查新旧密码是否一致,如果一致则返回提示信息,否则将新密码使用MD5加密之后提交至数据库,然后向前端返回成功更改提示信息。界面实现效果如图5-4所示。

图5-4 查看信息界面

5.2 登录模块

5.2.1 角色登录

网盘界面由files.vue实现。用户登入之后会跳转至网盘界面,用户可在此查看网盘内的文件并进行管理。点击文件夹即可查看对应文件夹,前端会向/api/f/getDir接口发出请求,携带文件仓库与目标文件夹参数,后端获取对应文件夹下目录的数据返回至前端,前端根据后端的数据重新渲染目录,并记录用户当前路径信息。点击上一级或根目录按钮,前端会读取存储的路径信息,通过/api/f/getDir接口向后端请求对应目录的数据并再次渲染,以返回上一级目录。界面实现效果如图5-7所示。

图5-5用户登录前台界面

图5-6 管理员登录后台界面

5.3 考试功能模块

5.3.1 发布试卷

回收站模块同样由files.vue实现用户在网盘界面删除的文件并非被真的删除了,而是移动到了回收站,这里展示的是用户文件仓库中,所有被标记为删除的文件与文件夹。选择一个或多个文件及文件夹之后,即可执行还原操作。

点击还原文件按钮后会显示路径选择窗口,选择文件夹存放的目录然后点击确定后前端调用/api/rf/recovery接口发送请求,将被还原的文件及文件夹信息传递至后端,后端调用服务层类recycleBinService的recycleOrRecovery方法处理业务。根据请求携带的文件及文件夹信息分别处理,首先与还原文件及文件夹数据的名称进行对比,若存在重名则返回提示信息,否则将对应文件对象重新设置为未回收状态并设置文件的新路径。而文件夹则会通过recycleFoldersFile方法并设置为还原模式进行进一步操作,以还原文件夹下所有的子文件夹以及文件。界面实现效果如图5-11所示。

图5-7发布试卷页面

5.3.2 学科列表

选择选择一个或多个文件及文件夹之后,即可删除选择的文件或文件夹,而清空操作则是直接删除对回收站下的所有文件。在回收站执行的删除的操作会删除FTP上的文件,彻底从系统中移除本文件。删除文件和清空回收站都调用/api/f/delete接口,如果执行删除操作,前端会将选择的文件及文件夹信息通过此接口发送的后端,如果是清空操作,前端则会将回收站所有的文件信息传递至后端。后端接受到请求与文件信息之后对文件及文件夹进行分别处理,文件夹通过调用服务层folderService类删除数据库信息。文件则调用服务层fileService类deleteFTPFIle方法进行处理。因为FTP上的一个物理文件很可能在逻辑上关联了多条数据库信息,如果贸然删除FTP上的物理文件可能导致其他保存了次文件的用户将无法下载该文件,所以deleteFTPFIle方法在删除文件之前首先会检查该文件是否有多个关联数据库条目。进入deleteFTPFIle方法后,首先通过文件ID获取文件对象,之后通过文件对象的FTP地址从数据库中查询文件,再通过文件ID从数据库中查找分享帖,如果查到到相同FTP路径的文件大于1,以及查找到存在分享此文件的分享帖,则仅从数据库中删除数据库信息,否则调用FtpUtil类删除FTP文件。

图5-7学科列表页面

5.3.3 考试种类

选择选择一个或多个文件及文件夹之后,即可删除选择的文件或文件夹,而清空操作则是直接删除对回收站下的所有文件。在回收站执行的删除的操作会删除FTP上的文件,彻底从系统中移除本文件。删除文件和清空回收站都调用/api/f/delete接口,如果执行删除操作,前端会将选择的文件及文件夹信息通过此接口发送的后端,如果是清空操作,前端则会将回收站所有的文件信息传递至后端。后端接受到请求与文件信息之后对文件及文件夹进行分别处理,文件夹通过调用服务层folderService类删除数据库信息。文件则调用服务层fileService类deleteFTPFIle方法进行处理。因为FTP上的一个物理文件很可能在逻辑上关联了多条数据库信息,如果贸然删除FTP上的物理文件可能导致其他保存了次文件的用户将无法下载该文件,所以deleteFTPFIle方法在删除文件之前首先会检查该文件是否有多个关联数据库条目。进入deleteFTPFIle方法后,首先通过文件ID获取文件对象,之后通过文件对象的FTP地址从数据库中查询文件,再通过文件ID从数据库中查找分享帖,如果查到到相同FTP路径的文件大于1,以及查找到存在分享此文件的分享帖,则仅从数据库中删除数据库信息,否则调用FtpUtil类删除FTP文件。

图5-8练习试卷页面

图5-9时段页面

5.7 后台管理模块

后台管理模块为系统管理员提供了对系统中数据进行查询与管理的平台。后台管理页面仅对管理员用户开放,管理用用户即用户等级为9的用户。用户查看此页面以及子页面时,前端会通过/api/a/verityUserLevel接口携带当前用户ID向后端验证用户是否为管理员,然后才允许继续操作。否则跳转回登录页面。

5.7.1 角色管理

用户管理由userManage.vue实现。此页面用于对系统中的用户账户进行查询与管理。当管理员进入用户管理页面,前端首先会通过/api/a/getAll接口向后端发送请求,以获取所有的用户账户数据并返回至前端,前端收到数据之后分页渲染。界面实现效果如图5-20所示。

管理员可以通过页面操作按钮来查看用户信息,也可以通过搜索栏来查找指定用户的信息。在搜索栏中输入用户名,点击查找,前端便会通过/api/a/getUserByKeyWord接口将关键词传递至后端,后端接受请求之之后将查找到的数据返回至前端,前端再将数据渲染到页面上。

当管理点击新增按钮就会显示添加用户窗口,管理员填写完相关数据之后,点击确认,前端就会将该数据通过/api/a/addUser接口提交到数据库中。点击编辑按钮会打开与添加用户窗口一致的编辑用户窗口,前端会自动将被编辑用户的数据填入输入框,管理员只需更改需要更改的数据即可,点击提交前端会通过/api/a/updateUser接口将数据更新至数据库中。以上操作完成后,后端会返回成功信息至前端,前端再次获取更新后的用户数据并渲染用户信息列表。界面实现效果如图5-21所示。

当管理员点击某个用户账户信息上的禁用按钮时,前端会弹出提示框,询问管理员是否进行操作,点击确定,前端便会通过/api/a/UpdateStatus/接口禁用此账户。禁用后,该用户就无法使用此账户来登录系统。

图5-20 角色管理界面

5.7.2 组卷管理

分享管理由postsManage.vue实现分享管理页面用于管理系统中的分享帖。当管理员进入本页面,前端首先会通过/api/a/getAllPosts接口获取所有分享帖的数据,然后渲染到页面上。

此页面也提供了按照用户昵称来检索其对应分享帖的功能,在搜索栏输入用户昵称然后点击搜索,前端就会/api/a/searchPosts接口携带搜索内容传递至后端,后端接收请求后查找数据库中的对应内容,并返回至前端。前端收到数据之后渲染到页面上。界面实现效果如图5-22所示。

分享帖以列表形式分页展现在页面上,管理员可以通过点击帖子标题进入对应分享帖。或者点击编辑以及删除按钮对该帖子进行操作。点击编辑按钮时,会显示帖子编辑窗口,前端会将该帖子的对应数据自动填入输入框内。管理员编辑完成之后,点击确定按钮前端就会通过/api/a/edit接口,将帖子数据传递至后端,后端接受数据后提交至数据库,然后返回成功信息至前端,前端再次请求新的帖子信息并渲染至页面上。界面实现效果如图5-23所示。

点击删除按钮,前端会通过/api/a/deletePosts接口携带帖子ID发送请求到后端,后端在收到请求后,会通过帖子ID获取具体的帖子对象,然后将帖子对象的被删除属性设置为真。然后通过服务层方法类noticeServer的addNotice方法对被删除帖子的发帖子发送帖子被删除的通知。然后将被修改的帖子对象存入数据库并返回成功信息至前端。前端收到成功信息之后再次获取所有帖子信息更新当前页面。

图5-22 组卷管理页面

图5-23 帖子编辑窗口

四,核心代码展示

package com.zlf.exam.controller.student;
import com.zlf.exam.base.BaseApiController;
import com.zlf.exam.base.RestResponse;
import com.zlf.exam.domain.TaskExam;
import com.zlf.exam.domain.TaskExamCustomerAnswer;
import com.zlf.exam.domain.TextContent;
import com.zlf.exam.domain.User;
import com.zlf.exam.domain.enums.ExamPaperTypeEnum;
import com.zlf.exam.domain.task.TaskItemAnswerObject;
import com.zlf.exam.domain.task.TaskItemObject;
import com.zlf.exam.service.*;
import com.zlf.exam.utility.DateTimeUtil;
import com.zlf.exam.utility.JsonUtil;
import com.zlf.exam.viewmodel.student.dashboard.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@RestController("StudentDashboardController")
@RequestMapping(value = "/api/student/dashboard")
public class DashboardController extends BaseApiController {
    private final UserService userService;
    private final ExamPaperService examPaperService;
    private final QuestionService questionService;
    private final TaskExamService taskExamService;
    private final TaskExamCustomerAnswerService taskExamCustomerAnswerService;
    private final TextContentService textContentService;
    @Autowired
    public DashboardController(UserService userService, ExamPaperService examPaperService, QuestionService questionService, TaskExamService taskExamService, TaskExamCustomerAnswerService taskExamCustomerAnswerService, TextContentService textContentService) {
        this.userService = userService;
        this.examPaperService = examPaperService;
        this.questionService = questionService;
        this.taskExamService = taskExamService;
        this.taskExamCustomerAnswerService = taskExamCustomerAnswerService;
        this.textContentService = textContentService;
    }
    @RequestMapping(value = "/index", method = RequestMethod.POST)
    public RestResponse<IndexVM> index() {
        IndexVM indexVM = new IndexVM();
        User user = getCurrentUser();
        PaperFilter fixedPaperFilter = new PaperFilter();
        fixedPaperFilter.setGradeLevel(user.getUserLevel());
        fixedPaperFilter.setExamPaperType(ExamPaperTypeEnum.Fixed.getCode());
        indexVM.setFixedPaper(examPaperService.indexPaper(fixedPaperFilter));
        PaperFilter timeLimitPaperFilter = new PaperFilter();
        timeLimitPaperFilter.setDateTime(new Date());
        timeLimitPaperFilter.setGradeLevel(user.getUserLevel());
        timeLimitPaperFilter.setExamPaperType(ExamPaperTypeEnum.TimeLimit.getCode());
        List<PaperInfo> limitPaper = examPaperService.indexPaper(timeLimitPaperFilter);
        List<PaperInfoVM> paperInfoVMS = limitPaper.stream().map(d -> {
            PaperInfoVM vm = modelMapper.map(d, PaperInfoVM.class);
            vm.setStartTime(DateTimeUtil.dateFormat(d.getLimitStartTime()));
            vm.setEndTime(DateTimeUtil.dateFormat(d.getLimitEndTime()));
            return vm;
        }).collect(Collectors.toList());
        indexVM.setTimeLimitPaper(paperInfoVMS);
        return RestResponse.ok(indexVM);
    }
    @RequestMapping(value = "/task", method = RequestMethod.POST)
    public RestResponse<List<TaskItemVm>> task() {
        User user = getCurrentUser();
        List<TaskExam> taskExams = taskExamService.getByGradeLevel(user.getUserLevel());
        if (taskExams.size() == 0) {
            return RestResponse.ok(new ArrayList<>());
        }
        List<Integer> tIds = taskExams.stream().map(taskExam -> taskExam.getId()).collect(Collectors.toList());
        List<TaskExamCustomerAnswer> taskExamCustomerAnswers = taskExamCustomerAnswerService.selectByTUid(tIds, user.getId());
        List<TaskItemVm> vm = taskExams.stream().map(t -> {
            TaskItemVm itemVm = new TaskItemVm();
            itemVm.setId(t.getId());
            itemVm.setTitle(t.getTitle());
            TaskExamCustomerAnswer taskExamCustomerAnswer = taskExamCustomerAnswers.stream()
                    .filter(tc -> tc.getTaskExamId().equals(t.getId())).findFirst().orElse(null);
            List<TaskItemPaperVm> paperItemVMS = getTaskItemPaperVm(t.getFrameTextContentId(), taskExamCustomerAnswer);
            itemVm.setPaperItems(paperItemVMS);
            return itemVm;
        }).collect(Collectors.toList());
        return RestResponse.ok(vm);
    }
    private List<TaskItemPaperVm> getTaskItemPaperVm(Integer tFrameId, TaskExamCustomerAnswer taskExamCustomerAnswers) {
        TextContent textContent = textContentService.selectById(tFrameId);
        List<TaskItemObject> paperItems = JsonUtil.toJsonListObject(textContent.getContent(), TaskItemObject.class);
        List<TaskItemAnswerObject> answerPaperItems = null;
        if (null != taskExamCustomerAnswers) {
            TextContent answerTextContent = textContentService.selectById(taskExamCustomerAnswers.getTextContentId());
            answerPaperItems = JsonUtil.toJsonListObject(answerTextContent.getContent(), TaskItemAnswerObject.class);
        }
        List<TaskItemAnswerObject> finalAnswerPaperItems = answerPaperItems;
        return paperItems.stream().map(p -> {
                    TaskItemPaperVm ivm = new TaskItemPaperVm();
                    ivm.setExamPaperId(p.getExamPaperId());
                    ivm.setExamPaperName(p.getExamPaperName());
                    if (null != finalAnswerPaperItems) {
                        finalAnswerPaperItems.stream()
                                .filter(a -> a.getExamPaperId().equals(p.getExamPaperId()))
                                .findFirst()
                                .ifPresent(a -> {
                                    ivm.setExamPaperAnswerId(a.getExamPaperAnswerId());
                                    ivm.setStatus(a.getStatus());
                                });
                    }
                    return ivm;
                }
        ).collect(Collectors.toList());
    }
}
package com.zlf.exam.controller.student;
import com.github.pagehelper.PageInfo;
import com.zlf.exam.base.BaseApiController;
import com.zlf.exam.base.RestResponse;
import com.zlf.exam.domain.Message;
import com.zlf.exam.domain.MessageUser;
import com.zlf.exam.domain.User;
import com.zlf.exam.domain.UserEventLog;
import com.zlf.exam.domain.enums.RoleEnum;
import com.zlf.exam.domain.enums.UserStatusEnum;
import com.zlf.exam.event.UserEvent;
import com.zlf.exam.service.AuthenticationService;
import com.zlf.exam.service.MessageService;
import com.zlf.exam.service.UserEventLogService;
import com.zlf.exam.service.UserService;
import com.zlf.exam.utility.DateTimeUtil;
import com.zlf.exam.utility.PageInfoHelper;
import com.zlf.exam.viewmodel.student.user.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@RestController("StudentUserController")
@RequestMapping(value = "/api/student/user")
public class UserController extends BaseApiController {
    private final UserService userService;
    private final UserEventLogService userEventLogService;
    private final MessageService messageService;
    private final AuthenticationService authenticationService;
    private final ApplicationEventPublisher eventPublisher;
    //后台登录代码
    @Autowired
    public UserController(UserService userService, UserEventLogService userEventLogService, MessageService messageService, AuthenticationService authenticationService, ApplicationEventPublisher eventPublisher) {
        this.userService = userService;
        this.userEventLogService = userEventLogService;
        this.messageService = messageService;
        this.authenticationService = authenticationService;
        this.eventPublisher = eventPublisher;
    }
    @RequestMapping(value = "/current", method = RequestMethod.POST)
    public RestResponse<UserResponseVM> current() {
        User user = getCurrentUser();
        UserResponseVM userVm = UserResponseVM.from(user);
        return RestResponse.ok(userVm);
    }
    //后台注册代码
    @RequestMapping(value = "/register", method = RequestMethod.POST)
    public RestResponse register(@RequestBody @Valid UserRegisterVM model) {
        User existUser = userService.getUserByUserName(model.getUserName());
        if (null != existUser) {
            return new RestResponse<>(2, "用户已存在");
        }
        User user = modelMapper.map(model, User.class);
        String encodePwd = authenticationService.pwdEncode(model.getPassword());
        user.setUserUuid(UUID.randomUUID().toString());
        user.setPassword(encodePwd);
        user.setRole(RoleEnum.STUDENT.getCode());
        user.setStatus(UserStatusEnum.Enable.getCode());
        user.setLastActiveTime(new Date());
        user.setCreateTime(new Date());
        user.setDeleted(false);
        userService.insertByFilter(user);
        UserEventLog userEventLog = new UserEventLog(user.getId(), user.getUserName(), user.getRealName(), new Date());
        userEventLog.setContent("欢迎 " + user.getUserName() + " 注册来到在线考试系统");
        eventPublisher.publishEvent(new UserEvent(userEventLog));
        return RestResponse.ok();
    }
    //后台个人信息更新代码
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    public RestResponse update(@RequestBody @Valid UserUpdateVM model) {
        if (StringUtils.isBlank(model.getBirthDay())) {
            model.setBirthDay(null);
        }
        User user = userService.selectById(getCurrentUser().getId());
        modelMapper.map(model, user);
        user.setModifyTime(new Date());
        userService.updateByIdFilter(user);
        UserEventLog userEventLog = new UserEventLog(user.getId(), user.getUserName(), user.getRealName(), new Date());
        userEventLog.setContent(user.getUserName() + " 更新了个人资料");
        eventPublisher.publishEvent(new UserEvent(userEventLog));
        return RestResponse.ok();
    }
    @RequestMapping(value = "/log", method = RequestMethod.POST)
    public RestResponse<List<UserEventLogVM>> log() {
        User user = getCurrentUser();
        List<UserEventLog> userEventLogs = userEventLogService.getUserEventLogByUserId(user.getId());
        List<UserEventLogVM> userEventLogVMS = userEventLogs.stream().map(d -> {
            UserEventLogVM vm = modelMapper.map(d, UserEventLogVM.class);
            vm.setCreateTime(DateTimeUtil.dateFormat(d.getCreateTime()));
            return vm;
        }).collect(Collectors.toList());
        return RestResponse.ok(userEventLogVMS);
    }
    @RequestMapping(value = "/message/page", method = RequestMethod.POST)
    public RestResponse<PageInfo<MessageResponseVM>> messagePageList(@RequestBody MessageRequestVM messageRequestVM) {
        messageRequestVM.setReceiveUserId(getCurrentUser().getId());
        PageInfo<MessageUser> messageUserPageInfo = messageService.studentPage(messageRequestVM);
        List<Integer> ids = messageUserPageInfo.getList().stream().map(d -> d.getMessageId()).collect(Collectors.toList());
        List<Message> messages = ids.size() != 0 ? messageService.selectMessageByIds(ids) : null;
        PageInfo<MessageResponseVM> page = PageInfoHelper.copyMap(messageUserPageInfo, e -> {
            MessageResponseVM vm = modelMapper.map(e, MessageResponseVM.class);
            messages.stream().filter(d -> e.getMessageId().equals(d.getId())).findFirst().ifPresent(message -> {
                vm.setTitle(message.getTitle());
                vm.setContent(message.getContent());
                vm.setSendUserName(message.getSendUserName());
            });
            vm.setCreateTime(DateTimeUtil.dateFormat(e.getCreateTime()));
            return vm;
        });
        return RestResponse.ok(page);
    }
    @RequestMapping(value = "/message/unreadCount", method = RequestMethod.POST)
    public RestResponse unReadCount() {
        Integer count = messageService.unReadCount(getCurrentUser().getId());
        return RestResponse.ok(count);
    }
    @RequestMapping(value = "/message/read/{id}", method = RequestMethod.POST)
    public RestResponse read(@PathVariable Integer id) {
        messageService.read(id);
        return RestResponse.ok();
    }
}

五,项目总结


相关文章
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
111 62
|
4天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
39 13
|
12天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
1月前
|
XML Java 数据库连接
SpringBoot集成Flowable:打造强大的工作流管理系统
在企业级应用开发中,工作流管理是一个核心组件,它能够帮助我们定义、执行和管理业务流程。Flowable是一个开源的工作流和业务流程管理(BPM)平台,它提供了强大的工作流引擎和建模工具。结合SpringBoot,我们可以快速构建一个高效、灵活的工作流管理系统。本文将探讨如何将Flowable集成到SpringBoot应用中,并展示其强大的功能。
155 1
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
75 2
|
1月前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
2月前
|
存储 安全 Java
打造智能合同管理系统:SpringBoot与电子签章的完美融合
【10月更文挑战第7天】 在数字化转型的浪潮中,电子合同管理系统因其高效、环保和安全的特点,正逐渐成为企业合同管理的新宠。本文将分享如何利用SpringBoot框架实现一个集电子文件签字与合同管理于一体的智能系统,探索技术如何助力合同管理的现代化。
104 4
|
2月前
|
前端开发 Java Apache
SpringBoot实现电子文件签字+合同系统!
【10月更文挑战第15天】 在现代企业运营中,合同管理和电子文件签字成为了日常活动中不可或缺的一部分。随着技术的发展,电子合同系统因其高效性、安全性和环保性,逐渐取代了传统的纸质合同。本文将详细介绍如何使用SpringBoot框架实现一个电子文件签字和合同管理系统。
95 1
|
2月前
|
文字识别 安全 Java
SpringBoot3.x和OCR构建车牌识别系统
本文介绍了一个基于Java SpringBoot3.x框架的车牌识别系统,详细阐述了系统的设计目标、需求分析及其实现过程。利用Tesseract OCR库和OpenCV库,实现了车牌图片的识别与处理,确保系统的高准确性和稳定性。文中还提供了具体的代码示例,展示了如何构建和优化车牌识别服务,以及如何处理特殊和异常车牌。通过实际应用案例,帮助读者理解和应用这一解决方案。
|
1月前
|
JavaScript NoSQL Java
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
43 0