main
xiaoifei 2 months ago
commit ffe9f1c9bd

23
.gitignore vendored

@ -0,0 +1,23 @@
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

8
.idea/.gitignore vendored

@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="exam" />
</profile>
</annotationProcessing>
</component>
</project>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/backend/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8 (2)" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/spring-boot-online-exam-master.iml" filepath="$PROJECT_DIR$/.idea/spring-boot-online-exam-master.iml" />
</modules>
</component>
</project>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/web" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DdlMappings">
<mapping uuid="3f2269d9-40c7-4022-bc5b-913dfbbc6cdc" name="@localhost Mapping">
<data-sources db="52ce0e2c-1ca8-4087-a535-1632d84f6e81" ddl="7ee42c98-c0b3-46e7-9153-4802360edee6" />
</mapping>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SqlDialectMappings">
<file url="PROJECT" dialect="MySQL" />
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

@ -0,0 +1,7 @@
# build docker for project
FROM waterknife/centos-nginx-jdk8-mysql
WORKDIR /lsg/
COPY backend/target/*.jar ./app.jar
COPY entrypoint.sh ./
RUN chmod 777 entrypoint.sh
EXPOSE 9527

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Liang Shan Guang
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,108 @@
# 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做
+ ......抓紧做吧,争取每周末做一点......

@ -0,0 +1,6 @@
.idea/
*.iml
src/main/resources/public
src/main/resources/static
target/
dist/

@ -0,0 +1,52 @@
# 在线考试系统的后端实现
## 拦截器注入application.yml中的属性
> 拦截器执行在自动bean初始化之前会导致拦截器中无法注入配置属性按照下面的步骤即可正常注入
+ 给拦截器加`@Component`注解
![拦截器注入配置文件属性](images/拦截器注入配置文件属性.png)
+ 在配置类中用`@Autowired`注入
![拦截器注入配置文件属性2](images/拦截器注入配置文件属性2.png)
## 代码调试的时候如何打印完整的SQL语句和参数
> 主要是指application.yml的配置
参考博客[JPA打印SQL参数](https://mp.weixin.qq.com/s/zyTOdTwFhi2CwxCI9P1kQw)
+ 打印SQL语句
```yaml
spring:
jpa:
# 调试的时候用用于打印完成SQL语句(但是不打印参数),联合下面的logging.level一同打印最完整的SQL信息(语句+参数)
show-sql: true
```
+ 不打印SQL语句
```yaml
spring:
jpa:
# 调试的时候用用于打印完成SQL语句(但是不打印参数),联合下面的logging.level一同打印最完整的SQL信息(语句+参数)
show-sql: false
```
+ 打印SQL参数
```yaml
# SQL语句打印(能打印参数设置为trace是打印完整语句默认我们就关掉吧)
logging:
level:
org.hibernate.type.descriptor.sql.BasicBinder: trace
```
+ 不打印SQL参数
```yaml
# SQL语句打印(能打印参数设置为trace是打印完整语句默认我们就关掉吧)
logging:
level:
org.hibernate.type.descriptor.sql.BasicBinder: off
```
## SpringBoot整合vue工程到static目录中遇到的问题
+ [Spring Boot整合Vue解决静态资源映射页面刷新失效路径配置等问题](https://blog.csdn.net/godelgnis/article/details/89683760)

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.huawei.l00379880</groupId>
<artifactId>exam</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>exam</name>
<description>基于SpringBoot的在线考试系统</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
<!-- 常用Java工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.5.10</version>
</dependency>
<!-- FastDFS文件服务器的客户端 -->
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.26.5</version>
</dependency>
<!-- FastDFS文件传输需要 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<!-- JWT相关 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,12 @@
package lsgwr.exam;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ExamApplication {
public static void main(String[] args) {
SpringApplication.run(ExamApplication.class, args);
}
}

@ -0,0 +1,32 @@
/***********************************************************
* @Description : 访
* @author : 广(Laing Shan Guang)
* @date : 2019-05-17 00:11
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@Slf4j
public class CORSConf {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
log.info("初始化 CORSConfiguration 配置");
registry.addMapping("/**")
.allowedHeaders("*")
.allowedMethods("*")
.allowedOrigins("*");
}
};
}
}

@ -0,0 +1,27 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-22 08:21
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.config;
import lsgwr.exam.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class IntercepterConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 拦截user下的api
registry.addInterceptor(loginInterceptor).addPathPatterns("/api/**");
}
}

@ -0,0 +1,19 @@
package lsgwr.exam.config;
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
@Configuration
public class ServletConfig {
@Bean
public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer() {
return factory -> {
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/");
factory.addErrorPages(error404Page);
};
}
}

@ -0,0 +1,60 @@
/***********************************************************
* @Description : Swagger2
* @author : 广(Laing Shan Guang)
* @date : 2019-05-15 07:39
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket api() {
ParameterBuilder ticketPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<>();
ticketPar.name("Access-Token").description("Rest接口权限认证token,无需鉴权可为空")
.modelRef(new ModelRef("string")).parameterType("header")
//header中的ticket参数非必填传空也可以
.required(false).build();
//根据每个方法名也知道当前方法在设置什么参数
pars.add(ticketPar.build());
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
// 自行修改为自己的包路径
.apis(RequestHandlerSelectors.basePackage("lsgwr"))
.paths(PathSelectors.any())
.build()
.globalOperationParameters(pars);
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("online exam by springboot")
.description("在线考试系统 by 梁山广 at 2021")
.termsOfServiceUrl("https://github.com/19920625lsg/spring-boot-online-exam")
.version("2.0")
.contact(new Contact("liangshanguang", "https://github.com/lsgwr/spring-boot-online-exam", "liangshanguang2@gmail.com"))
.build();
}
}

@ -0,0 +1,5 @@
/*
* Created By Liang Shan Guang at 2019-05-14 08:20
* Description :
*/
package lsgwr.exam.config;

@ -0,0 +1,242 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-28 08:04
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.controller;
import lsgwr.exam.entity.Exam;
import lsgwr.exam.entity.ExamRecord;
import lsgwr.exam.service.ExamService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lsgwr.exam.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
@RestController
@Api(tags = "Exam APIs")
@RequestMapping("/api/exam")
public class ExamController {
@Autowired
private ExamService examService;
@GetMapping("/question/all")
@ApiOperation("获取所有问题的列表")
ResultVO<List<QuestionVo>> getQuestionAll() {
ResultVO<List<QuestionVo>> resultVO;
try {
List<QuestionVo> questionAll = examService.getQuestionAll();
resultVO = new ResultVO<>(0, "获取全部问题列表成功", questionAll);
} catch (Exception e) {
e.printStackTrace();
resultVO = new ResultVO<>(-1, "获取全部问题列表失败", null);
}
return resultVO;
}
@PostMapping("/question/update")
@ApiOperation("更新问题")
ResultVO<QuestionVo> questionUpdate(@RequestBody QuestionVo questionVo) {
// 完成问题的更新
System.out.println(questionVo);
try {
QuestionVo questionVoResult = examService.updateQuestion(questionVo);
return new ResultVO<>(0, "更新问题成功", questionVoResult);
} catch (Exception e) {
e.printStackTrace();
return new ResultVO<>(-1, "更新问题失败", null);
}
}
@PostMapping("/question/create")
@ApiOperation("创建问题")
ResultVO<String> questionCreate(@RequestBody QuestionCreateSimplifyVo questionCreateSimplifyVo, HttpServletRequest request) {
QuestionCreateVo questionCreateVo = new QuestionCreateVo();
// 把能拷贝过来的属性都拷贝过来
BeanUtils.copyProperties(questionCreateSimplifyVo, questionCreateVo);
// 设置创建者信息
String userId = (String) request.getAttribute("user_id");
questionCreateVo.setQuestionCreatorId(userId);
System.out.println(questionCreateVo);
try {
examService.questionCreate(questionCreateVo);
return new ResultVO<>(0, "问题创建成功", null);
} catch (Exception e) {
e.printStackTrace();
return new ResultVO<>(-1, "创建问题失败", null);
}
}
@GetMapping("/question/selection")
@ApiOperation("获取问题分类的相关选项")
ResultVO<QuestionSelectionVo> 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) {
// 根据问题id获取问题的详细信息
System.out.println(id);
ResultVO<QuestionDetailVo> resultVO;
try {
QuestionDetailVo questionDetailVo = examService.getQuestionDetail(id);
resultVO = new ResultVO<>(0, "获取问题详情成功", questionDetailVo);
} catch (Exception e) {
e.printStackTrace();
resultVO = new ResultVO<>(-1, "获取问题详情失败", null);
}
return resultVO;
}
@GetMapping("/all")
@ApiOperation("获取全部考试的列表")
ResultVO<List<ExamVo>> getExamAll() {
// 需要拼接前端需要的考试列表对象
ResultVO<List<ExamVo>> resultVO;
try {
List<ExamVo> examVos = examService.getExamAll();
resultVO = new ResultVO<>(0, "获取全部考试的列表成功", examVos);
} catch (Exception e) {
e.printStackTrace();
resultVO = new ResultVO<>(-1, "获取全部考试的列表失败", null);
}
return resultVO;
}
@GetMapping("/question/type/list")
@ApiOperation("获取问题列表,按照单选、多选和判断题分类返回")
ResultVO<ExamQuestionTypeVo> getExamQuestionTypeList() {
// 获取问题的分类列表
ResultVO<ExamQuestionTypeVo> resultVO;
try {
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;
String userId = (String) request.getAttribute("user_id");
try {
Exam exam = examService.create(examCreateVo, userId);
resultVO = new ResultVO<>(0, "创建考试成功", exam);
} catch (Exception e) {
e.printStackTrace();
resultVO = new ResultVO<>(-1, "创建考试失败", null);
}
return resultVO;
}
@PostMapping("/update")
@ApiOperation("更新考试")
ResultVO<Exam> updateExam(@RequestBody ExamVo examVo, HttpServletRequest request) {
// 从前端传参数过来,在这里完成考试的入库
ResultVO<Exam> resultVO;
String userId = (String) request.getAttribute("user_id");
try {
Exam exam = examService.update(examVo, userId);
resultVO = new ResultVO<>(0, "更新考试成功", exam);
} catch (Exception e) {
e.printStackTrace();
resultVO = new ResultVO<>(-1, "更新考试失败", null);
}
return resultVO;
}
@GetMapping("/card/list")
@ApiOperation("获取考试列表,适配前端卡片列表")
ResultVO<List<ExamCardVo>> getExamCardList() {
// 获取考试列表卡片
ResultVO<List<ExamCardVo>> resultVO;
try {
List<ExamCardVo> examCardVoList = examService.getExamCardList();
resultVO = new ResultVO<>(0, "获取考试列表卡片成功", examCardVoList);
} catch (Exception e) {
e.printStackTrace();
resultVO = new ResultVO<>(-1, "获取考试列表卡片失败", null);
}
return resultVO;
}
@GetMapping("/detail/{id}")
@ApiOperation("根据考试的id获取考试详情")
ResultVO<ExamDetailVo> getExamDetail(@PathVariable String id) {
// 根据id获取考试详情
ResultVO<ExamDetailVo> resultVO;
try {
ExamDetailVo examDetail = examService.getExamDetail(id);
resultVO = new ResultVO<>(0, "获取考试详情成功", examDetail);
} catch (Exception e) {
resultVO = new ResultVO<>(-1, "获取考试详情失败", null);
}
return resultVO;
}
@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;
}
@GetMapping("/record/list")
@ApiOperation("获取当前用户的考试记录")
ResultVO<List<ExamRecordVo>> getExamRecordList(HttpServletRequest request) {
ResultVO<List<ExamRecordVo>> resultVO;
try {
// 拦截器里设置上的用户id
String userId = (String) request.getAttribute("user_id");
// 下面根据用户账号拿到他(她所有的考试信息)注意要用VO封装下
List<ExamRecordVo> examRecordVoList = examService.getExamRecordList(userId);
resultVO = new ResultVO<>(0, "获取考试记录成功", examRecordVoList);
} catch (Exception e) {
e.printStackTrace();
resultVO = new ResultVO<>(-1, "获取考试记录失败", null);
}
return resultVO;
}
@GetMapping("/record/detail/{recordId}")
@ApiOperation("根据考试记录id获取考试记录详情")
ResultVO<RecordDetailVo> getExamRecordDetail(@PathVariable String recordId) {
ResultVO<RecordDetailVo> resultVO;
try {
RecordDetailVo recordDetailVo = examService.getRecordDetail(recordId);
resultVO = new ResultVO<>(0, "获取考试记录详情成功", recordDetailVo);
} catch (Exception e) {
e.printStackTrace();
resultVO = new ResultVO<>(-1, "获取考试记录详情失败", null);
}
return resultVO;
}
}

