文章目录
一、项目演示
项目演示地址: 视频地址
二、项目介绍
项目描述:这是一个基于SpringBoot+Vue框架 开发的高校在线考试系统。首先,这是一个前后端分离的项目,代码简洁规范,注释说明详细,易于理解和学习。其次,这项目功能丰富,具有一个高校在线考试系统该有的所有功能。
项目功能:此项目分为三个 角色:学生 、教师 和管理员 。
学生 有登录、查看我的课程信息、查看我的考试信息、考试答题、查看我的成绩信息、查看公告信息、修改个人信息等功能。
教师 有登录、查看数据统计信息、查看学期信息、查看我的课程信息、管理我的题库信息、管理我的课程考试信息、管理我的课程成绩信息、查看公告信息和修改个人信息等功能。
管理员有登录、查看数据统计信息、管理所有学生信息、管理所有教师信息、管理所有管理员信息、管理所有教学组织信息、管理所有学期信息、管理所有课程信息、管理所有题库信息、管理所有课程考试信息、管理所有课程成绩信息和管理所有公告信息等功能。
应用技术:SpringBoot + Vue3.0 + MySQL + MyBatis + Redis + ElementUI-Plus + Vite
运行环境:IntelliJ IDEA2019.3.5 + MySQL5.7 + Redis5.0.5 + JDK1.8 + Maven3.6.3 + Node14.16.1 + Visual Studio Code(以上工具在项目压缩包中都自带)
三、运行截图






















四、主要代码
1.考试交卷代码
java
/**
* 提交考试
*
* @param examDTO
* @return
*/
@Override
public ResponseDTO<Boolean> submitExam(ExamDTO examDTO) {
if (CommonUtil.isEmpty(examDTO.getId())) {
return ResponseDTO.errorByMsg(CodeMsg.DATA_ERROR);
}
// 获取考试信息
Exam exam = examMapper.selectByPrimaryKey(examDTO.getId());
if (exam == null) {
return ResponseDTO.errorByMsg(CodeMsg.EXAM_NOT_EXIST);
}
// 获取当前登录用户(学生)
String userId = examDTO.getUserId();
if (CommonUtil.isEmpty(userId)) {
return ResponseDTO.errorByMsg(CodeMsg.DATA_ERROR);
}
User user = userMapper.selectByPrimaryKey(userId);
if (user == null) {
return ResponseDTO.errorByMsg(CodeMsg.USER_NOT_EXIST);
}
// 获取考试题目
QuestionExample questionExample = new QuestionExample();
questionExample.createCriteria().andQuestionBankIdEqualTo(exam.getQuestionBankId());
List<Question> questionList = questionMapper.selectByExample(questionExample);
// 获取学生答案
Map<String, String> answers = examDTO.getAnswers();
if (answers == null) {
answers = java.util.Collections.emptyMap();
}
// 计算成绩
int totalScore = 0;
for (Question question : questionList) {
String userAnswer = answers.get(question.getId());
String correctAnswer = question.getAnswer();
if (!CommonUtil.isEmpty(userAnswer) && !CommonUtil.isEmpty(correctAnswer)) {
// 多选题需要比较每个选项是否都正确
if (question.getType() == 2) {
// 多选题:将答案按逗号分隔并排序后比较
String[] userAnswersArray = userAnswer.split(",");
String[] correctAnswersArray = correctAnswer.split(",");
java.util.Arrays.sort(userAnswersArray);
java.util.Arrays.sort(correctAnswersArray);
if (java.util.Arrays.equals(userAnswersArray, correctAnswersArray)) {
totalScore += question.getScore();
}
} else {
// 单选题、判断题:直接比较答案
if (userAnswer.equals(correctAnswer)) {
totalScore += question.getScore();
}
}
}
}
// 计算用时(分钟)
Integer timeUsed = examDTO.getTimeUsed();
if (timeUsed == null) {
timeUsed = 0;
}
// 计算获得学分(60分以上获得学分)
int earnedScore = totalScore >= 60 ? 3 : 0;
// 创建成绩记录
Score score = new Score();
score.setId(UuidUtil.getShortUuid());
score.setUserId(userId);
score.setCourseId(exam.getCourseId());
score.setExamId(exam.getId());
score.setScore(totalScore);
score.setTimeUsed(timeUsed);
score.setRank(0); // 排名稍后统一计算
score.setEarnedScore(earnedScore);
// 保存成绩
int result = scoreMapper.insert(score);
if (result <= 0) {
return ResponseDTO.errorByMsg(CodeMsg.SCORE_SAVE_ERROR);
}
// 提交考试后,重新计算该考试所有学生的排名
scoreService.updateRankByExamId(exam.getId());
return ResponseDTO.successByMsg(true, "提交成功!您的成绩是:" + totalScore + "分");
}
2.保存题库信息代码
java
/**
* 保存题库信息
*
* @param questionBankDTO
* @return
*/
@Override
public ResponseDTO<Boolean> saveQuestionBank(QuestionBankDTO questionBankDTO) {
CodeMsg validate = ValidateEntityUtil.validate(questionBankDTO);
if (!validate.getCode().equals(CodeMsg.SUCCESS.getCode())) {
return ResponseDTO.errorByMsg(validate);
}
QuestionBank questionBank = CopyUtil.copy(questionBankDTO, QuestionBank.class);
if (CommonUtil.isEmpty(questionBank.getId())) {
questionBank.setId(UuidUtil.getShortUuid());
if (questionBankMapper.insertSelective(questionBank) == 0) {
return ResponseDTO.errorByMsg(CodeMsg.QUESTION_BANK_ADD_ERROR);
}
} else {
if (questionBankMapper.updateByPrimaryKeySelective(questionBank) == 0) {
return ResponseDTO.errorByMsg(CodeMsg.QUESTION_BANK_EDIT_ERROR);
}
}
return ResponseDTO.successByMsg(true, "保存成功!");
}
3.用户登录代码
java
/**
* 用户登录操作
*
* @param userDTO
* @return
*/
@Override
public ResponseDTO<UserDTO> login(UserDTO userDTO) {
// 进行是否为空判断
if (CommonUtil.isEmpty(userDTO.getNo())) {
return ResponseDTO.errorByMsg(CodeMsg.NO_EMPTY);
}
if (CommonUtil.isEmpty(userDTO.getPassword())) {
return ResponseDTO.errorByMsg(CodeMsg.PASSWORD_EMPTY);
}
// 对比学号/学工号和密码是否正确
UserExample userExample = new UserExample();
userExample.createCriteria().andNoEqualTo(userDTO.getNo()).andPasswordEqualTo(userDTO.getPassword())
.andRoleIdEqualTo(userDTO.getRoleId());
List<User> userList = userMapper.selectByExample(userExample);
if (userList == null || userList.size() != 1) {
return ResponseDTO.errorByMsg(CodeMsg.NO_PASSWORD_ERROR);
}
// 生成登录token并存入Redis中
UserDTO selectedUserDto = CopyUtil.copy(userList.get(0), UserDTO.class);
String token = UuidUtil.getShortUuid();
selectedUserDto.setToken(token);
// 把token存入redis中 有效期1小时
stringRedisTemplate.opsForValue().set("USER_" + token, JSON.toJSONString(selectedUserDto), 3600,
TimeUnit.SECONDS);
return ResponseDTO.successByMsg(selectedUserDto, "登录成功!");
}