修改了contrellon文件夹

main
hunqiu 3 hours ago
parent ffe9f1c9bd
commit b4a34f3397

@ -1,108 +1,18 @@
# spring-boot-online-exam
> 在线Demo预览http://129.211.88.191 账户分别是admin、teacher、student密码是admin123。视频讲解代码https://www.bilibili.com/video/BV1FP4y1L7xt/
> 好消息一个小伙伴做了Python实现欢迎大家starhttps://github.com/xingxingzaixian/django-drf-online-exam
## 1.快速体验
### 1.1 事先准备
> clone代码并进入代码路径
```shell
git clone git@github.com:lsgwr/spring-boot-online-exam.git
cd spring-boot-online-exam
```
下面按照Linux和windows说明快速搭建的方法
### 1.2 Linux
执行代码下的脚本start.sh即可
然后访问 http://ip:80 即可访问自己搭建的考试系统
### 1.3 windows
+ 1.安装JDK推荐JDK8
+ 2.从官方仓库下载发布的jar包建议选择最新版https://github.com/lsgwr/spring-boot-online-exam/releases
+ 3.安装MySQL创建数据库exam并初始化密码为aA111111导入doc/sql/exam.sql文件来创建数据库
+ 4.启动jar包`java -jar exam.jar`
+ 5.访问http://ip:9527 即可访问自己搭建的考试系统
## 2.介绍
基于springboot的在线考试系统
### 2.1 功能简介
+ 支持单选题、多选题、判断题
+ 支持学生(student)、教师(teacher)、管理员(admin)三种角色
+ 学生:参加考试和查看我的考试
+ 教师:学生的所有权限+创建/编辑题目+创建/编辑考试
+ 管理员:教师的所有权限+管理用户
### 2.3 软件架构
> 前后端分离,前段组件化,方便二次开发;后端
+ 后端采用SpringBoot+JPA++Swagger2+JWT校验,根据不同用户的权限返回给用户不同的数据
+ 后端采用Vue+AntDesign,组件化拆分,封装了很多年公共组件,方便维护和二次开发
### 2.3 使用教程
+ 1.下载代码
```shell
git clone https://github.com/19920625lsg/spring-boot-online-exam.git
```
+ 2.初始化数据库
> 安装mysql的步骤这里省略网上的教程很多。安装好mysql后新建exam数据库密码和`spring-boot-online-exam/backend/exam/src/main/resources/application.yml`的`password: xxxxxx`保持一致,然后导入`spring-boot-online-exam/doc/sql/exam.sql`
+ 3.启动后端
> 打开`spring-boot-online-exam/backend/exam`这个Maven项目可以在IDE里启动或者执行`mvn install`生成jar包启动
+ 4.启动前端
+ 进入到前端代码路径 `cd spring-boot-online-exam/frontend/exam/`
+ 安装依赖 `npm install`
+ 启动前端 `npm run serve`
+ 5.部署完毕,查看效果
> 打开 http://localhost:8000 或者 http://本机ip:8000 即可查看演示效果
## 3.功能图示
+ 1.管理题目
+ 1.1 题目列表
> ![题目查看](doc/images/question_list.png)
+ 1.2 题目创建
> ![题目创建](doc/images/question_create.png)
+ 1.3 题目更新
> ![题目更新](doc/images/question_update.png)
+ 2.考试管理
+ 2.1 考试列表
> ![考试查看](doc/images/exam_list.png)
+ 2.2 考试创建
> ![考试创建](doc/images/exam_create.png)
+ 2.3 考试更新(`还有点小bug开发中`)
> ![考试更新](doc/images/exam_update.png)
+ 3.我的考试
+ 3.1 参加考试
> 在"考试列表"模块点击自己想参加的考试卡片即可
> ![参加考试1](doc/images/exam_join.png)
> ![参加考试2](doc/images/exam_join2.png)
+ 3.2 考试记录查看
> ![考试记录查看](doc/images/exam_detail.png)
## 4.参与贡献
1. Fork 本仓库
2. 新建 exam_xxx 分支
3. 提交代码
4. 新建 Pull Request
## 5.Todo
+ `√`0.修复issue提地bug题目创建失败
+ `√`1.考试详情编辑
+ 2.支持题目和考试的删除`删除的话比较麻烦先不做了最好是弄个visible字段不实际删除要不后面有些关联数据找不到就不好了`
> 如果题目有关联的考试则必须先删除对应的考试,反过来删除考试则不用删除题目
+ 3.图片改成base64存到数据库中
+ 4.题干和选项支持富文本
+ 5.支持批量导入题目
+ 6.新增用户管理、学科管理功能
+ 7.老师能考到所有学生的成绩以及考试的统计信息
+ 8.更多的数据分析功能
+ 9.支持容器化一键式部署(编好Dockerfile)
+ 10.支持移动端最好用uniapp做
+ ......抓紧做吧,争取每周末做一点......
ResultVO<RecordDetailVo> getExamRecordDetail(@PathVariable String recordId) {
// 定义返回结果
ResultVO<RecordDetailVo> resultVO;
try {
// 调用examService获取考试记录详情
RecordDetailVo recordDetailVo = examService.getRecordDetail(recordId);
// 返回成功结果
resultVO = new ResultVO<>(0, "获取考试记录详情成功", recordDetailVo);
} catch (Exception e) {
// 打印异常信息
e.printStackTrace();
// 返回失败结果
resultVO = new ResultVO<>(-1, "获取考试记录详情失败", null);
}
// 返回结果
return resultVO;
}
}