@ -0,0 +1,78 @@
package lsgwr.exam.controller;
import lsgwr.exam.qo.DownloadQo;
import lsgwr.exam.qo.UploadModel;
import lsgwr.exam.qo.UploadModel2;
import lsgwr.exam.utils.FileTransUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
/***********************************************************
* @note : ,SwaggerSwaggerUI
*
* @author : 广
* * AjaxResponseEntity
* *
* * 1. - `MultipartFile`
* * 2. - `MultipartFile []`
* * 3. - `@ModelAttribute`
* @version : V1.0 at 2018/7/16 20:43
***********************************************************/
@RestController
@Api(tags = "Upload And Download APIs")
@RequestMapping("/api/file")
@Slf4j
public class UploadDownloadController {
// @Autowired
// AITestConfig aiTestConfig;
//
// @PostMapping("/upload/single")
// @ApiOperation("单文件上传")
// public String uploadFile(@RequestParam("file") MultipartFile uploadfile) {
// return FileTransUtil.uploadFile(uploadfile, "/root/" + File.separator + uploadfile.getOriginalFilename());
// }
@ApiOperation("单文件上传,支持同时传入参数")
@PostMapping("/api/upload/singleAndparas")
public String uploadFileSingle(@RequestParam("dir") String dir, @RequestParam("file") MultipartFile uploadfile) {
return FileTransUtil.uploadFile(uploadfile, dir);
}
@ApiOperation("单文件上传,支持同时传入参数,Model")
@PostMapping("/upload/single/model")
public String singleUploadFileModel(@ModelAttribute("model") UploadModel2 model) {
return FileTransUtil.uploadFile(model.getFile(), model.getDir());
}
@ApiOperation("多文件上传,支持同时传入参数")
@PostMapping("upload/multiAndparas")
public String uploadFileMulti(@RequestParam("dir") String dir, @RequestParam("files") MultipartFile[] uploadfiles) {
return FileTransUtil.uploadFiles(uploadfiles, dir);
}
@ApiOperation("多文件上传,支持同时传入参数")
@PostMapping(value = "/upload/multi/model")
public String multiUploadFileModel(@ModelAttribute(("model")) UploadModel model) {
return FileTransUtil.uploadFiles(model.getFiles(), model.getDir());
}
@ApiOperation("Get下载文件")
@GetMapping(value = "/download/get")
public ResponseEntity<InputStreamResource> downloadFileGet(@RequestParam String filePath) throws IOException {
return FileTransUtil.downloadFile(filePath);
}
@ApiOperation("Post下载文件")
@PostMapping(value = "/download/post")
public ResponseEntity<InputStreamResource> downloadFilePost(@RequestBody DownloadQo downloadQo) throws IOException {
return FileTransUtil.downloadFile(downloadQo.getPath());
}
}

@ -0,0 +1,90 @@
/***********************************************************
* @Description : REST
* @author : 广(Laing Shan Guang)
* @date : 2019-05-16 23:45
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.controller;
import lsgwr.exam.dto.RegisterDTO;
import lsgwr.exam.entity.User;
import lsgwr.exam.enums.ResultEnum;
import lsgwr.exam.qo.LoginQo;
import lsgwr.exam.service.UserService;
import lsgwr.exam.vo.ResultVO;
import lsgwr.exam.vo.UserInfoVo;
import lsgwr.exam.vo.UserVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@RestController
@Api(tags = "User APIs")
@RequestMapping("/api/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/register")
@ApiOperation("注册")
ResultVO<User> register(@RequestBody RegisterDTO registerDTO) {
ResultVO<User> resultVO;
// 注册信息的完善,还有唯一性校验没(用户名、邮箱和手机号)已经在user表中通过unique来设置了
User user = userService.register(registerDTO);
if (user != null) {
// 注册成功
resultVO = new ResultVO<>(ResultEnum.REGISTER_SUCCESS.getCode(), ResultEnum.REGISTER_SUCCESS.getMessage(), user);
} else {
resultVO = new ResultVO<>(ResultEnum.REGISTER_FAILED.getCode(), ResultEnum.REGISTER_FAILED.getMessage(), null);
}
return resultVO;
}
@PostMapping("/login")
@ApiOperation("根据用户名或邮箱登录,登录成功返回token")
ResultVO<String> login(@RequestBody LoginQo loginQo) { // 这里不用手机号是因为手机号和用户名难以进行格式区分,而用户名和
// 用户登录
ResultVO<String> resultVO;
String token = userService.login(loginQo);
if (token != null) {
// 登录成功
resultVO = new ResultVO<>(ResultEnum.LOGIN_SUCCESS.getCode(), ResultEnum.LOGIN_SUCCESS.getMessage(), token);
} else {
// 登录失败
resultVO = new ResultVO<>(ResultEnum.LOGIN_FAILED.getCode(), ResultEnum.LOGIN_FAILED.getMessage(), null);
}
return resultVO;
}
@GetMapping("/user-info")
@ApiOperation("获取用户信息")
ResultVO<UserVo> getUserInfo(HttpServletRequest request) {
String userId = (String) request.getAttribute("user_id");
UserVo userVo = userService.getUserInfo(userId);
return new ResultVO<>(ResultEnum.GET_INFO_SUCCESS.getCode(), ResultEnum.GET_INFO_SUCCESS.getMessage(), userVo);
}
@GetMapping("/info")
@ApiOperation("获取用户的详细信息,包括个人信息页面和操作权限")
ResultVO<UserInfoVo> getInfo(HttpServletRequest request) {
System.out.println("进入/user/info的获取用户信息的接口");
String userId = (String) request.getAttribute("user_id");
UserInfoVo userInfoVo = userService.getInfo(userId);
return new ResultVO<>(ResultEnum.GET_INFO_SUCCESS.getCode(), ResultEnum.GET_INFO_SUCCESS.getMessage(), userInfoVo);
}
@GetMapping("/test")
@ApiOperation("测试接口")
String test(HttpServletRequest request) {
// 下面这两个属性都是登录拦截器从token中解析地当用户名不对或者token过期时是走不到接口内的
String userId = (String) request.getAttribute("user_id");
String username = (String) request.getAttribute("username");
System.out.println("用户id" + userId);
System.out.println("用户名:" + username);
return "用户id" + userId + "\n用户名" + username;
}
}

@ -0,0 +1,5 @@
/*
* Created By Liang Shan Guang at 2019-05-14 08:20
* Description : REST
*/
package lsgwr.exam.controller;

@ -0,0 +1,21 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-16 23:40
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.dto;
import lombok.Data;
@Data
public class RegisterDTO {
private String email;
private String password;
private String password2;
private String mobile;
/**
*
*/
private String captcha;
}

@ -0,0 +1,5 @@
/*
* Created By Liang Shan Guang at 2019-05-16 23:38
* Description :
*/
package lsgwr.exam.dto;

@ -0,0 +1,27 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-26 12:31
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Data
@Entity
public class Action {
@Id
@GeneratedValue
private Integer actionId;
private String actionName;
private String actionDescription;
private Boolean defaultCheck;
}

@ -0,0 +1,55 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019/5/14 07:42
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.util.Date;
@Entity
@Data
@DynamicUpdate
public class Exam {
@Id
private String examId;
private String examName;
private String examAvatar;
private String examDescription;
private String examQuestionIds;
private String examQuestionIdsRadio;
private String examQuestionIdsCheck;
private String examQuestionIdsJudge;
private Integer examScore;
private Integer examScoreRadio;
private Integer examScoreCheck;
private Integer examScoreJudge;
private String examCreatorId;
private Integer examTimeLimit;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date examStartDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date examEndDate;
/**
* , Java
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* Java
* @DynamicUpdate
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}

@ -0,0 +1,56 @@
/***********************************************************
* @Description : id()
* @author : 广(Laing Shan Guang)
* @date : 2019/5/14 07:43
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.util.Date;
@Data
@Entity
public class ExamRecord {
/**
*
*/
@Id
private String examRecordId;
/**
* id
*/
private String examId;
/**
* (_-),
*/
private String answerOptionIds;
/**
* userid
*/
private String examJoinerId;
/**
*
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date examJoinDate;
/**
* ()
*/
private Integer examTimeCost;
/**
*
*/
private Integer examJoinScore;
/**
*
*/
private Integer examResultLevel;
}

@ -0,0 +1,24 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019/5/14 07:44
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Data
@Entity
public class ExamRecordLevel {
@Id
@GeneratedValue
private Integer examRecordLevelId;
private String examRecordLevelName;
private String examRecordLevelDescription;
}

@ -0,0 +1,27 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-26 12:30
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Data
@Entity
public class Page {
@Id
@GeneratedValue
private Integer pageId;
private String pageName;
private String pageDescription;
private String actionIds;
}

@ -0,0 +1,46 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019/5/14 07:46
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.util.Date;
@Data
@Entity
@DynamicUpdate
public class Question {
@Id
private String questionId;
private String questionName;
private Integer questionScore;
private String questionCreatorId;
private Integer questionLevelId;
private Integer questionTypeId;
private Integer questionCategoryId;
private String questionDescription;
private String questionOptionIds;
private String questionAnswerOptionIds;
/**
* , Java
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* Java
* @DynamicUpdate
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}

@ -0,0 +1,31 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019/5/14 07:46
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.entity;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Data
@Entity
public class QuestionCategory {
@Id
@GeneratedValue
@JsonProperty("id")
private Integer questionCategoryId;
@JsonProperty("name")
private String questionCategoryName;
@JsonProperty("description")
private String questionCategoryDescription;
}

@ -0,0 +1,30 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019/5/14 07:47
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.entity;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
@Data
public class QuestionLevel {
@Id
@GeneratedValue
@JsonProperty("id")
private Integer questionLevelId;
@JsonProperty("name")
private String questionLevelName;
@JsonProperty("description")
private String questionLevelDescription;
}

@ -0,0 +1,22 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019/5/14 07:48
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
@Data
@Entity
public class QuestionOption {
@Id
private String questionOptionId;
private String questionOptionContent;
private String questionOptionDescription;
}

@ -0,0 +1,30 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019/5/14 07:48
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.entity;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Data
@Entity
public class QuestionType {
@Id
@GeneratedValue
@JsonProperty("id")
private Integer questionTypeId;
@JsonProperty("name")
private String questionTypeName;
@JsonProperty("description")
private String questionTypeDescription;
}

@ -0,0 +1,29 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019/5/14 07:49
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Data
@Entity
public class Role {
@Id
@GeneratedValue
private Integer roleId;
private String roleName;
private String roleDescription;
private String roleDetail;
/**
* 访(-)
*/
private String rolePageIds;
}

@ -0,0 +1,45 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019/5/14 07:49
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.util.Date;
@Data
@Entity
@DynamicUpdate
public class User {
@Id
private String userId;
private String userUsername;
private String userNickname;
private String userPassword;
private Integer userRoleId;
private String userAvatar;
private String userDescription;
private String userEmail;
private String userPhone;
/**
* , Java
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* Java
* @DynamicUpdate
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}

@ -0,0 +1,5 @@
/*
* Created By Liang Shan Guang at 2019-05-14 00:34
* Description :
*/
package lsgwr.exam.entity;

@ -0,0 +1,25 @@
package lsgwr.exam.enums;
import lombok.Getter;
/**
*
* @author liangshanguang
*/
@Getter
public enum LoginTypeEnum {
/**
* 12
*/
USERNAME(1, "用户名"),
EMAIL(2, "邮箱");
LoginTypeEnum(Integer type, String name) {
this.type = type;
this.name = name;
}
private Integer type;
private String name;
}

@ -0,0 +1,29 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-18 12:00
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.enums;
import lombok.Getter;
@Getter
public enum QuestionEnum {
/**
*
*/
RADIO(1, "单选题"),
CHECK(2, "多选题"),
JUDGE(3, "判断题");
QuestionEnum(Integer id, String role) {
this.id = id;
this.role = role;
}
private Integer id;
private String role;
}

@ -0,0 +1,27 @@
package lsgwr.exam.enums;
import lombok.Getter;
@Getter
public enum ResultEnum {
// 下面是本项目用到的所有错误码
REGISTER_SUCCESS(0, "注册成功"),
REGISTER_FAILED(-2, "注册失败"),
LOGIN_SUCCESS(0, "登录成功"),
LOGIN_FAILED(-1, "用户名或者密码错误"),
GET_INFO_SUCCESS(0, "获取用户信息成功"),
PARAM_ERR(1, "参数不正确"),
PRODUCT_NOT_EXIST(10, "用户不存在"),
PRODUCT_STOCK_ERR(11, "考试信息异常"),
ORDER_STATUS_ERR(14, "考试状态异常"),
ORDER_UPDATE_ERR(15, "考试更新异常"),
ORDER_DETAIL_EMPTY(16, "用户详情为空");
ResultEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
private Integer code;
private String message;
}

@ -0,0 +1,29 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-18 12:00
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.enums;
import lombok.Getter;
@Getter
public enum RoleEnum {
/**
* role
*/
ADMIN(1, "管理员"),
TEACHER(2, "教师"),
STUDENT(3, "学生");
RoleEnum(Integer id, String role) {
this.id = id;
this.role = role;
}
private Integer id;
private String role;
}

@ -0,0 +1,25 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-17 07:50
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.exception;
import lsgwr.exam.enums.ResultEnum;
import lombok.Getter;
@Getter
public class ExamException extends RuntimeException {
private Integer code;
public ExamException(ResultEnum resultEnum) {
super(resultEnum.getMessage());
this.code = resultEnum.getCode();
}
public ExamException( Integer code, String message) {
super(message);
this.code = code;
}
}

@ -0,0 +1,5 @@
/*
* Created By Liang Shan Guang at 2019-05-17 07:51
* Description :
*/
package lsgwr.exam.exception;

@ -0,0 +1,99 @@
/***********************************************************
* @Description : Token
* @author : 广(Laing Shan Guang)
* @date : 2019-05-22 07:35
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.interceptor;
import com.google.gson.Gson;
import lsgwr.exam.utils.JwtUtils;
import lsgwr.exam.vo.JsonData;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/**
* https://stackoverflow.com/questions/43591582/application-properties-value-in-spring-boot-interceptor
*
* @author liangshanguang
*/
@Component
public class LoginInterceptor implements HandlerInterceptor {
/**
* @Component使pplication.yml
*/
@Value("${interceptors.auth-ignore-uris}")
private String authIgnoreUris;
/**
* controller
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("进入拦截器啦!");
String uri = request.getRequestURI();
System.out.println(uri);
System.out.println("无需拦截的接口路径:" + authIgnoreUris);
String[] authIgnoreUriArr = authIgnoreUris.split(",");
// 登录和注册接口不需要进行token拦截和校验
for (String authIgnoreUri : authIgnoreUriArr) {
if (authIgnoreUri.equals(uri)) {
return true;
}
}
// 注意要和前端适配Access-Token属性前端会在登陆后的每个接口请求头加Access-Token属性
String token = request.getHeader("Access-Token");
if (token == null) {
// token不在header中时也可能在参数中(RequestParam)
token = request.getParameter("token");
}
if (token != null) {
// 请求中是携带参数的
Claims claims = JwtUtils.checkJWT(token);
if (claims == null) {
// 返回null说明用户篡改了token导致校验失败
sendJsonMessage(response, JsonData.buildError("token无效请重新登录"));
return false;
}
// 用户的的主键id
String id = (String) claims.get("id");
// 用户名
String username = (String) claims.get("username");
// 把这两个参数放到请求中从而可以在controller中获取到不需要在controller中在用Jwt解密了,request.getAttribute("属性名")即可获取
request.setAttribute("user_id", id);
request.setAttribute("username", username);
return true;
}
sendJsonMessage(response, JsonData.buildError("token为null,请先登录!"));
return false;
}
/**
*
*
* @param response
* @param obj
* @throws Exception
*/
public static void sendJsonMessage(HttpServletResponse response, Object obj) throws Exception {
Gson g = new Gson();
response.setContentType("application/json; charset=utf-8");
PrintWriter writer = response.getWriter();
writer.print(g.toJson(obj));
writer.close();
response.flushBuffer();
}
}

@ -0,0 +1,17 @@
package lsgwr.exam.qo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/***********************************************************
* @note :
* @author : 广
* @version : V1.0 at 2019/5/19 20:10
***********************************************************/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DownloadQo {
String path;
}

@ -0,0 +1,29 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-19 20:18
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.qo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginQo {
/**
* 12
*/
private Integer loginType;
/**
* /
*/
private String userInfo;
/**
*
*/
private String password;
}

@ -0,0 +1,27 @@
package lsgwr.exam.qo;
/***********************************************************
* @Description :
* @author : 广
* @date : 2017/8/19 15:51
* @version : V1.0
***********************************************************/
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.web.multipart.MultipartFile;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UploadModel {
/**
*
*/
private MultipartFile[] files;
/**
*
*/
private String dir;
}

@ -0,0 +1,27 @@
package lsgwr.exam.qo;
/***********************************************************
* @Description :
* @author : 广
* @date : 2018/5/19 15:51
* @version : V1.0
***********************************************************/
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.web.multipart.MultipartFile;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UploadModel2 {
/**
*
*/
private MultipartFile file;
/**
*
*/
private String dir;
}

@ -0,0 +1,6 @@
/***********************************************************
* @note : (Query Object)
* @author : 广
* @version : V1.0 at 2018/7/18 17:32
***********************************************************/
package lsgwr.exam.qo;

@ -0,0 +1,13 @@
/***********************************************************
* @Description : Action
* @author : 广(Laing Shan Guang)
* @date : 2019-05-26 12:39
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.repository;
import lsgwr.exam.entity.Action;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ActionRepository extends JpaRepository<Action, Integer> {
}

@ -0,0 +1,13 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-14 08:24
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.repository;
import lsgwr.exam.entity.ExamRecordLevel;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ExamRecordLevelRepository extends JpaRepository<ExamRecordLevel, Integer> {
}

@ -0,0 +1,22 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-14 08:23
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.repository;
import lsgwr.exam.entity.ExamRecord;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ExamRecordRepository extends JpaRepository<ExamRecord, String> {
/**
*
*
* @param userId id
* @return
*/
List<ExamRecord> findByExamJoinerIdOrderByExamJoinDateDesc(String userId);
}

@ -0,0 +1,18 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-14 08:22
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.repository;
import lsgwr.exam.entity.Exam;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface ExamRepository extends JpaRepository<Exam, String> {
@Query("select e from Exam e order by e.updateTime desc")
List<Exam> findAll();
}

@ -0,0 +1,13 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-26 12:41
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.repository;
import lsgwr.exam.entity.Page;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PageRepository extends JpaRepository<Page, Integer> {
}

@ -0,0 +1,13 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-14 08:25
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.repository;
import lsgwr.exam.entity.QuestionCategory;
import org.springframework.data.jpa.repository.JpaRepository;
public interface QuestionCategoryRepository extends JpaRepository<QuestionCategory, Integer> {
}

@ -0,0 +1,13 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-14 08:26
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.repository;
import lsgwr.exam.entity.QuestionLevel;
import org.springframework.data.jpa.repository.JpaRepository;
public interface QuestionLevelRepository extends JpaRepository<QuestionLevel, Integer> {
}

@ -0,0 +1,13 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-14 08:27
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.repository;
import lsgwr.exam.entity.QuestionOption;
import org.springframework.data.jpa.repository.JpaRepository;
public interface QuestionOptionRepository extends JpaRepository<QuestionOption, String> {
}

@ -0,0 +1,19 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-14 08:25
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.repository;
import lsgwr.exam.entity.Question;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface QuestionRepository extends JpaRepository<Question, String> {
List<Question> findByQuestionTypeId(Integer id);
@Query("select q from Question q order by q.updateTime desc")
List<Question> findAll();
}

@ -0,0 +1,13 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-14 08:28
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.repository;
import lsgwr.exam.entity.QuestionType;
import org.springframework.data.jpa.repository.JpaRepository;
public interface QuestionTypeRepository extends JpaRepository<QuestionType, Integer> {
}

@ -0,0 +1,13 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-14 08:29
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.repository;
import lsgwr.exam.entity.Role;
import org.springframework.data.jpa.repository.JpaRepository;
public interface RoleRepository extends JpaRepository<Role, Integer> {
}

@ -0,0 +1,28 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-14 08:30
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.repository;
import lsgwr.exam.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, String> {
/**
*
*
* @param username
* @return (unique 1)
*/
User findByUserUsername(String username);
/**
*
*
* @param email
* @return (unique 1)
*/
User findByUserEmail(String email);
}