@ -29,15 +29,22 @@ public class ExamController {
@GetMapping("/question/all")
@ApiOperation("获取所有问题的列表")
ResultVO<List<QuestionVo>> getQuestionAll() {
// 获取全部问题列表
ResultVO<List<QuestionVo>> getQuestionAll() {
// 定义返回值
ResultVO<List<QuestionVo>> resultVO;
try {
// 调用examService获取全部问题列表
List<QuestionVo> questionAll = examService.getQuestionAll();
// 返回成功结果
resultVO = new ResultVO<>(0, "获取全部问题列表成功", questionAll);
} catch (Exception e) {
// 打印异常信息
e.printStackTrace();
// 返回失败结果
resultVO = new ResultVO<>(-1, "获取全部问题列表失败", null);
}
// 返回结果
return resultVO;
}
@ -47,10 +54,14 @@ public class ExamController {
// 完成问题的更新
System.out.println(questionVo);
try {
// 调用examService的updateQuestion方法更新问题
QuestionVo questionVoResult = examService.updateQuestion(questionVo);
// 返回更新成功的结果
return new ResultVO<>(0, "更新问题成功", questionVoResult);
} catch (Exception e) {
// 打印异常信息
e.printStackTrace();
// 返回更新失败的结果
return new ResultVO<>(-1, "更新问题失败", null);
}
}
@ -58,6 +69,7 @@ public class ExamController {
@PostMapping("/question/create")
@ApiOperation("创建问题")
ResultVO<String> questionCreate(@RequestBody QuestionCreateSimplifyVo questionCreateSimplifyVo, HttpServletRequest request) {
// 创建一个QuestionCreateVo对象
QuestionCreateVo questionCreateVo = new QuestionCreateVo();
// 把能拷贝过来的属性都拷贝过来
BeanUtils.copyProperties(questionCreateSimplifyVo, questionCreateVo);
@ -66,25 +78,33 @@ public class ExamController {
questionCreateVo.setQuestionCreatorId(userId);
System.out.println(questionCreateVo);
try {
// 调用examService的questionCreate方法创建问题
examService.questionCreate(questionCreateVo);
// 返回问题创建成功的ResultVO
return new ResultVO<>(0, "问题创建成功", null);
} catch (Exception e) {
// 打印异常信息
e.printStackTrace();
// 返回创建问题失败的ResultVO
return new ResultVO<>(-1, "创建问题失败", null);
}
}
@GetMapping("/question/selection")
@ApiOperation("获取问题分类的相关选项")
ResultVO<QuestionSelectionVo> getSelections() {
// 获取问题分类选项
ResultVO<QuestionSelectionVo> getSelections() {
// 调用examService的getSelections方法获取问题分类选项
QuestionSelectionVo questionSelectionVo = examService.getSelections();
// 如果获取成功
if (questionSelectionVo != null) {
// 返回成功的结果
return new ResultVO<>(0, "获取问题分类选项成功", questionSelectionVo);
} else {
// 否则返回失败的结果
return new ResultVO<>(-1, "获取问题分类选项失败", null);
}
}
@GetMapping("/question/detail/{id}")
@ApiOperation("根据问题的id获取问题的详细信息")
ResultVO<QuestionDetailVo> getQuestionDetail(@PathVariable String id) {
@ -92,58 +112,72 @@ public class ExamController {
System.out.println(id);
ResultVO<QuestionDetailVo> resultVO;
try {
// 调用examService的getQuestionDetail方法根据问题id获取问题的详细信息
QuestionDetailVo questionDetailVo = examService.getQuestionDetail(id);
// 如果获取成功则返回ResultVO对象状态码为0提示信息为"获取问题详情成功"数据为questionDetailVo
resultVO = new ResultVO<>(0, "获取问题详情成功", questionDetailVo);
} catch (Exception e) {
// 如果获取失败则打印异常信息并返回ResultVO对象状态码为-1提示信息为"获取问题详情失败"数据为null
e.printStackTrace();
resultVO = new ResultVO<>(-1, "获取问题详情失败", null);
}
// 返回ResultVO对象
return resultVO;
}
@GetMapping("/all")
@ApiOperation("获取全部考试的列表")
ResultVO<List<ExamVo>> getExamAll() {
// 需要拼接前端需要的考试列表对象
ResultVO<List<ExamVo>> resultVO;
try {
// 调用examService的getExamAll方法获取全部考试的列表
List<ExamVo> examVos = examService.getExamAll();
// 将获取到的考试列表封装到ResultVO对象中并返回
resultVO = new ResultVO<>(0, "获取全部考试的列表成功", examVos);
} catch (Exception e) {
// 捕获异常,并打印异常信息
e.printStackTrace();
// 将异常信息封装到ResultVO对象中并返回
resultVO = new ResultVO<>(-1, "获取全部考试的列表失败", null);
}
return resultVO;
}
@GetMapping("/question/type/list")
@ApiOperation("获取问题列表,按照单选、多选和判断题分类返回")
ResultVO<ExamQuestionTypeVo> getExamQuestionTypeList() {
// 获取问题的分类列表
ResultVO<ExamQuestionTypeVo> resultVO;
try {
// 调用examService的getExamQuestionType方法获取问题分类列表
ExamQuestionTypeVo examQuestionTypeVo = examService.getExamQuestionType();
// 如果获取成功,则返回成功的结果
resultVO = new ResultVO<>(0, "获取问题列表成功", examQuestionTypeVo);
} catch (Exception e) {
// 如果获取失败,则打印异常信息,并返回失败的结果
e.printStackTrace();
resultVO = new ResultVO<>(-1, "获取问题列表失败", null);
}
// 返回结果
return resultVO;
}
@PostMapping("/create")
@ApiOperation("创建考试")
ResultVO<Exam> createExam(@RequestBody ExamCreateVo examCreateVo, HttpServletRequest request) {
// 从前端传参数过来,在这里完成考试的入库
ResultVO<Exam> resultVO;
// 获取当前用户的id
String userId = (String) request.getAttribute("user_id");
try {
// 调用examService的create方法将examCreateVo和userId作为参数传入创建考试
Exam exam = examService.create(examCreateVo, userId);
// 创建一个ResultVO对象将创建成功的考试信息返回
resultVO = new ResultVO<>(0, "创建考试成功", exam);
} catch (Exception e) {
// 捕获异常打印异常信息并创建一个ResultVO对象将创建失败的考试信息返回
e.printStackTrace();
resultVO = new ResultVO<>(-1, "创建考试失败", null);
}
// 返回ResultVO对象
return resultVO;
}
@ -152,12 +186,17 @@ public class ExamController {
ResultVO<Exam> updateExam(@RequestBody ExamVo examVo, HttpServletRequest request) {
// 从前端传参数过来,在这里完成考试的入库
ResultVO<Exam> resultVO;
// 获取当前用户id
String userId = (String) request.getAttribute("user_id");
try {
// 调用service层更新考试
Exam exam = examService.update(examVo, userId);
// 返回更新成功的resultVO
resultVO = new ResultVO<>(0, "更新考试成功", exam);
} catch (Exception e) {
// 打印异常信息
e.printStackTrace();
// 返回更新失败的resultVO
resultVO = new ResultVO<>(-1, "更新考试失败", null);
}
return resultVO;
@ -169,12 +208,16 @@ public class ExamController {
// 获取考试列表卡片
ResultVO<List<ExamCardVo>> resultVO;
try {
// 调用examService的getExamCardList方法获取考试列表卡片
List<ExamCardVo> examCardVoList = examService.getExamCardList();
// 如果获取成功,则返回成功的结果
resultVO = new ResultVO<>(0, "获取考试列表卡片成功", examCardVoList);
} catch (Exception e) {
// 如果获取失败,则打印异常信息,并返回失败的结果
e.printStackTrace();
resultVO = new ResultVO<>(-1, "获取考试列表卡片失败", null);
}
// 返回结果
return resultVO;
}
@ -194,16 +237,20 @@ public class ExamController {
@PostMapping("/finish/{examId}")
@ApiOperation("根据用户提交的答案对指定id的考试判分")
// 完成考试
ResultVO<ExamRecord> finishExam(@PathVariable String examId, @RequestBody HashMap<String, List<String>> answersMap, HttpServletRequest request) {
// 定义返回结果
ResultVO<ExamRecord> resultVO;
try {
// 拦截器里设置上的用户id
String userId = (String) request.getAttribute("user_id");
// 下面根据用户提交的信息进行判分,返回用户的得分情况
ExamRecord examRecord = examService.judge(userId, examId, answersMap);
// 返回结果
resultVO = new ResultVO<>(0, "考卷提交成功", examRecord);
} catch (Exception e) {
e.printStackTrace();
// 返回错误结果
resultVO = new ResultVO<>(-1, "考卷提交失败", null);
}
return resultVO;
@ -211,6 +258,7 @@ public class ExamController {
@GetMapping("/record/list")
@ApiOperation("获取当前用户的考试记录")
// 获取考试记录列表
ResultVO<List<ExamRecordVo>> getExamRecordList(HttpServletRequest request) {
ResultVO<List<ExamRecordVo>> resultVO;
try {
@ -229,14 +277,20 @@ public class ExamController {
@GetMapping("/record/detail/{recordId}")
@ApiOperation("根据考试记录id获取考试记录详情")
ResultVO<RecordDetailVo> getExamRecordDetail(@PathVariable String recordId) {
// 定义返回结果
ResultVO<RecordDetailVo> resultVO;
try {
// 调用examService获取考试记录详情
RecordDetailVo recordDetailVo = examService.getRecordDetail(recordId);
// 返回成功结果
resultVO = new ResultVO<>(0, "获取考试记录详情成功", recordDetailVo);
} catch (Exception e) {
// 打印异常信息
e.printStackTrace();
// 返回失败结果
resultVO = new ResultVO<>(-1, "获取考试记录详情失败", null);
}
// 返回结果
return resultVO;
}
}

@ -42,37 +42,49 @@ public class UploadDownloadController {
@ApiOperation("单文件上传,支持同时传入参数")
@PostMapping("/api/upload/singleAndparas")
public String uploadFileSingle(@RequestParam("dir") String dir, @RequestParam("file") MultipartFile uploadfile) {
// 单文件上传
public String uploadFileSingle(@RequestParam("dir") String dir, @RequestParam("file") MultipartFile uploadfile) {
// 调用FileTransUtil工具类中的uploadFile方法将上传的文件和目录作为参数传入
return FileTransUtil.uploadFile(uploadfile, dir);
}
// 单文件上传支持同时传入参数Model
@ApiOperation("单文件上传,支持同时传入参数,Model")
@PostMapping("/upload/single/model")
public String singleUploadFileModel(@ModelAttribute("model") UploadModel2 model) {
// 调用FileTransUtil工具类中的uploadFile方法将上传的文件和目录作为参数传入
return FileTransUtil.uploadFile(model.getFile(), model.getDir());
}
// 多文件上传,支持同时传入参数
@ApiOperation("多文件上传,支持同时传入参数")
@PostMapping("upload/multiAndparas")
public String uploadFileMulti(@RequestParam("dir") String dir, @RequestParam("files") MultipartFile[] uploadfiles) {
// 调用FileTransUtil工具类中的uploadFiles方法将上传的文件数组和目录作为参数传入
return FileTransUtil.uploadFiles(uploadfiles, dir);
}
// 多文件上传,支持同时传入参数
@ApiOperation("多文件上传,支持同时传入参数")
@PostMapping(value = "/upload/multi/model")
public String multiUploadFileModel(@ModelAttribute(("model")) UploadModel model) {
// 调用FileTransUtil工具类中的uploadFiles方法将上传的文件数组和目录作为参数传入
return FileTransUtil.uploadFiles(model.getFiles(), model.getDir());
}
// Get下载文件
@ApiOperation("Get下载文件")
@GetMapping(value = "/download/get")
public ResponseEntity<InputStreamResource> downloadFileGet(@RequestParam String filePath) throws IOException {
// 调用FileTransUtil工具类中的downloadFile方法将文件路径作为参数传入
return FileTransUtil.downloadFile(filePath);
}
// Post下载文件
@ApiOperation("Post下载文件")
@PostMapping(value = "/download/post")
public ResponseEntity<InputStreamResource> downloadFilePost(@RequestBody DownloadQo downloadQo) throws IOException {
// 调用FileTransUtil工具类中的downloadFile方法将文件路径作为参数传入
return FileTransUtil.downloadFile(downloadQo.getPath());
}
}

@ -70,10 +70,15 @@ public class UserController {
@GetMapping("/info")
@ApiOperation("获取用户的详细信息,包括个人信息页面和操作权限")
ResultVO<UserInfoVo> getInfo(HttpServletRequest request) {
// 获取用户信息的接口
ResultVO<UserInfoVo> getInfo(HttpServletRequest request) {
// 打印进入接口的日志
System.out.println("进入/user/info的获取用户信息的接口");
// 获取用户ID
String userId = (String) request.getAttribute("user_id");
// 调用userService获取用户信息
UserInfoVo userInfoVo = userService.getInfo(userId);
// 返回结果
return new ResultVO<>(ResultEnum.GET_INFO_SUCCESS.getCode(), ResultEnum.GET_INFO_SUCCESS.getMessage(), userInfoVo);
}
@ -87,4 +92,4 @@ public class UserController {
System.out.println("用户名:" + username);
return "用户id" + userId + "\n用户名" + username;
}
}
}
Loading…
Cancel
Save