@ -0,0 +1,5 @@
/*
* Created By Liang Shan Guang at 2019-05-14 08:20
* Description :
*/
package lsgwr.exam.repository;

@ -0,0 +1,122 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-28 08:05
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.service;
import lsgwr.exam.entity.Exam;
import lsgwr.exam.entity.ExamRecord;
import lsgwr.exam.vo.*;
import java.util.HashMap;
import java.util.List;
public interface ExamService {
/**
*
*/
List<QuestionVo> getQuestionAll();
/**
*
*
* @param questionVo
*/
QuestionVo updateQuestion(QuestionVo questionVo);
/**
*
*
* @param questionCreateVo
*/
void questionCreate(QuestionCreateVo questionCreateVo);
/**
*
*
* @return
*/
QuestionSelectionVo getSelections();
/**
*
*
* @param id id
* @return VO
*/
QuestionDetailVo getQuestionDetail(String id);
/**
*
*/
List<ExamVo> getExamAll();
/**
* 便
*
* @return
*/
ExamQuestionTypeVo getExamQuestionType();
/**
*
*
* @param examCreateVo
* @param userId id
* @return
*/
Exam create(ExamCreateVo examCreateVo, String userId);
/**
*
*
* @return
*/
List<ExamCardVo> getExamCardList();
/**
* id
*
* @param id exam
* @return VO
*/
ExamDetailVo getExamDetail(String id);
/**
*
*
* @param userId
* @param examId
* @param answersMap
* @return
*/
ExamRecord judge(String userId, String examId, HashMap<String, List<String>> answersMap);
/**
* id
*
* @param userId id
* @return
*/
List<ExamRecordVo> getExamRecordList(String userId);
/**
*
*
* @param recordId id
* @return
*/
RecordDetailVo getRecordDetail(String recordId);
/**
*
*
* @param examVo
* @param userId
* @return
*/
Exam update(ExamVo examVo, String userId);
}

@ -0,0 +1,45 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-17 08:02
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.service;
import lsgwr.exam.dto.RegisterDTO;
import lsgwr.exam.entity.User;
import lsgwr.exam.qo.LoginQo;
import lsgwr.exam.vo.UserInfoVo;
import lsgwr.exam.vo.UserVo;
public interface UserService {
/**
*
*
* @param registerDTO
* @return
*/
User register(RegisterDTO registerDTO);
/**
* token
*
* @param loginQo
* @return tokennull
*/
String login(LoginQo loginQo);
/**
* id
*
* @return
*/
UserVo getUserInfo(String userId);
/**
* ()
* @param userId id
* @return
*/
UserInfoVo getInfo(String userId);
}

@ -0,0 +1,674 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-28 08:06
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.service.impl;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import lsgwr.exam.entity.*;
import lsgwr.exam.enums.QuestionEnum;
import lsgwr.exam.service.ExamService;
import lsgwr.exam.repository.*;
import lsgwr.exam.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.*;
@Service
@Transactional
public class ExamServiceImpl implements ExamService {
private final ExamRepository examRepository;
private final ExamRecordRepository examRecordRepository;
private final QuestionRepository questionRepository;
private final UserRepository userRepository;
private final QuestionLevelRepository questionLevelRepository;
private final QuestionTypeRepository questionTypeRepository;
private final QuestionCategoryRepository questionCategoryRepository;
private final QuestionOptionRepository questionOptionRepository;
public ExamServiceImpl(QuestionRepository questionRepository, UserRepository userRepository, QuestionLevelRepository questionLevelRepository, QuestionTypeRepository questionTypeRepository, QuestionCategoryRepository questionCategoryRepository, QuestionOptionRepository questionOptionRepository, ExamRepository examRepository, ExamRecordRepository examRecordRepository) {
this.questionRepository = questionRepository;
this.userRepository = userRepository;
this.questionLevelRepository = questionLevelRepository;
this.questionTypeRepository = questionTypeRepository;
this.questionCategoryRepository = questionCategoryRepository;
this.questionOptionRepository = questionOptionRepository;
this.examRepository = examRepository;
this.examRecordRepository = examRecordRepository;
}
@Override
public List<QuestionVo> getQuestionAll() {
List<Question> questionList = questionRepository.findAll();
return getQuestionVos(questionList);
}
private List<QuestionVo> getQuestionVos(List<Question> questionList) {
// 需要自定义的question列表
List<QuestionVo> questionVoList = new ArrayList<>();
// 循环完成每个属性的定制
for (Question question : questionList) {
QuestionVo questionVo = getQuestionVo(question);
questionVoList.add(questionVo);
}
return questionVoList;
}
private QuestionVo getQuestionVo(Question question) {
QuestionVo questionVo = new QuestionVo();
// 先复制能复制的属性
BeanUtils.copyProperties(question, questionVo);
// 设置问题的创建者
questionVo.setQuestionCreator(
Objects.requireNonNull(
userRepository.findById(
question.getQuestionCreatorId()
).orElse(null)
).getUserUsername());
// 设置问题的难度
questionVo.setQuestionLevel(
Objects.requireNonNull(
questionLevelRepository.findById(
question.getQuestionLevelId()
).orElse(null)
).getQuestionLevelDescription());
// 设置题目的类别,比如单选、多选、判断等
questionVo.setQuestionType(
Objects.requireNonNull(
questionTypeRepository.findById(
question.getQuestionTypeId()
).orElse(null)
).getQuestionTypeDescription());
// 设置题目分类,比如数学、语文、英语、生活、人文等
questionVo.setQuestionCategory(
Objects.requireNonNull(
questionCategoryRepository.findById(
question.getQuestionCategoryId()
).orElse(null)
).getQuestionCategoryName()
);
// 选项的自定义Vo列表
List<QuestionOptionVo> optionVoList = new ArrayList<>();
// 获得所有的选项列表
List<QuestionOption> optionList = questionOptionRepository.findAllById(
Arrays.asList(question.getQuestionOptionIds().split("-"))
);
// 获取所有的答案列表optionList中每个option的isAnswer选项
List<QuestionOption> answerList = questionOptionRepository.findAllById(
Arrays.asList(question.getQuestionAnswerOptionIds().split("-"))
);
// 根据选项和答案的id相同设置optionVo的isAnswer属性
for (QuestionOption option : optionList) {
QuestionOptionVo optionVo = new QuestionOptionVo();
BeanUtils.copyProperties(option, optionVo);
for (QuestionOption answer : answerList) {
if (option.getQuestionOptionId().equals(answer.getQuestionOptionId())) {
optionVo.setAnswer(true);
}
}
optionVoList.add(optionVo);
}
// 设置题目的所有选项
questionVo.setQuestionOptionVoList(optionVoList);
return questionVo;
}
@Override
public QuestionVo updateQuestion(QuestionVo questionVo) {
// 1.把需要的属性都设置好
StringBuilder questionAnswerOptionIds = new StringBuilder();
List<QuestionOption> questionOptionList = new ArrayList<>();
List<QuestionOptionVo> questionOptionVoList = questionVo.getQuestionOptionVoList();
int size = questionOptionVoList.size();
for (int i = 0; i < questionOptionVoList.size(); i++) {
QuestionOptionVo questionOptionVo = questionOptionVoList.get(i);
QuestionOption questionOption = new QuestionOption();
BeanUtils.copyProperties(questionOptionVo, questionOption);
questionOptionList.add(questionOption);
if (questionOptionVo.getAnswer()) {
if (i != size - 1) {
// 把更新后的答案的id加上去,记得用-连到一起
questionAnswerOptionIds.append(questionOptionVo.getQuestionOptionId()).append("-");
} else {
// 最后一个不需要用-连接
questionAnswerOptionIds.append(questionOptionVo.getQuestionOptionId());
}
}
}
// 1.更新问题
Question question = questionRepository.findById(questionVo.getQuestionId()).orElse(null);
assert question != null;
BeanUtils.copyProperties(questionVo, question);
question.setQuestionAnswerOptionIds(questionAnswerOptionIds.toString());
questionRepository.save(question);
// 2.更新所有的option
questionOptionRepository.saveAll(questionOptionList);
// 返回更新后的问题,方便前端局部刷新
return getQuestionVo(question);
}
@Override
public void questionCreate(QuestionCreateVo questionCreateVo) {
// 问题创建
Question question = new Question();
// 把能复制的属性都复制过来
BeanUtils.copyProperties(questionCreateVo, question);
// 设置下questionOptionIds和questionAnswerOptionIds需要自己用Hutool生成下
List<QuestionOption> questionOptionList = new ArrayList<>();
List<QuestionOptionCreateVo> questionOptionCreateVoList = questionCreateVo.getQuestionOptionCreateVoList();
for (QuestionOptionCreateVo questionOptionCreateVo : questionOptionCreateVoList) {
QuestionOption questionOption = new QuestionOption();
// 设置选项的的内容
questionOption.setQuestionOptionContent(questionOptionCreateVo.getQuestionOptionContent());
// 设置选项的id
questionOption.setQuestionOptionId(IdUtil.simpleUUID());
questionOptionList.add(questionOption);
}
// 把选项都存起来然后才能用于下面设置Question的questionOptionIds和questionAnswerOptionIds
questionOptionRepository.saveAll(questionOptionList);
String questionOptionIds = "";
String questionAnswerOptionIds = "";
// 经过上面的saveAll方法所有的option的主键id都已经持久化了
for (int i = 0; i < questionOptionCreateVoList.size(); i++) {
// 获取指定选项
QuestionOptionCreateVo questionOptionCreateVo = questionOptionCreateVoList.get(i);
// 获取保存后的指定对象
QuestionOption questionOption = questionOptionList.get(i);
questionOptionIds += questionOption.getQuestionOptionId() + "-";
if (questionOptionCreateVo.getAnswer()) {
// 如果是答案的话
questionAnswerOptionIds += questionOption.getQuestionOptionId() + "-";
}
}
// 把字符串最后面的"-"给去掉
questionAnswerOptionIds = replaceLastSeparator(questionAnswerOptionIds);
questionOptionIds = replaceLastSeparator(questionOptionIds);
// 设置选项id组成的字符串
question.setQuestionOptionIds(questionOptionIds);
// 设置答案选项id组成的字符串
question.setQuestionAnswerOptionIds(questionAnswerOptionIds);
// 自己生成问题的id
question.setQuestionId(IdUtil.simpleUUID());
// 先把创建时间和更新时间每次都取当前时间吧
question.setCreateTime(new Date());
question.setUpdateTime(new Date());
// 保存问题到数据库
questionRepository.save(question);
}
@Override
public QuestionSelectionVo getSelections() {
QuestionSelectionVo questionSelectionVo = new QuestionSelectionVo();
questionSelectionVo.setQuestionCategoryList(questionCategoryRepository.findAll());
questionSelectionVo.setQuestionLevelList(questionLevelRepository.findAll());
questionSelectionVo.setQuestionTypeList(questionTypeRepository.findAll());
return questionSelectionVo;
}
/**
* split
*
* @param str
* @return
*/
public static String trimMiddleLine(String str) {
if (str.charAt(str.length() - 1) == '-') {
str = str.substring(0, str.length() - 1);
}
return str;
}
@Override
public QuestionDetailVo getQuestionDetail(String id) {
Question question = questionRepository.findById(id).orElse(null);
QuestionDetailVo questionDetailVo = new QuestionDetailVo();
questionDetailVo.setId(id);
questionDetailVo.setName(question.getQuestionName());
questionDetailVo.setDescription(question.getQuestionDescription());
// 问题类型,单选题/多选题/判断题
questionDetailVo.setType(
Objects.requireNonNull(
questionTypeRepository.findById(
question.getQuestionTypeId()
).orElse(null)
).getQuestionTypeDescription()
);
// 获取当前问题的选项
String optionIdsStr = trimMiddleLine(question.getQuestionOptionIds());
String[] optionIds = optionIdsStr.split("-");
// 获取选项列表
List<QuestionOption> optionList = questionOptionRepository.findAllById(Arrays.asList(optionIds));
questionDetailVo.setOptions(optionList);
return questionDetailVo;
}
@Override
public List<ExamVo> getExamAll() {
List<Exam> examList = examRepository.findAll();
return getExamVos(examList);
}
private List<ExamVo> getExamVos(List<Exam> examList) {
// 需要自定义的exam列表
List<ExamVo> examVoList = new ArrayList<>();
// 循环完成每个属性的定制
for (Exam exam : examList) {
ExamVo examVo = new ExamVo();
// 先尽量复制能复制的所有属性
BeanUtils.copyProperties(exam, examVo);
// 设置问题的创建者
examVo.setExamCreator(
Objects.requireNonNull(
userRepository.findById(
exam.getExamCreatorId()
).orElse(null)
).getUserUsername()
);
// 获取所有单选题列表并赋值到ExamVo的属性ExamQuestionSelectVoRadioList上
List<ExamQuestionSelectVo> radioQuestionVoList = new ArrayList<>();
List<Question> radioQuestionList = questionRepository.findAllById(
Arrays.asList(exam.getExamQuestionIdsRadio().split("-"))
);
for (Question question : radioQuestionList) {
ExamQuestionSelectVo radioQuestionVo = new ExamQuestionSelectVo();
BeanUtils.copyProperties(question, radioQuestionVo);
radioQuestionVo.setChecked(true); // 考试中的问题肯定被选中的
radioQuestionVoList.add(radioQuestionVo);
}
examVo.setExamQuestionSelectVoRadioList(radioQuestionVoList);
// 获取所有多选题列表并赋值到ExamVo的属性ExamQuestionSelectVoCheckList上
List<ExamQuestionSelectVo> checkQuestionVoList = new ArrayList<>();
List<Question> checkQuestionList = questionRepository.findAllById(
Arrays.asList(exam.getExamQuestionIdsCheck().split("-"))
);
for (Question question : checkQuestionList) {
ExamQuestionSelectVo checkQuestionVo = new ExamQuestionSelectVo();
BeanUtils.copyProperties(question, checkQuestionVo);
checkQuestionVo.setChecked(true); // 考试中的问题肯定被选中的
checkQuestionVoList.add(checkQuestionVo);
}
examVo.setExamQuestionSelectVoCheckList(checkQuestionVoList);
// 获取所有多选题列表并赋值到ExamVo的属性ExamQuestionSelectVoJudgeList上
List<ExamQuestionSelectVo> judgeQuestionVoList = new ArrayList<>();
List<Question> judgeQuestionList = questionRepository.findAllById(
Arrays.asList(exam.getExamQuestionIdsJudge().split("-"))
);
for (Question question : judgeQuestionList) {
ExamQuestionSelectVo judgeQuestionVo = new ExamQuestionSelectVo();
BeanUtils.copyProperties(question, judgeQuestionVo);
judgeQuestionVo.setChecked(true); // 考试中的问题肯定被选中的
judgeQuestionVoList.add(judgeQuestionVo);
}
examVo.setExamQuestionSelectVoJudgeList(judgeQuestionVoList);
// 把examVo加到examVoList中
examVoList.add(examVo);
}
return examVoList;
}
@Override
public ExamQuestionTypeVo getExamQuestionType() {
ExamQuestionTypeVo examQuestionTypeVo = new ExamQuestionTypeVo();
// 获取所有单选题列表并赋值到ExamVo的属性ExamQuestionSelectVoRadioList上
List<ExamQuestionSelectVo> radioQuestionVoList = new ArrayList<>();
List<Question> radioQuestionList = questionRepository.findByQuestionTypeId(QuestionEnum.RADIO.getId());
for (Question question : radioQuestionList) {
ExamQuestionSelectVo radioQuestionVo = new ExamQuestionSelectVo();
BeanUtils.copyProperties(question, radioQuestionVo);
radioQuestionVoList.add(radioQuestionVo);
}
examQuestionTypeVo.setExamQuestionSelectVoRadioList(radioQuestionVoList);
// 获取所有多选题列表并赋值到ExamVo的属性ExamQuestionSelectVoCheckList上
List<ExamQuestionSelectVo> checkQuestionVoList = new ArrayList<>();
List<Question> checkQuestionList = questionRepository.findByQuestionTypeId(QuestionEnum.CHECK.getId());
for (Question question : checkQuestionList) {
ExamQuestionSelectVo checkQuestionVo = new ExamQuestionSelectVo();
BeanUtils.copyProperties(question, checkQuestionVo);
checkQuestionVoList.add(checkQuestionVo);
}
examQuestionTypeVo.setExamQuestionSelectVoCheckList(checkQuestionVoList);
// 获取所有多选题列表并赋值到ExamVo的属性ExamQuestionSelectVoJudgeList上
List<ExamQuestionSelectVo> judgeQuestionVoList = new ArrayList<>();
List<Question> judgeQuestionList = questionRepository.findByQuestionTypeId(QuestionEnum.JUDGE.getId());
for (Question question : judgeQuestionList) {
ExamQuestionSelectVo judgeQuestionVo = new ExamQuestionSelectVo();
BeanUtils.copyProperties(question, judgeQuestionVo);
judgeQuestionVoList.add(judgeQuestionVo);
}
examQuestionTypeVo.setExamQuestionSelectVoJudgeList(judgeQuestionVoList);
return examQuestionTypeVo;
}
@Override
public Exam create(ExamCreateVo examCreateVo, String userId) {
// 在线考试系统创建
Exam exam = new Exam();
BeanUtils.copyProperties(examCreateVo, exam);
exam.setExamId(IdUtil.simpleUUID());
exam.setExamCreatorId(userId);
exam.setCreateTime(new Date());
exam.setUpdateTime(new Date());
// Todo:这两个日志后面是要在前端传入的,这里暂时定为当前日期
exam.setExamStartDate(new Date());
exam.setExamEndDate(new Date());
String radioIdsStr = "";
String checkIdsStr = "";
String judgeIdsStr = "";
List<ExamQuestionSelectVo> radios = examCreateVo.getRadios();
List<ExamQuestionSelectVo> checks = examCreateVo.getChecks();
List<ExamQuestionSelectVo> judges = examCreateVo.getJudges();
int radioCnt = 0, checkCnt = 0, judgeCnt = 0;
for (ExamQuestionSelectVo radio : radios) {
if (radio.getChecked()) {
radioIdsStr += radio.getQuestionId() + "-";
radioCnt++;
}
}
radioIdsStr = replaceLastSeparator(radioIdsStr);
for (ExamQuestionSelectVo check : checks) {
if (check.getChecked()) {
checkIdsStr += check.getQuestionId() + "-";
checkCnt++;
}
}
checkIdsStr = replaceLastSeparator(checkIdsStr);
for (ExamQuestionSelectVo judge : judges) {
if (judge.getChecked()) {
judgeIdsStr += judge.getQuestionId() + "-";
judgeCnt++;
}
}
judgeIdsStr = replaceLastSeparator(judgeIdsStr);
exam.setExamQuestionIds(radioIdsStr + "-" + checkIdsStr + "-" + judgeIdsStr);
// 设置各个题目的id
exam.setExamQuestionIdsRadio(radioIdsStr);
exam.setExamQuestionIdsCheck(checkIdsStr);
exam.setExamQuestionIdsJudge(judgeIdsStr);
// 计算总分数
int examScore = radioCnt * exam.getExamScoreRadio() + checkCnt * exam.getExamScoreCheck() + judgeCnt * exam.getExamScoreJudge();
exam.setExamScore(examScore);
examRepository.save(exam);
return exam;
}
@Override
public Exam update(ExamVo examVo, String userId) {
Exam exam = new Exam();
BeanUtils.copyProperties(examVo, exam);
exam.setExamCreatorId(userId); // 考试的更新人为最新的创建人
exam.setUpdateTime(new Date()); // 考试的更新日期要记录下
String radioIdsStr = "";
String checkIdsStr = "";
String judgeIdsStr = "";
List<ExamQuestionSelectVo> radios = examVo.getExamQuestionSelectVoRadioList();
List<ExamQuestionSelectVo> checks = examVo.getExamQuestionSelectVoCheckList();
List<ExamQuestionSelectVo> judges = examVo.getExamQuestionSelectVoJudgeList();
int radioCnt = 0, checkCnt = 0, judgeCnt = 0;
for (ExamQuestionSelectVo radio : radios) {
if (radio.getChecked()) {
radioIdsStr += radio.getQuestionId() + "-";
radioCnt++;
}
}
radioIdsStr = replaceLastSeparator(radioIdsStr);
for (ExamQuestionSelectVo check : checks) {
if (check.getChecked()) {
checkIdsStr += check.getQuestionId() + "-";
checkCnt++;
}
}
checkIdsStr = replaceLastSeparator(checkIdsStr);
for (ExamQuestionSelectVo judge : judges) {
if (judge.getChecked()) {
judgeIdsStr += judge.getQuestionId() + "-";
judgeCnt++;
}
}
judgeIdsStr = replaceLastSeparator(judgeIdsStr);
exam.setExamQuestionIds(radioIdsStr + "-" + checkIdsStr + "-" + judgeIdsStr);
// 设置各个题目的id
exam.setExamQuestionIdsRadio(radioIdsStr);
exam.setExamQuestionIdsCheck(checkIdsStr);
exam.setExamQuestionIdsJudge(judgeIdsStr);
// 计算总分数
int examScore = radioCnt * exam.getExamScoreRadio() + checkCnt * exam.getExamScoreCheck() + judgeCnt * exam.getExamScoreJudge();
exam.setExamScore(examScore);
examRepository.save(exam);
return exam;
}
@Override
public List<ExamCardVo> getExamCardList() {
List<Exam> examList = examRepository.findAll();
List<ExamCardVo> examCardVoList = new ArrayList<>();
for (Exam exam : examList) {
ExamCardVo examCardVo = new ExamCardVo();
BeanUtils.copyProperties(exam, examCardVo);
examCardVoList.add(examCardVo);
}
return examCardVoList;
}
@Override
public ExamDetailVo getExamDetail(String id) {
Exam exam = examRepository.findById(id).orElse(null);
ExamDetailVo examDetailVo = new ExamDetailVo();
examDetailVo.setExam(exam);
assert exam != null;
examDetailVo.setRadioIds(exam.getExamQuestionIdsRadio().split("-"));
examDetailVo.setCheckIds(exam.getExamQuestionIdsCheck().split("-"));
examDetailVo.setJudgeIds(exam.getExamQuestionIdsJudge().split("-"));
return examDetailVo;
}
@Override
public ExamRecord judge(String userId, String examId, HashMap<String, List<String>> answersMap) {
// 开始考试判分啦~~~
// 1.首先获取考试对象和选项数组
ExamDetailVo examDetailVo = getExamDetail(examId);
Exam exam = examDetailVo.getExam();
// 2.然后获取该考试下所有的题目信息
List<String> questionIds = new ArrayList<>();
// 2.1 题目id的数组
List<String> radioIdList = Arrays.asList(examDetailVo.getRadioIds());
List<String> checkIdList = Arrays.asList(examDetailVo.getCheckIds());
List<String> judgeIdList = Arrays.asList(examDetailVo.getJudgeIds());
questionIds.addAll(radioIdList);
questionIds.addAll(checkIdList);
questionIds.addAll(judgeIdList);
// 2.2 每种题目的分数
int radioScore = exam.getExamScoreRadio();
int checkScore = exam.getExamScoreCheck();
int judgeScore = exam.getExamScoreJudge();
// 2.3 根据问题id的数组拿到所有的问题对象供下面步骤用
List<Question> questionList = questionRepository.findAllById(questionIds);
Map<String, Question> questionMap = new HashMap<>();
for (Question question : questionList) {
questionMap.put(question.getQuestionId(), question);
}
// 3.根据正确答案和用户作答信息进行判分
Set<String> questionIdsAnswer = answersMap.keySet();
// 存储当前考试每个题目的得分情况
Map<String, Integer> judgeMap = new HashMap<>();
// 考生作答地每个题目的选项(题目和题目之间用$分隔,题目有多个选项地话用-分隔,题目和选项之间用_分隔),用于查看考试详情
// 例子题目1的id_作答选项1-作答选项2&题目2的id_作答选项1&题目3_作答选项1-作答选项2-作答选项3
StringBuilder answerOptionIdsSb = new StringBuilder();
// 用户此次考试的总分
int totalScore = 0;
for (String questionId : questionIdsAnswer) {
// 获取用户作答地这个题的答案信息
Question question = questionMap.get(questionId);
// 获取答案选项
String questionAnswerOptionIds = replaceLastSeparator(question.getQuestionAnswerOptionIds());
List<String> questionAnswerOptionIdList = Arrays.asList(questionAnswerOptionIds.split("-"));
Collections.sort(questionAnswerOptionIdList);
String answerStr = listConcat(questionAnswerOptionIdList);
// 获取用户作答
List<String> questionUserOptionIdList = answersMap.get(questionId);
Collections.sort(questionUserOptionIdList);
String userStr = listConcat(questionUserOptionIdList);
// 判断questionAnswerOptionIds和answersMap里面的答案是否相等
if (answerStr.equals(userStr)) {
// 说明题目作答正确,下面根据题型给分
int score = 0;
if (radioIdList.contains(questionId)) {
score = radioScore;
}
if (checkIdList.contains(questionId)) {
score = checkScore;
}
if (judgeIdList.contains(questionId)) {
score = judgeScore;
}
// 累计本次考试得分
totalScore += score;
// True代表题目答对
answerOptionIdsSb.append(questionId + "@True_" + userStr + "$");
judgeMap.put(questionId, score);
} else {
// 说明题目作答错误,直接判零分,False代表题目答错
answerOptionIdsSb.append(questionId + "@False_" + userStr + "$");
judgeMap.put(questionId, 0);
}
}
// 4.计算得分记录本次考试结果存到ExamRecord中
ExamRecord examRecord = new ExamRecord();
examRecord.setExamRecordId(IdUtil.simpleUUID());
examRecord.setExamId(examId);
// 注意去掉最后可能有的&_-
examRecord.setAnswerOptionIds(replaceLastSeparator(answerOptionIdsSb.toString()));
examRecord.setExamJoinerId(userId);
examRecord.setExamJoinDate(new Date());
examRecord.setExamJoinScore(totalScore);
examRecordRepository.save(examRecord);
return examRecord;
}
@Override
public List<ExamRecordVo> getExamRecordList(String userId) {
// 获取指定用户下的考试记录列表
List<ExamRecord> examRecordList = examRecordRepository.findByExamJoinerIdOrderByExamJoinDateDesc(userId);
List<ExamRecordVo> examRecordVoList = new ArrayList<>();
for (ExamRecord examRecord : examRecordList) {
ExamRecordVo examRecordVo = new ExamRecordVo();
Exam exam = examRepository.findById(examRecord.getExamId()).orElse(null);
examRecordVo.setExam(exam);
User user = userRepository.findById(userId).orElse(null);
examRecordVo.setUser(user);
examRecordVo.setExamRecord(examRecord);
examRecordVoList.add(examRecordVo);
}
return examRecordVoList;
}
@Override
public RecordDetailVo getRecordDetail(String recordId) {
// 获取考试详情的封装对象
ExamRecord record = examRecordRepository.findById(recordId).orElse(null);
RecordDetailVo recordDetailVo = new RecordDetailVo();
recordDetailVo.setExamRecord(record);
// 用户的答案,需要解析
HashMap<String, List<String>> answersMap = new HashMap<>();
HashMap<String, String> resultsMap = new HashMap<>();
assert record != null;
String answersStr = record.getAnswerOptionIds();
// $分隔题目,因为$在正则中有特殊用途(行尾),所以需要括起来
String[] questionArr = answersStr.split("[$]");
for (String questionStr : questionArr) {
System.out.println(questionStr);
// 区分开题目标题和选项
String[] questionTitleResultAndOption = questionStr.split("_");
String[] questionTitleAndResult = questionTitleResultAndOption[0].split("@");
String[] questionOptions = questionTitleResultAndOption[1].split("-");
// 题目:答案选项
answersMap.put(questionTitleAndResult[0], Arrays.asList(questionOptions));
// 题目True / False
resultsMap.put(questionTitleAndResult[0], questionTitleAndResult[1]);
}
recordDetailVo.setAnswersMap(answersMap);
recordDetailVo.setResultsMap(resultsMap);
// 下面再计算正确答案的map
ExamDetailVo examDetailVo = getExamDetail(record.getExamId());
List<String> questionIdList = new ArrayList<>();
questionIdList.addAll(Arrays.asList(examDetailVo.getRadioIds()));
questionIdList.addAll(Arrays.asList(examDetailVo.getCheckIds()));
questionIdList.addAll(Arrays.asList(examDetailVo.getJudgeIds()));
// 获取所有的问题对象
List<Question> questionList = questionRepository.findAllById(questionIdList);
HashMap<String, List<String>> answersRightMap = new HashMap<>();
for (Question question : questionList) {
// 记得去掉最后可能出现的特殊字符
String questionAnswerOptionIdsStr = replaceLastSeparator(question.getQuestionAnswerOptionIds());
String[] questionAnswerOptionIds = questionAnswerOptionIdsStr.split("-");
answersRightMap.put(question.getQuestionId(), Arrays.asList(questionAnswerOptionIds));
}
recordDetailVo.setAnswersRightMap(answersRightMap);
return recordDetailVo;
}
/**
* -
*
* @param str
* @return -
*/
private String replaceLastSeparator(String str) {
String lastChar = str.substring(str.length() - 1);
// 题目和题目之间用$分隔,题目有多个选项地话用-分隔,题目和选项之间用_分隔
if ("-".equals(lastChar) || "_".equals(lastChar) || "$".equals(lastChar)) {
str = StrUtil.sub(str, 0, str.length() - 1);
}
return str;
}
/**
* -
*
* @param strList
* @return -
*/
private String listConcat(List<String> strList) {
StringBuilder sb = new StringBuilder();
for (String str : strList) {
sb.append(str);
sb.append("-");
}
return replaceLastSeparator(sb.toString());
}
}

@ -0,0 +1,174 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-17 08:03
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.service.impl;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.IdUtil;
import lsgwr.exam.dto.RegisterDTO;
import lsgwr.exam.entity.Action;
import lsgwr.exam.entity.Page;
import lsgwr.exam.entity.Role;
import lsgwr.exam.entity.User;
import lsgwr.exam.enums.LoginTypeEnum;
import lsgwr.exam.enums.RoleEnum;
import lsgwr.exam.qo.LoginQo;
import lsgwr.exam.repository.ActionRepository;
import lsgwr.exam.repository.PageRepository;
import lsgwr.exam.repository.RoleRepository;
import lsgwr.exam.repository.UserRepository;
import lsgwr.exam.service.UserService;
import lsgwr.exam.utils.JwtUtils;
import lsgwr.exam.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
UserRepository userRepository;
@Autowired
RoleRepository roleRepository;
@Autowired
PageRepository pageRepository;
@Autowired
ActionRepository actionRepository;
@Override
public User register(RegisterDTO registerDTO) {
try {
User user = new User();
user.setUserId(IdUtil.simpleUUID());
// 好像还缺少个用户名,用"exam_user_手机号"来注册需要校验唯一性数据字段已经设置unique了失败会异常地
String defaultUsername = "user";
user.setUserUsername(defaultUsername + "_" + registerDTO.getMobile());
// 初始化昵称和用户名相同
user.setUserNickname(user.getUserUsername());
// 这里还需要进行加密处理后续解密用Base64.decode()
user.setUserPassword(Base64.encode(registerDTO.getPassword()));
// 默认设置为学生身份,需要老师和学生身份地话需要管理员修改
user.setUserRoleId(RoleEnum.STUDENT.getId());
// 设置头像图片地址, 先默认一个地址,后面用户可以自己再改
String defaultAvatar = "http://d.lanrentuku.com/down/png/1904/business_avatar/8_avatar_2754583.png";
user.setUserAvatar(defaultAvatar);
// 设置描述信息,随便设置段默认的
user.setUserDescription("welcome to online exam system");
// 需要验证这个邮箱是不是已经存在数据字段已经设置unique了失败会异常地
user.setUserEmail(registerDTO.getEmail());
// 需要验证手机号是否已经存在数据字段已经设置unique了失败会异常地
user.setUserPhone(registerDTO.getMobile());
userRepository.save(user);
System.out.println(user);
return user;
} catch (Exception e) {
e.printStackTrace(); // 用户已经存在
// 出异常返回null表示注册失败
return null;
}
}
@Override
public String login(LoginQo loginQo) {
User user;
if (LoginTypeEnum.USERNAME.getType().equals(loginQo.getLoginType())) {
// 登陆者用地是用户名
user = userRepository.findByUserUsername(loginQo.getUserInfo());
} else {
// 登陆者用地是邮箱
user = userRepository.findByUserEmail(loginQo.getUserInfo());
}
if (user != null) {
// 如果user不是null即能找到才能验证用户名和密码
// 数据库存的密码
String passwordDb = Base64.decodeStr(user.getUserPassword());
// 用户请求参数中的密码
String passwordQo = loginQo.getPassword();
System.out.println(passwordDb);
System.out.println(passwordQo);
if (passwordQo.equals(passwordDb)) {
// 如果密码相等地话说明认证成功,返回生成的token有效期为一天
return JwtUtils.genJsonWebToken(user);
}
}
return null;
}
@Override
public UserVo getUserInfo(String userId) {
User user = userRepository.findById(userId).orElse(null);
UserVo userVo = new UserVo();
assert user != null;
BeanUtils.copyProperties(user, userVo);
return userVo;
}
@Override
public UserInfoVo getInfo(String userId) {
User user = userRepository.findById(userId).orElse(null);
assert user != null;
UserInfoVo userInfoVo = new UserInfoVo();
// 1.尽可能的拷贝属性
BeanUtils.copyProperties(user, userInfoVo);
Integer roleId = user.getUserRoleId();
Role role = roleRepository.findById(roleId).orElse(null);
assert role != null;
String roleName = role.getRoleName();
// 2.设置角色名称
userInfoVo.setRoleName(roleName);
// 3.设置当前用户的角色细节
RoleVo roleVo = new RoleVo();
BeanUtils.copyProperties(role, roleVo);
// 4.设置角色的可访问页面
String rolePageIds = role.getRolePageIds();
String[] pageIdArr = rolePageIds.split("-");
List<PageVo> pageVoList = new ArrayList<>();
for (String pageIdStr : pageIdArr) {
// 获取页面的id
Integer pageId = Integer.parseInt(pageIdStr);
// 4.1 向Role中添加Page
Page page = pageRepository.findById(pageId).orElse(null);
PageVo pageVo = new PageVo();
BeanUtils.copyProperties(page, pageVo);
// 4.2 向Page中添加action
List<ActionVo> actionVoList = new ArrayList<>();
String actionIdsStr = page.getActionIds();
String[] actionIdArr = actionIdsStr.split("-");
for (String actionIdStr : actionIdArr) {
Integer actionId = Integer.parseInt(actionIdStr);
Action action = actionRepository.findById(actionId).orElse(null);
ActionVo actionVo = new ActionVo();
assert action != null;
BeanUtils.copyProperties(action, actionVo);
actionVoList.add(actionVo);
}
// 设置actionVoList到pageVo中然后把pageVo加到pageVoList中
pageVo.setActionVoList(actionVoList);
// 设置pageVoList下面再设置到RoleVo中
pageVoList.add(pageVo);
}
// 设置PageVo的集合到RoleVo中
roleVo.setPageVoList(pageVoList);
// 最终把PageVo设置到UserInfoVo中这样就完成了拼接
userInfoVo.setRoleVo(roleVo);
return userInfoVo;
}
}

@ -0,0 +1,5 @@
/*
* Created By Liang Shan Guang at 2019-05-14 08:20
* Description :
*/
package lsgwr.exam.service;

@ -0,0 +1,126 @@
package lsgwr.exam.utils;
import cn.hutool.core.io.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/***********************************************************
* @note :
* @author : 广
* @version : V1.0 at 2019/5/19 16:15
***********************************************************/
@Slf4j
public class FileTransUtil {
/**
*
*
* @param uploadfile
* @param dir
* @return
*/
public static String uploadFile(MultipartFile uploadfile, String dir) {
log.info("Single file upload!");
if (uploadfile.isEmpty()) {
return "文件名不能为空";
}
try {
saveUploadedFiles(Arrays.asList(uploadfile), dir);
} catch (IOException e) {
e.printStackTrace();
return "后台服务异常";
}
log.info("file upload successfully! " + dir);
return "文件上传成功";
}
/**
*
*
* @param uploadfiles
* @param dir
* @return
*/
public static String uploadFiles(MultipartFile[] uploadfiles, String dir) {
log.debug("Multiple file upload!");
String uploadedFileName = Arrays.stream(uploadfiles).map(x -> x.getOriginalFilename()).filter(x -> !StringUtils.isEmpty(x)).collect(Collectors.joining(" , "));
if (StringUtils.isEmpty(uploadedFileName)) {
return "文件名不能为空";
}
try {
FileTransUtil.saveUploadedFiles(Arrays.asList(uploadfiles), dir);
} catch (IOException e) {
return "后台服务异常";
}
log.info("file upload successfully! " + uploadedFileName);
return "文件上传成功";
}
/**
*
*
* @param files
* @throws IOException
*/
public static void saveUploadedFiles(List<MultipartFile> files, String dir) throws IOException {
for (MultipartFile file : files) {
if (file.isEmpty()) {
continue;
}
if (!FileUtil.exist(dir)) {
// 文件夹不存在就创建
FileUtil.mkdir(dir);
}
byte[] bytes = file.getBytes();
String fileName = file.getOriginalFilename().replace("\\", "/");
if (fileName.lastIndexOf('/')>0){
// 上传文件夹的时候会有这种情况
String fileDir = dir + "/" + fileName.substring(0, fileName.lastIndexOf('/'));
if (!FileUtil.exist(fileDir)) {
// 文件夹不存在就创建,创建文件夹的时候会用到
FileUtil.mkdir(fileDir);
}
}
Path path = Paths.get(dir + "/" + fileName);
Files.write(path, bytes);
}
}
/**
*
*
* @param filePath
* @return
* @throws IOException
*/
public static ResponseEntity<InputStreamResource> downloadFile(String filePath) throws IOException {
log.info("downloading file : " + filePath);
FileSystemResource file = new FileSystemResource(filePath);
HttpHeaders headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Content-Disposition", String.format("attachment; filename=\"%s\"", new String(file.getFilename().getBytes("gbk"), "iso-8859-1")));
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
System.out.println(file.getFilename());
return ResponseEntity
.ok()
.headers(headers)
.contentLength(file.contentLength())
.contentType(MediaType.parseMediaType("application/octet-stream"))
.body(new InputStreamResource(file.getInputStream()));
}
}

@ -0,0 +1,156 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-19 10:27
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.utils;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
@Service
public class FileUtils {
/**
* urlfile
*
* @param url
* @param suffix
*/
public static File createFileByUrl(String url, String suffix) {
byte[] byteFile = getImageFromNetByUrl(url);
if (byteFile != null) {
File file = getFileFromBytes(byteFile, suffix);
return file;
} else {
return null;
}
}
/**
*
*
* @param strUrl
* @return
*/
private static byte[] getImageFromNetByUrl(String strUrl) {
try {
URL url = new URL(strUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5 * 1000);
// 通过输入流获取图片数据
InputStream inStream = conn.getInputStream();
// 得到图片的二进制数据
byte[] btImg = readInputStream(inStream);
return btImg;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
*
*
* @param inStream
* @return
* @throws Exception
*/
private static byte[] readInputStream(InputStream inStream) throws Exception {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, len);
}
inStream.close();
return outStream.toByteArray();
}
// 创建临时文件
private static File getFileFromBytes(byte[] b, String suffix) {
BufferedOutputStream stream = null;
File file = null;
try {
file = File.createTempFile("pattern", "." + suffix);
System.out.println("临时文件位置:" + file.getCanonicalPath());
FileOutputStream fstream = new FileOutputStream(file);
stream = new BufferedOutputStream(fstream);
stream.write(b);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return file;
}
public static MultipartFile createImg(String url) {
try {
// File转换成MutipartFile
File file = FileUtils.createFileByUrl(url, "jpg");
FileInputStream inputStream = new FileInputStream(file);
MultipartFile multipartFile = new MockMultipartFile(file.getName(), inputStream);
return multipartFile;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public static MultipartFile fileToMultipart(String filePath) {
try {
// File转换成MutipartFile
File file = new File(filePath);
FileInputStream inputStream = new FileInputStream(file);
MultipartFile multipartFile = new MockMultipartFile(file.getName(), "png", "image/png", inputStream);
return multipartFile;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
FileUtils.createFileByUrl("http://122.112.151.149:8888/group1/M00/00/00/wKgAkF0HyPeAAisRAADs167VCfA155.png", "png");
FileUtils.createImg("http://122.112.151.149:8888/group1/M00/00/00/wKgAkF0HyPeAAisRAADs167VCfA155.png");
}
public static boolean base64ToFile(String filePath, String base64Data) throws Exception {
String dataPrix = "";
String data = "";
if (base64Data == null || "".equals(base64Data)) {
return false;
} else {
String[] d = base64Data.split("base64,");
if (d != null && d.length == 2) {
dataPrix = d[0];
data = d[1];
} else {
return false;
}
}
// 因为BASE64Decoder的jar问题此处使用spring框架提供的工具包
byte[] bs = Base64Utils.decodeFromString(data);
// 使用apache提供的工具类操作流
org.apache.commons.io.FileUtils.writeByteArrayToFile(new File(filePath), bs);
return true;
}
}

@ -0,0 +1,59 @@
/***********************************************************
* @Description : JWTJWTtokentoken
* @author : 广(Laing Shan Guang)
* @date : 2019-05-21 08:15
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.utils;
import lsgwr.exam.entity.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
public class JwtUtils {
/**
* token
*/
private static final String SUBJECT = "lsg_exam";
/**
* 1
*/
private static final long EXPIRE = 1000 * 60 * 60 * 24;
private static final String APP_SECRET = "liangshanguang";
public static String genJsonWebToken(User user) {
if (user == null || user.getUserId() == null || user.getUserUsername() == null || user.getUserAvatar() == null) {
return null;
}
return Jwts.builder().setSubject(SUBJECT)
// 下面3行设置token中间字段携带用户的信息
.claim("id", user.getUserId())
.claim("username", user.getUserUsername())
.claim("avatar", user.getUserAvatar())
.setIssuedAt(new Date())
// 设置过期时间
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
.signWith(SignatureAlgorithm.HS256, APP_SECRET)
// 生成的结果字符串太长,这里压缩下
.compact();
}
/**
* token
*
* @param token token
* @return
*/
public static Claims checkJWT(String token) {
try {
return Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(token).getBody();
} catch (Exception e) {
// 篡改token会导致校验失败走到异常分支这里返回null
return null;
}
}
}

@ -0,0 +1,29 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-17 07:43
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.utils;
import lsgwr.exam.vo.ResultVO;
public class ResultVOUtil {
public static ResultVO success(Integer code, String msg, Object object) {
return new ResultVO(code, msg, object);
}
public static ResultVO success(Object object) {
return new ResultVO(0, "成功", object);
}
public static ResultVO success() {
return new ResultVO(0, "成功", null);
}
public static ResultVO error(Integer code, String msg) {
return new ResultVO(code, msg, null);
}
}

@ -0,0 +1,5 @@
/*
* Created By Liang Shan Guang at 2019-05-14 08:19
* Description : , Hutool
*/
package lsgwr.exam.utils;

@ -0,0 +1,22 @@
/***********************************************************
* @Description : Action
* @author : 广(Laing Shan Guang)
* @date : 2019-05-26 13:50
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class ActionVo {
@JsonProperty("action")
private String actionName;
@JsonProperty("describe")
private String actionDescription;
@JsonProperty("defaultCheck")
private Boolean defaultCheck;
}

@ -0,0 +1,29 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-06-23 19:30
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class ExamCardVo {
@JsonProperty("id")
private String examId;
@JsonProperty("title")
private String examName;
@JsonProperty("avatar")
private String examAvatar;
@JsonProperty("content")
private String examDescription;
@JsonProperty("score")
private Integer examScore;
/**
*
*/
@JsonProperty("elapse")
private Integer examTimeLimit;
}

@ -0,0 +1,65 @@
/***********************************************************
* @Description : examCreatorIdtoken
* @author : 广(Laing Shan Guang)
* @date : 2019-06-17 08:14
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class ExamCreateVo {
@JsonProperty("name")
private String examName;
@JsonProperty("avatar")
private String examAvatar;
@JsonProperty("desc")
private String examDescription;
/**
*
*/
@JsonProperty("elapse")
private Integer examTimeLimit;
/**
*
*/
private List<ExamQuestionSelectVo> radios;
/**
*
*/
private List<ExamQuestionSelectVo> checks;
/**
*
*/
private List<ExamQuestionSelectVo> judges;
/**
*
*/
@JsonProperty("radioScore")
private Integer examScoreRadio;
/**
*
*/
@JsonProperty("checkScore")
private Integer examScoreCheck;
/**
*
*/
@JsonProperty("judgeScore")
private Integer examScoreJudge;
}

@ -0,0 +1,34 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-06-24 08:14
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import lsgwr.exam.entity.Exam;
import lombok.Data;
@Data
public class ExamDetailVo {
/**
*
*/
private Exam exam;
/**
* id
*/
private String[] radioIds;
/**
* id
*/
private String[] checkIds;
/**
* id
*/
private String[] judgeIds;
}

@ -0,0 +1,41 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-06-22 17:00
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class ExamPageVo {
/**
*
*/
private Integer pageSize;
/**
* 1
*/
private Integer pageNo;
/**
*
*/
private Long totalCount;
/**
*
*/
private Integer totalPage;
/**
*
*/
@JsonProperty("data")
private List<ExamVo> examVoList;
}

@ -0,0 +1,26 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-06-17 23:10
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class ExamQuestionSelectVo {
@JsonProperty("id")
private String questionId;
@JsonProperty("name")
private String questionName;
/**
* .falsetrue
*
*/
@JsonProperty("checked")
private Boolean checked = false;
}

@ -0,0 +1,24 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-06-23 11:00
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class ExamQuestionTypeVo {
@JsonProperty("radios")
private List<ExamQuestionSelectVo> examQuestionSelectVoRadioList;
@JsonProperty("checks")
private List<ExamQuestionSelectVo> examQuestionSelectVoCheckList;
@JsonProperty("judges")
private List<ExamQuestionSelectVo> examQuestionSelectVoJudgeList;
}

@ -0,0 +1,30 @@
/***********************************************************
* @Description : VO
* @author : 广(Liang Shan Guang)
* @date : 2019/10/25 7:42
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import lsgwr.exam.entity.Exam;
import lsgwr.exam.entity.ExamRecord;
import lsgwr.exam.entity.User;
import lombok.Data;
@Data
public class ExamRecordVo {
/**
*
*/
private Exam exam;
/**
*
*/
private ExamRecord examRecord;
/**
*
*/
private User user;
}

@ -0,0 +1,89 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019/5/14 07:42
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.Date;
import java.util.List;
@Data
public class ExamVo {
@JsonProperty("id")
private String examId;
@JsonProperty("name")
private String examName;
@JsonProperty("avatar")
private String examAvatar;
@JsonProperty("desc")
private String examDescription;
@JsonProperty("radios")
private List<ExamQuestionSelectVo> examQuestionSelectVoRadioList;
@JsonProperty("checks")
private List<ExamQuestionSelectVo> examQuestionSelectVoCheckList;
@JsonProperty("judges")
private List<ExamQuestionSelectVo> examQuestionSelectVoJudgeList;
@JsonProperty("score")
private Integer examScore;
@JsonProperty("radioScore")
private Integer examScoreRadio;
@JsonProperty("checkScore")
private Integer examScoreCheck;
@JsonProperty("judgeScore")
private Integer examScoreJudge;
/**
* id
*/
@JsonProperty("creator")
private String examCreator;
/**
*
*/
@JsonProperty("elapse")
private Integer examTimeLimit;
/**
*
*/
@JsonProperty("startDate")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date examStartDate;
/**
*
*/
@JsonProperty("endDate")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date examEndDate;
/**
*
*/
@JsonProperty("createTime")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
*
*/
@JsonProperty("updateTime")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}

@ -0,0 +1,81 @@
package lsgwr.exam.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
*
*
* @author liangshanguang
* @date 2019-05-22 08:11
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class JsonData implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 0 1-1
*/
private Integer code;
/**
*
*/
private Object data;
/**
*
*/
private String msg;
/**
*
*/
public static JsonData buildSuccess() {
return new JsonData(0, null, null);
}
/**
*
*/
public static JsonData buildSuccess(Object data) {
return new JsonData(0, data, null);
}
/**
*
*/
public static JsonData buildError(String msg) {
return new JsonData(-1, null, msg);
}
/**
* ,
*/
public static JsonData buildError(String msg, Integer code) {
return new JsonData(code, null, msg);
}
/**
* ,
*
* @param data
* @param msg
* @return
*/
public static JsonData buildSuccess(Object data, String msg) {
return new JsonData(0, data, msg);
}
/**
* ,
*/
public static JsonData buildSuccess(Object data, int code) {
return new JsonData(code, data, null);
}
}

@ -0,0 +1,24 @@
/***********************************************************
* @Description : Action
* @author : 广(Laing Shan Guang)
* @date : 2019-05-26 13:46
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class PageVo {
@JsonProperty("actionEntitySet")
private List<ActionVo> actionVoList;
@JsonProperty("permissionId")
private String pageName;
@JsonProperty("permissionName")
private String pageDescription;
}

@ -0,0 +1,54 @@
/***********************************************************
* @Description : ,
* @author : 广(Laing Shan Guang)
* @date : 2019-06-02 13:26
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class QuestionCreateSimplifyVo {
/**
*
*/
@JsonProperty("name")
private String questionName;
@JsonProperty("desc")
private String questionDescription;
/**
* id
*/
@JsonProperty("level")
private Integer questionLevelId;
/**
* ()
*/
@JsonProperty("type")
private Integer questionTypeId;
/**
*
*/
@JsonProperty("category")
private Integer questionCategoryId;
/**
*
*/
@JsonProperty("option")
private String option;
/**
* truefalse
*/
@JsonProperty("options")
private List<QuestionOptionCreateVo> questionOptionCreateVoList;
}

@ -0,0 +1,60 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-06-02 13:26
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class QuestionCreateVo {
/**
*
*/
@JsonProperty("name")
private String questionName;
@JsonProperty("desc")
private String questionDescription;
/**
* ,5
*/
@JsonProperty("score")
private Integer questionScore = 5;
/**
* idtoken
*/
@JsonProperty("creator")
private String questionCreatorId;
/**
* id
*/
@JsonProperty("level")
private Integer questionLevelId;
/**
* ()
*/
@JsonProperty("type")
private Integer questionTypeId;
/**
*
*/
@JsonProperty("category")
private Integer questionCategoryId;
/**
* truefalse
*/
@JsonProperty("options")
private List<QuestionOptionCreateVo> questionOptionCreateVoList;
}

@ -0,0 +1,43 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-10-20 09:51
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import lsgwr.exam.entity.QuestionOption;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class QuestionDetailVo {
/**
* id
*/
private String id;
/**
*
*/
private String name;
/**
*
*/
private String description;
/**
*
*/
private String type;
/**
*
*/
private List<QuestionOption> options;
/**
* ,id
*/
private List<String> answers = new ArrayList<>();
}

@ -0,0 +1,27 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-06-02 20:23
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class QuestionOptionCreateVo {
/**
*
*/
@JsonProperty("content")
private String questionOptionContent;
/**
*
*/
@JsonProperty("answer")
private Boolean answer = false;
}

@ -0,0 +1,25 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-06-01 09:45
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class QuestionOptionVo {
@JsonProperty("id")
private String questionOptionId;
@JsonProperty("content")
private String questionOptionContent;
@JsonProperty("answer")
private Boolean answer = false;
@JsonProperty("description")
private String questionOptionDescription;
}

@ -0,0 +1,42 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-28 22:09
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class QuestionPageVo {
/**
*
*/
private Integer pageSize;
/**
* 1
*/
private Integer pageNo;
/**
*
*/
private Long totalCount;
/**
*
*/
private Integer totalPage;
/**
*
*/
@JsonProperty("data")
private List<QuestionVo> questionVoList;
}

@ -0,0 +1,27 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-06-03 07:35
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lsgwr.exam.entity.QuestionCategory;
import lsgwr.exam.entity.QuestionLevel;
import lsgwr.exam.entity.QuestionType;
import lombok.Data;
import java.util.List;
@Data
public class QuestionSelectionVo {
@JsonProperty("types")
private List<QuestionType> questionTypeList;
@JsonProperty("categories")
private List<QuestionCategory> questionCategoryList;
@JsonProperty("levels")
private List<QuestionLevel> questionLevelList;
}

@ -0,0 +1,86 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-28 08:17
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.Date;
import java.util.List;
@Data
public class QuestionVo {
@JsonProperty("id")
private String questionId;
@JsonProperty("name")
private String questionName;
@JsonProperty("score")
private Integer questionScore;
/**
* questionCreatorId
*/
@JsonProperty("creator")
private String questionCreator;
/**
* questionLevelId
*/
@JsonProperty("level")
private String questionLevel;
/**
* question_levelid
*/
@JsonProperty("levelId")
private int questionLevelId;
/**
* questionTypeId
*/
@JsonProperty("type")
private String questionType;
/**
* question_typeid
*/
@JsonProperty("typeId")
private int questionTypeId;
/**
* questionCategoryId
*/
@JsonProperty("category")
private String questionCategory;
/**
* question_categoryid
*/
@JsonProperty("categoryId")
private int questionCategoryId;
@JsonProperty("description")
private String questionDescription;
/**
* questionOptionIds,isAnswer
*/
@JsonProperty("options")
private List<QuestionOptionVo> questionOptionVoList;
/**
* Java
* @DynamicUpdate
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}

@ -0,0 +1,35 @@
/***********************************************************
* @Description : VO
* @author : 广(Liang Shan Guang)
* @date : 2019/10/27 15:37
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import lsgwr.exam.entity.ExamRecord;
import lombok.Data;
import java.util.HashMap;
import java.util.List;
@Data
public class RecordDetailVo {
/**
*
*/
private ExamRecord examRecord;
/**
* , idid
*/
private HashMap<String, List<String>> answersMap;
/**
* MapidTrue or False
*/
private HashMap<String, String> resultsMap;
/**
* idid
*/
private HashMap<String, List<String>> answersRightMap;
}

@ -0,0 +1,40 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-17 07:42
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL) // 避免返回NULL的字段
public class ResultVO<T> {
public ResultVO(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public ResultVO() {
}
/**
*
*/
private Integer code;
/**
*
*/
private String msg = "";
/**
*
*/
private T data;
}

@ -0,0 +1,27 @@
/***********************************************************
* @Description :
* @author : 广(Laing Shan Guang)
* @date : 2019-05-26 13:27
* @email : liangshanguang2@gmail.com
***********************************************************/
package lsgwr.exam.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class RoleVo {
@JsonProperty("id")
private String roleName;
@JsonProperty("name")
private String roleDescription;
@JsonProperty("describe")
private String roleDetail;
@JsonProperty("permissions")
private List<PageVo> pageVoList;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save