, ResultCode> builder = ImmutableMap.builder();
+
+ @ExceptionHandler(Exception.class)
+ @ResponseBody
+ public ResponseResult exception(Exception exception) {
+ exception.printStackTrace();
+ //记录日志
+ LOGGER.error("catch exception:{}", exception.getMessage());
+ if (EXCEPTIONS == null) {
+ EXCEPTIONS = builder.build();//EXCEPTION构建成功
+ }
+ //从EXCEPTIONS中找到异常类型所对应的错误代码,如果找到了,将错误代码相应给用户,如果找不到则给用户相应99999
+ ResultCode resultCode = EXCEPTIONS.get(exception.getClass());
+ if (resultCode != null) {
+ return new ResponseResult(resultCode);
+ }
+ //返回99999异常
+ return new ResponseResult(CommonCode.SERVER_ERROR);
+ }
+
+ static {
+ //定义异常类型所对应的错误代码
+ builder.put(HttpMessageNotReadableException.class, CommonCode.INVALID_PARAM);
+ }
+
+ @ExceptionHandler(CustomException.class)//捕获CustomException类型异常
+ @ResponseBody
+ public ResponseResult customException(CustomException customException) {
+ customException.printStackTrace();
+ //记录日志
+ LOGGER.error("catch exception:{}", customException.getMessage());
+
+ ResultCode resultCode = customException.getResultCode();
+ return new ResponseResult(resultCode);
+ }
+}
diff --git a/src/main/java/com/msdw/tms/common/exception/RRException.java b/src/main/java/com/msdw/tms/common/exception/RRException.java
new file mode 100644
index 0000000..41eee66
--- /dev/null
+++ b/src/main/java/com/msdw/tms/common/exception/RRException.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2016-2019 人人开源 All rights reserved.
+ *
+ * https://www.renren.io
+ *
+ * 版权所有,侵权必究!
+ */
+
+package com.msdw.tms.common.exception;
+
+/**
+ * 自定义异常
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public class RRException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ private String msg;
+ private int code = 500;
+
+ public RRException(String msg) {
+ super(msg);
+ this.msg = msg;
+ }
+
+ public RRException(String msg, Throwable e) {
+ super(msg, e);
+ this.msg = msg;
+ }
+
+ public RRException(String msg, int code) {
+ super(msg);
+ this.msg = msg;
+ this.code = code;
+ }
+
+ public RRException(String msg, int code, Throwable e) {
+ super(msg, e);
+ this.msg = msg;
+ this.code = code;
+ }
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+
+
+}
diff --git a/src/main/java/com/msdw/tms/common/utils/AliyunOssUtil.java b/src/main/java/com/msdw/tms/common/utils/AliyunOssUtil.java
new file mode 100644
index 0000000..05084d7
--- /dev/null
+++ b/src/main/java/com/msdw/tms/common/utils/AliyunOssUtil.java
@@ -0,0 +1,315 @@
+package com.msdw.tms.common.utils;
+
+import com.aliyun.oss.ClientException;
+import com.aliyun.oss.OSSClient;
+import com.aliyun.oss.OSSException;
+import com.aliyun.oss.model.*;
+import com.msdw.tms.config.AliyunOssConfig;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+
+public class AliyunOssUtil {
+
+ private static String sdf = new SimpleDateFormat("yyyyMMdd").format(new Date());
+
+ /**
+ * 创建存储空间
+ *
+ * @param client
+ * @param config
+ */
+ public static void createBucket(OSSClient client, AliyunOssConfig config) {
+ // 判断存储空间是否存在,不存在,则创建
+ if (!client.doesBucketExist(config.getBucketName())) {
+ CreateBucketRequest bucketRequest = new CreateBucketRequest(null);
+ // 设置仓库名称
+ bucketRequest.setBucketName(config.getBucketName());
+ // 设置仓库权限
+ bucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
+ // 创建仓库
+ client.createBucket(bucketRequest);
+ }
+ }
+
+ /**
+ * 上传文件
+ *
+ * @param file 需要上传的文件
+ * @param client
+ * @param config
+ * @return
+ * @throws OSSException
+ * @throws ClientException
+ * @throws IOException
+ */
+ public static FilesResult uploadFiles(MultipartFile file, OSSClient client, AliyunOssConfig config) throws OSSException, ClientException, IOException {
+ FilesResult result = new FilesResult();
+ // 创建存储空间
+ createBucket(client, config);
+ // 获取文件名
+ String fileUrl = file.getOriginalFilename();
+ // 获取文件尾缀
+ String ext = fileUrl.substring(fileUrl.lastIndexOf("."));
+ // 获取文件类型
+ String fileType = getFileType(ext);
+ //创建文件
+ String folderName = ext.substring(ext.indexOf(".") + 1);
+ String folder = createFolder(client, config.getBucketName(), folderName);
+ // 组合储存路径
+ String fileName = folder + "/" + sdf + "/" + System.currentTimeMillis() + ext;
+ long fileSize = file.getSize();
+
+ ObjectMetadata metadata = new ObjectMetadata();
+ // 指定该Object被下载时的网页的缓存行为
+ metadata.setCacheControl("no-cache");
+ // 指定该Object下设置Header
+ metadata.setHeader("Pragma", "no-cache");
+ // 指定该Object被下载时的内容编码格式
+ metadata.setContentEncoding("utf-8");
+ // 文件的MIME,定义文件的类型及网页编码,决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成,
+ // 如果没有扩展名则填默认值application/octet-stream
+ metadata.setContentType(fileType);
+ // 指定该Object被下载时的名称(指示MINME用户代理如何显示附加的文件,打开或下载,及文件名称)
+ metadata.setContentDisposition("filename/filesize=" + file.getName() + "/" + fileSize + "Byte.");
+ // 上传文件 (上传文件流的形式)
+ client.putObject(config.getBucketName(), fileName, new ByteArrayInputStream(file.getBytes()), metadata);
+ result.setFileName(fileName);
+ result.setFileUrl(config.getSufferUrl() + fileName);
+
+ if (null != client)
+ client.shutdown();
+
+ return result;
+ }
+
+ /**
+ * 用户头像上传
+ *
+ * @param file 需要上传的文件
+ * @param client
+ * @param config
+ * @return
+ * @throws OSSException
+ * @throws ClientException
+ * @throws IOException
+ */
+ public static FilesResult uploadUserAvatars(MultipartFile file, OSSClient client, AliyunOssConfig config) throws OSSException, ClientException, IOException {
+ FilesResult result = new FilesResult();
+ String userAvatars = config.getUserAvatars();
+ // 创建存储空间
+ createBucket(client, config);
+ // 获取文件名
+ String fileUrl = file.getOriginalFilename();
+ // 获取文件尾缀
+ String ext = fileUrl.substring(fileUrl.lastIndexOf("."));
+ // 获取文件类型
+ String fileType = getFileType(ext);
+ // 组合储存路径
+ String fileName = userAvatars + "/" + sdf + "/" + System.currentTimeMillis() + ext;
+ long fileSize = file.getSize();
+
+ ObjectMetadata metadata = new ObjectMetadata();
+ // 指定该Object被下载时的网页的缓存行为
+ metadata.setCacheControl("no-cache");
+ // 指定该Object下设置Header
+ metadata.setHeader("Pragma", "no-cache");
+ // 指定该Object被下载时的内容编码格式
+ metadata.setContentEncoding("utf-8");
+ // 文件的MIME,定义文件的类型及网页编码,决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成,
+ // 如果没有扩展名则填默认值application/octet-stream
+ metadata.setContentType(fileType);
+ // 指定该Object被下载时的名称(指示MINME用户代理如何显示附加的文件,打开或下载,及文件名称)
+ metadata.setContentDisposition("filename/filesize=" + file.getName() + "/" + fileSize + "Byte.");
+ // 上传文件 (上传文件流的形式)
+ client.putObject(config.getBucketName(), fileName, new ByteArrayInputStream(file.getBytes()), metadata);
+ result.setFileName(fileName);
+ result.setFileUrl(config.getSufferUrl() + fileName);
+
+ if (null != client)
+ client.shutdown();
+
+ return result;
+ }
+
+ /**
+ * 简单上传
+ *
+ * @param client
+ * @param config
+ * @param objectName 表示上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
+ * @param stream
+ * @return
+ */
+ public static FilesResult uploadFiles(OSSClient client, AliyunOssConfig config, String objectName, ByteArrayInputStream stream) {
+ FilesResult result = new FilesResult();
+ try {
+ PutObjectRequest putObjectRequest = new PutObjectRequest(config.getBucketName(), objectName, stream);
+ client.putObject(putObjectRequest);
+ result.setFileName(objectName);
+ result.setFileUrl(config.getSufferUrl() + objectName);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw e;
+ } finally {
+ if (null != client)
+ client.shutdown();
+ }
+ return result;
+ }
+
+ /**
+ * 文件下载
+ *
+ * @param response
+ * @param client
+ * @param config
+ * @param objectName
+ */
+ public static void downloadFiles(HttpServletResponse response, OSSClient client, AliyunOssConfig config,
+ String objectName) throws IOException {
+
+ OSSObject ossObject = client.getObject(config.getBucketName(), objectName);
+ InputStream input = null;
+ OutputStream outputStream = null;
+ try {
+ // 获取文件名
+ String fileName = objectName.substring(objectName.lastIndexOf("/") + 1);
+ //获取输入流
+ input = ossObject.getObjectContent();
+ // 获取OutputStream输出流
+ outputStream = response.getOutputStream();
+ byte[] buffer = new byte[input.available()];
+
+ response.setHeader("content-Type", "application/vnd.ms-excel");
+ response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
+ response.flushBuffer();
+
+ for (int length = 0; (length = input.read(buffer)) > 0; ) {
+ outputStream.write(buffer, 0, length);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw e;
+ } finally {
+ if (null != outputStream) {
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ if (null != input) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ if (null != client)
+ client.shutdown();
+ }
+
+ }
+
+ /**
+ * 删除存储空间buckName
+ *
+ * @param ossClient oss对象
+ * @param bucketName 存储空间
+ */
+ public static void deleteBucket(OSSClient ossClient, String bucketName) {
+ ossClient.deleteBucket(bucketName);
+ }
+
+ /**
+ * 创建模拟文件夹
+ *
+ * @param ossClient oss连接
+ * @param bucketName 存储空间
+ * @param folder 模拟文件夹名如"qj_nanjing/"
+ * @return
+ */
+ public static String createFolder(OSSClient ossClient, String bucketName, String folder) {
+ // 文件夹名
+ final String keySuffixWithSlash = folder;
+ // 判断文件夹是否存在,不存在则创建
+ if (!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)) {
+ // 创建文件夹
+ ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
+ // 得到文件夹名
+ OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash);
+ String fileDir = object.getKey();
+ return fileDir;
+ }
+ return keySuffixWithSlash;
+ }
+
+ /**
+ * 根据key删除OSS服务器上的文件
+ *
+ * @param ossClient oss连接
+ * @param bucketName 存储空间
+ * @param fileName 模拟文件夹名 如"qj_nanjing/"
+ */
+ public static void deleteFile(OSSClient ossClient, String bucketName, String fileName) {
+ ossClient.deleteObject(bucketName, fileName);
+ }
+
+ /**
+ * 获取文件类型
+ *
+ * @param fileExtension 文件后缀
+ * @return
+ */
+ public static String getFileType(String fileExtension) {
+ if (".bmp".equalsIgnoreCase(fileExtension)) {
+ return "image/bmp";
+ }
+ if (".gif".equalsIgnoreCase(fileExtension)) {
+ return "image/gif";
+ }
+ if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)
+ || ".png".equalsIgnoreCase(fileExtension)) {
+ return "image/jpg";
+ }
+ if (".html".equalsIgnoreCase(fileExtension)) {
+ return "text/html";
+ }
+ if (".txt".equalsIgnoreCase(fileExtension)) {
+ return "text/plain";
+ }
+ if (".vsd".equalsIgnoreCase(fileExtension)) {
+ return "application/vnd.visio";
+ }
+ if (".ppt".equalsIgnoreCase(fileExtension) || ".pptx".equalsIgnoreCase(fileExtension)) {
+ return "application/vnd.ms-powerpoint";
+ }
+ if (".doc".equalsIgnoreCase(fileExtension) || ".docx".equalsIgnoreCase(fileExtension)) {
+ return "application/msword";
+ }
+ if (".xml".equalsIgnoreCase(fileExtension)) {
+ return "text/xml";
+ }
+ if (".mp4".equalsIgnoreCase(fileExtension) || ".avi".equalsIgnoreCase(fileExtension)) {
+ return "video/mp4";
+ }
+ if (".mpg".equalsIgnoreCase(fileExtension) || ".mpeg".equalsIgnoreCase(fileExtension)) {
+ return "video/mpeg";
+ }
+ if ("pdf".equalsIgnoreCase(fileExtension)) {
+ return "application/pdf";
+ }
+ return "application/octet-stream";
+ }
+
+}
diff --git a/src/main/java/com/msdw/tms/common/utils/Constant.java b/src/main/java/com/msdw/tms/common/utils/Constant.java
new file mode 100644
index 0000000..80e4d2d
--- /dev/null
+++ b/src/main/java/com/msdw/tms/common/utils/Constant.java
@@ -0,0 +1,340 @@
+/**
+ * Copyright (c) 2016-2019 人人开源 All rights reserved.
+ *
+ * https://www.renren.io
+ *
+ * 版权所有,侵权必究!
+ */
+
+package com.msdw.tms.common.utils;
+
+/**
+ * 常量
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public class Constant {
+ /**
+ * 超级管理员ID
+ */
+ public static final int SUPER_ADMIN = 1;
+ /**
+ * 当前页码
+ */
+ public static final String PAGE = "page";
+ /**
+ * 每页显示记录数
+ */
+ public static final String LIMIT = "limit";
+ /**
+ * 排序字段
+ */
+ public static final String ORDER_FIELD = "sidx";
+ /**
+ * 排序方式
+ */
+ public static final String ORDER = "order";
+ /**
+ * 升序
+ */
+ public static final String ASC = "asc";
+ /**
+ * 通过excel批量导入试题数据时起始行
+ */
+ public static final int STARTING_ROW = 2;
+ /**
+ * 通过excel批量导入试题数据时起始列
+ */
+ public static final int STARTING_CELL = 0;
+ /**
+ * 试题选项A
+ */
+ public static final String A = "A";
+ /**
+ * 试题选项B
+ */
+ public static final String B = "B";
+ /**
+ * 试题选项C
+ */
+ public static final String C = "C";
+ /**
+ * 试题选项D
+ */
+ public static final String D = "D";
+ /**
+ * 试题选项E
+ */
+ public static final String E = "E";
+ /**
+ * 试题选项F
+ */
+ public static final String F = "F";
+ /**
+ * excel模板信息表id
+ */
+ public static final int XLSX_TEMPLATE_ID = 1;
+ /**
+ * 测评规则表id
+ */
+ public static final int EVALUATION_RULES_ID = 1;
+ /**
+ * 菜单类型
+ *
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年11月15日 下午1:24:29
+ */
+ public enum MenuType {
+ /**
+ * 目录
+ */
+ CATALOG(0),
+ /**
+ * 菜单
+ */
+ MENU(1),
+ /**
+ * 按钮
+ */
+ BUTTON(2);
+
+ private int value;
+
+ MenuType(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+ }
+
+ /**
+ * 定时任务状态
+ *
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年12月3日 上午12:07:22
+ */
+ public enum ScheduleStatus {
+ /**
+ * 正常
+ */
+ NORMAL(0),
+ /**
+ * 暂停
+ */
+ PAUSE(1);
+
+ private int value;
+
+ ScheduleStatus(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+ }
+
+ /**
+ * 云服务商
+ */
+ public enum CloudService {
+ /**
+ * 七牛云
+ */
+ QINIU(1),
+ /**
+ * 阿里云
+ */
+ ALIYUN(2),
+ /**
+ * 腾讯云
+ */
+ QCLOUD(3);
+
+ private int value;
+
+ CloudService(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+ }
+
+ /**
+ * 是否启用
+ */
+ public enum IsEnable {
+ /**
+ * 启用
+ */
+ ENABLE(1, "启用"),
+ /**
+ * 不启用
+ */
+ NOT_ENABLE(0, "不启用");
+
+ private Integer type; //类型
+ private String desc; //描述
+
+ IsEnable(Integer type, String desc) {
+ this.type = type;
+ this.desc = desc;
+ }
+
+ public Integer getType() {
+ return type;
+ }
+
+ public void setType(Integer type) {
+ this.type = type;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+ }
+
+
+ /**
+ * 是否删除
+ */
+ public enum IsDel {
+ /**
+ * 删除
+ */
+ DEL(0, "删除"),
+ /**
+ * 不删除
+ */
+ NOT_DEL(1, "不删除");
+
+ private Integer type; //类型
+ private String desc; //描述
+
+ IsDel(Integer type, String desc) {
+ this.type = type;
+ this.desc = desc;
+ }
+
+ public Integer getType() {
+ return type;
+ }
+
+ public void setType(Integer type) {
+ this.type = type;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+ }
+
+ /**
+ * 评测规则类型
+ */
+ public enum RulesType {
+ /**
+ * 随机
+ */
+ RANDOM(0, "随机"),
+ /**
+ * 自定义
+ */
+ CUSTOMIZE(1, "自定义");
+
+ private Integer type; //类型
+ private String desc; //描述
+
+ RulesType(Integer type, String desc) {
+ this.type = type;
+ this.desc = desc;
+ }
+
+ public Integer getType() {
+ return type;
+ }
+
+ public void setType(Integer type) {
+ this.type = type;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+ }
+
+ /**
+ * 试题类型
+ */
+ public enum QuestionType {
+ /**
+ * 单选题
+ */
+ SINGLE_CHOICE(1, "单选题"),
+ /**
+ * 多选题
+ */
+ MULTIPLE_CHOICE(2, "多选题"),
+ /**
+ * 判断题
+ */
+ TRUE_OR_FALSE(3, "判断题");
+
+ private Integer type; //类型
+ private String desc; //描述
+
+ QuestionType(Integer type, String desc) {
+ this.type = type;
+ this.desc = desc;
+ }
+
+ public Integer getType() {
+ return type;
+ }
+
+ public void setType(Integer type) {
+ this.type = type;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+ }
+
+
+// public static void main(String[] args) {
+// String answer = "A";
+//// System.out.println(answer.length());//3
+//// System.out.println(answer.charAt(2));//E
+//
+// String str = "";
+// for (int i = 0; i < answer.length(); i++) {
+// char c = answer.charAt(i);
+// str += c + ",";
+// }
+// str = str.substring(0, str.length() - 1);
+// System.out.println(str);
+// }
+}
\ No newline at end of file
diff --git a/src/main/java/com/msdw/tms/common/utils/FilesResult.java b/src/main/java/com/msdw/tms/common/utils/FilesResult.java
new file mode 100644
index 0000000..103ac4b
--- /dev/null
+++ b/src/main/java/com/msdw/tms/common/utils/FilesResult.java
@@ -0,0 +1,41 @@
+package com.msdw.tms.common.utils;
+
+public class FilesResult {
+
+ // 文件名
+ private String fileName;
+ // 文件在储存空间的路径
+ private String fileUrl;
+ // 上传状态
+ private String status;
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+
+ public String getFileUrl() {
+ return fileUrl;
+ }
+
+ public void setFileUrl(String fileUrl) {
+ this.fileUrl = fileUrl;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ @Override
+ public String toString() {
+ return "UploadFilesResult [fileName=" + fileName + ", fileUrl=" + fileUrl + ", status=" + status + "]";
+ }
+
+}
diff --git a/src/main/java/com/msdw/tms/common/utils/PageUtils.java b/src/main/java/com/msdw/tms/common/utils/PageUtils.java
new file mode 100644
index 0000000..190589c
--- /dev/null
+++ b/src/main/java/com/msdw/tms/common/utils/PageUtils.java
@@ -0,0 +1,110 @@
+/**
+ * Copyright (c) 2016-2019 人人开源 All rights reserved.
+ *
+ * https://www.renren.io
+ *
+ * 版权所有,侵权必究!
+ */
+
+package com.msdw.tms.common.utils;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 分页工具类
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public class PageUtils implements Serializable {
+ private static final long serialVersionUID = 1L;
+ /**
+ * 总记录数
+ */
+ private int totalCount;
+ /**
+ * 每页记录数
+ */
+ private int pageSize;
+ /**
+ * 总页数
+ */
+ private int totalPage;
+ /**
+ * 当前页数
+ */
+ private int currPage;
+ /**
+ * 列表数据
+ */
+ private List> list;
+
+ /**
+ * 分页
+ * @param list 列表数据
+ * @param totalCount 总记录数
+ * @param pageSize 每页记录数
+ * @param currPage 当前页数
+ */
+ public PageUtils(List> list, int totalCount, int pageSize, int currPage) {
+ this.list = list;
+ this.totalCount = totalCount;
+ this.pageSize = pageSize;
+ this.currPage = currPage;
+ this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
+ }
+
+ /**
+ * 分页
+ */
+ public PageUtils(IPage> page) {
+ this.list = page.getRecords();
+ this.totalCount = (int)page.getTotal();
+ this.pageSize = (int)page.getSize();
+ this.currPage = (int)page.getCurrent();
+ this.totalPage = (int)page.getPages();
+ }
+
+ public int getTotalCount() {
+ return totalCount;
+ }
+
+ public void setTotalCount(int totalCount) {
+ this.totalCount = totalCount;
+ }
+
+ public int getPageSize() {
+ return pageSize;
+ }
+
+ public void setPageSize(int pageSize) {
+ this.pageSize = pageSize;
+ }
+
+ public int getTotalPage() {
+ return totalPage;
+ }
+
+ public void setTotalPage(int totalPage) {
+ this.totalPage = totalPage;
+ }
+
+ public int getCurrPage() {
+ return currPage;
+ }
+
+ public void setCurrPage(int currPage) {
+ this.currPage = currPage;
+ }
+
+ public List> getList() {
+ return list;
+ }
+
+ public void setList(List> list) {
+ this.list = list;
+ }
+
+}
diff --git a/src/main/java/com/msdw/tms/common/utils/Query.java b/src/main/java/com/msdw/tms/common/utils/Query.java
new file mode 100644
index 0000000..f94a521
--- /dev/null
+++ b/src/main/java/com/msdw/tms/common/utils/Query.java
@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2016-2019 人人开源 All rights reserved.
+ *
+ * https://www.renren.io
+ *
+ * 版权所有,侵权必究!
+ */
+
+package com.msdw.tms.common.utils;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.msdw.tms.common.xss.SQLFilter;
+import org.apache.commons.lang.StringUtils;
+
+import java.util.Map;
+
+/**
+ * 查询参数
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public class Query {
+
+ public IPage getPage(Map params) {
+ return this.getPage(params, null, false);
+ }
+
+ public IPage getPage(Map params, String defaultOrderField, boolean isAsc) {
+ //分页参数
+ long curPage = 1;
+ long limit = 10;
+
+ if (params.get(Constant.PAGE) != null) {
+ curPage = Long.parseLong((String) params.get(Constant.PAGE));
+ }
+ if (params.get(Constant.LIMIT) != null) {
+ limit = Long.parseLong((String) params.get(Constant.LIMIT));
+ }
+
+ //分页对象
+ Page page = new Page<>(curPage, limit);
+
+ //分页参数
+ params.put(Constant.PAGE, page);
+
+ //排序字段
+ //防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险)
+ String orderField = SQLFilter.sqlInject((String) params.get(Constant.ORDER_FIELD));
+ String order = (String) params.get(Constant.ORDER);
+
+ //前端字段排序
+ if (StringUtils.isNotEmpty(orderField) && StringUtils.isNotEmpty(order)) {
+ if (Constant.ASC.equalsIgnoreCase(order)) {
+ return page.addOrder(OrderItem.asc(orderField));
+ } else {
+ return page.addOrder(OrderItem.desc(orderField));
+ }
+ }
+
+ //没有排序字段,则不排序
+ if (StringUtils.isBlank(defaultOrderField)) {
+ return page;
+ }
+
+ //默认排序
+ if (isAsc) {
+ page.addOrder(OrderItem.asc(defaultOrderField));
+ } else {
+ page.addOrder(OrderItem.desc(defaultOrderField));
+ }
+
+ return page;
+ }
+
+ public IPage getPage(Integer pageNo, Integer size) {
+ //分页参数
+ long curPage = 1;
+ long limit = 10;
+
+ if (pageNo != null) {
+ curPage = Long.parseLong(pageNo.toString());
+ }
+ if (size != null) {
+ limit = Long.parseLong(size.toString());
+ }
+
+ //分页对象
+ Page page = new Page<>(curPage, limit);
+
+ return page;
+ }
+}
diff --git a/src/main/java/com/msdw/tms/common/utils/R.java b/src/main/java/com/msdw/tms/common/utils/R.java
new file mode 100644
index 0000000..4fcc3a4
--- /dev/null
+++ b/src/main/java/com/msdw/tms/common/utils/R.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) 2016-2019 人人开源 All rights reserved.
+ *
+ * https://www.renren.io
+ *
+ * 版权所有,侵权必究!
+ */
+
+package com.msdw.tms.common.utils;
+
+import org.apache.http.HttpStatus;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 返回数据
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public class R extends HashMap {
+ private static final long serialVersionUID = 1L;
+
+ public R() {
+ put("code", 0);
+ put("msg", "success");
+ }
+
+ public static R error() {
+ return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
+ }
+
+ public static R error(String msg) {
+ return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
+ }
+
+ public static R error(int code, String msg) {
+ R r = new R();
+ r.put("code", code);
+ r.put("msg", msg);
+ return r;
+ }
+
+ public static R ok(String msg) {
+ R r = new R();
+ r.put("msg", msg);
+ return r;
+ }
+
+ public static R ok(Map map) {
+ R r = new R();
+ r.putAll(map);
+ return r;
+ }
+
+ public static R ok() {
+ return new R();
+ }
+
+ public R put(String key, Object value) {
+ super.put(key, value);
+ return this;
+ }
+}
diff --git a/src/main/java/com/msdw/tms/common/utils/poi/ExcelAttribute.java b/src/main/java/com/msdw/tms/common/utils/poi/ExcelAttribute.java
new file mode 100644
index 0000000..31b70b9
--- /dev/null
+++ b/src/main/java/com/msdw/tms/common/utils/poi/ExcelAttribute.java
@@ -0,0 +1,25 @@
+package com.msdw.tms.common.utils.poi;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface ExcelAttribute {
+ /**
+ * 对应的列名称
+ */
+ String name() default "";
+
+ /**
+ * excel列的索引
+ */
+ int sort();
+
+ /**
+ * 字段类型对应的格式
+ */
+ String format() default "";
+}
diff --git a/src/main/java/com/msdw/tms/common/utils/poi/ExcelExportUtil.java b/src/main/java/com/msdw/tms/common/utils/poi/ExcelExportUtil.java
new file mode 100644
index 0000000..6da79eb
--- /dev/null
+++ b/src/main/java/com/msdw/tms/common/utils/poi/ExcelExportUtil.java
@@ -0,0 +1,87 @@
+package com.msdw.tms.common.utils.poi;
+
+import lombok.Data;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.net.URLEncoder;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 导出Excel工具类
+ * 基于模板打印的方式导出:
+ */
+@Data
+public class ExcelExportUtil {
+
+ private int rowIndex; //写入数据的起始行
+ private int styleIndex; //需要提取的样式所在的行号
+ private Class clazz; //对象的字节码
+ private Field fields[]; //对象中的所有属性
+
+ public ExcelExportUtil(Class clazz, int rowIndex, int styleIndex) {
+ this.clazz = clazz;
+ this.rowIndex = rowIndex;
+ this.styleIndex = styleIndex;
+ fields = clazz.getDeclaredFields();
+ }
+
+ /**
+ * 基于注解导出
+ * 参数:
+ * response:
+ * InputStream:模板的输入流
+ * objs:数据
+ * fileName:生成的文件名
+ */
+ public void export(HttpServletResponse response, InputStream is, List objs, String fileName) throws Exception {
+
+ //1.根据模板创建工作簿
+ XSSFWorkbook workbook = new XSSFWorkbook(is);
+ //2.读取工作表
+ Sheet sheet = workbook.getSheetAt(0);
+ //3.提取公共的样式
+ CellStyle[] styles = getTemplateStyles(sheet.getRow(styleIndex));
+ //4.根据数据创建每一行和每一个单元格的数据2
+ AtomicInteger datasAi = new AtomicInteger(rowIndex); //数字
+ for (T t : objs) {
+ //datasAi.getAndIncrement() :获取数字,并++ i++
+ Row row = sheet.createRow(datasAi.getAndIncrement());
+ for (int i = 0; i < styles.length; i++) {
+ Cell cell = row.createCell(i);
+ cell.setCellStyle(styles[i]);
+ for (Field field : fields) {
+ if (field.isAnnotationPresent(ExcelAttribute.class)) {
+ field.setAccessible(true);
+ ExcelAttribute ea = field.getAnnotation(ExcelAttribute.class);
+ if (i == ea.sort()) {
+ if (field.get(t) != null) {
+ cell.setCellValue(field.get(t).toString());
+ }
+ }
+ }
+ }
+ }
+ }
+ fileName = URLEncoder.encode(fileName, "UTF-8");
+ response.setContentType("application/octet-stream");
+ response.setHeader("content-disposition", "attachment;filename=" + new String(fileName.getBytes("ISO8859-1")));
+ response.setHeader("filename", fileName);
+ workbook.write(response.getOutputStream());
+ }
+
+ public CellStyle[] getTemplateStyles(Row row) {
+ CellStyle[] styles = new CellStyle[row.getLastCellNum()];
+ for (int i = 0; i < row.getLastCellNum(); i++) {
+ styles[i] = row.getCell(i).getCellStyle();
+ }
+ return styles;
+ }
+}
diff --git a/src/main/java/com/msdw/tms/common/utils/poi/ExcelImportUtil.java b/src/main/java/com/msdw/tms/common/utils/poi/ExcelImportUtil.java
new file mode 100644
index 0000000..57c5627
--- /dev/null
+++ b/src/main/java/com/msdw/tms/common/utils/poi/ExcelImportUtil.java
@@ -0,0 +1,120 @@
+package com.msdw.tms.common.utils.poi;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+
+public class ExcelImportUtil {
+
+ private Class clazz;
+ private Field fields[];
+
+ public ExcelImportUtil(Class clazz) {
+ this.clazz = clazz;
+ fields = clazz.getDeclaredFields();
+ }
+
+ /**
+ * 基于注解读取excel
+ */
+ public List readExcel(InputStream is, int rowIndex, int cellIndex) {
+ List list = new ArrayList();
+ T entity = null;
+ try {
+ XSSFWorkbook workbook = new XSSFWorkbook(is);
+ Sheet sheet = workbook.getSheetAt(0);
+ // 不准确
+ // int rowLength = sheet.getLastRowNum();
+ // System.out.println(sheet.getLastRowNum());
+ for (int rowNum = rowIndex; rowNum <= sheet.getLastRowNum(); rowNum++) {
+ Row row = sheet.getRow(rowNum);
+ entity = (T) clazz.newInstance();
+ // System.out.println(row.getLastCellNum());
+ for (int j = cellIndex; j < row.getLastCellNum(); j++) {
+ Cell cell = row.getCell(j);
+ for (Field field : fields) {
+ if (field.isAnnotationPresent(ExcelAttribute.class)) {
+ field.setAccessible(true);
+ ExcelAttribute ea = field.getAnnotation(ExcelAttribute.class);
+ if (j == ea.sort()) {
+ field.set(entity, covertAttrType(field, cell));
+ }
+ }
+ }
+ }
+ list.add(entity);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return list;
+ }
+
+ /**
+ * 类型转换 将cell 单元格格式转为 字段类型
+ */
+ private Object covertAttrType(Field field, Cell cell) throws Exception {
+ String fieldType = field.getType().getSimpleName();
+ if ("String".equals(fieldType)) {
+ return getValue(cell);
+ } else if ("Date".equals(fieldType)) {
+ return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(getValue(cell));
+ } else if ("int".equals(fieldType) || "Integer".equals(fieldType)) {
+ return Integer.parseInt(getValue(cell));
+ } else if ("double".equals(fieldType) || "Double".equals(fieldType)) {
+ return Double.parseDouble(getValue(cell));
+ } else {
+ return null;
+ }
+ }
+
+
+ /**
+ * 格式转为String
+ *
+ * @param cell
+ * @return
+ */
+ public String getValue(Cell cell) {
+ if (cell == null) {
+ return "";
+ }
+ switch (cell.getCellType()) {
+ case STRING:
+ return cell.getRichStringCellValue().getString().trim();
+ case NUMERIC:
+ if (DateUtil.isCellDateFormatted(cell)) {
+ Date dt = DateUtil.getJavaDate(cell.getNumericCellValue());
+ return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(dt);
+ } else {
+ // 防止数值变成科学计数法
+ String strCell = "";
+ Double num = cell.getNumericCellValue();
+ BigDecimal bd = new BigDecimal(num.toString());
+ if (bd != null) {
+ strCell = bd.toPlainString();
+ }
+ // 去除 浮点型 自动加的 .0
+ if (strCell.endsWith(".0")) {
+ strCell = strCell.substring(0, strCell.indexOf("."));
+ }
+ return strCell;
+ }
+ case BOOLEAN:
+ return String.valueOf(cell.getBooleanCellValue());
+ default:
+ return "";
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/msdw/tms/common/xss/HTMLFilter.java b/src/main/java/com/msdw/tms/common/xss/HTMLFilter.java
new file mode 100644
index 0000000..6f1df38
--- /dev/null
+++ b/src/main/java/com/msdw/tms/common/xss/HTMLFilter.java
@@ -0,0 +1,530 @@
+package com.msdw.tms.common.xss;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *
+ * HTML filtering utility for protecting against XSS (Cross Site Scripting).
+ *
+ * This code is licensed LGPLv3
+ *
+ * This code is a Java port of the original work in PHP by Cal Hendersen.
+ * http://code.iamcal.com/php/lib_filter/
+ *
+ * The trickiest part of the translation was handling the differences in regex handling
+ * between PHP and Java. These resources were helpful in the process:
+ *
+ * http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html
+ * http://us2.php.net/manual/en/reference.pcre.pattern.modifiers.php
+ * http://www.regular-expressions.info/modifiers.html
+ *
+ * A note on naming conventions: instance variables are prefixed with a "v"; global
+ * constants are in all caps.
+ *
+ * Sample use:
+ * String input = ...
+ * String clean = new HTMLFilter().filter( input );
+ *
+ * The class is not thread safe. Create a new instance if in doubt.
+ *
+ * If you find bugs or have suggestions on improvement (especially regarding
+ * performance), please contact us. The latest version of this
+ * source, and our contact details, can be found at http://xss-html-filter.sf.net
+ *
+ * @author Joseph O'Connell
+ * @author Cal Hendersen
+ * @author Michael Semb Wever
+ */
+public final class HTMLFilter {
+
+ /** regex flag union representing /si modifiers in php **/
+ private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
+ private static final Pattern P_COMMENTS = Pattern.compile("", Pattern.DOTALL);
+ private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
+ private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
+ private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
+ private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
+ private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
+ private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
+ private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
+ private static final Pattern P_ENTITY = Pattern.compile("(\\d+);?");
+ private static final Pattern P_ENTITY_UNICODE = Pattern.compile("([0-9a-f]+);?");
+ private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
+ private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
+ private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
+ private static final Pattern P_END_ARROW = Pattern.compile("^>");
+ private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
+ private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
+ private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
+ private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
+ private static final Pattern P_AMP = Pattern.compile("&");
+ private static final Pattern P_QUOTE = Pattern.compile("<");
+ private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
+ private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
+ private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
+
+ // @xxx could grow large... maybe use sesat's ReferenceMap
+ private static final ConcurrentMap P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap();
+ private static final ConcurrentMap P_REMOVE_SELF_BLANKS = new ConcurrentHashMap();
+
+ /** set of allowed html elements, along with allowed attributes for each element **/
+ private final Map> vAllowed;
+ /** counts of open tags for each (allowable) html element **/
+ private final Map vTagCounts = new HashMap();
+
+ /** html elements which must always be self-closing (e.g. "") **/
+ private final String[] vSelfClosingTags;
+ /** html elements which must always have separate opening and closing tags (e.g. "") **/
+ private final String[] vNeedClosingTags;
+ /** set of disallowed html elements **/
+ private final String[] vDisallowed;
+ /** attributes which should be checked for valid protocols **/
+ private final String[] vProtocolAtts;
+ /** allowed protocols **/
+ private final String[] vAllowedProtocols;
+ /** tags which should be removed if they contain no content (e.g. "" or "") **/
+ private final String[] vRemoveBlanks;
+ /** entities allowed within html markup **/
+ private final String[] vAllowedEntities;
+ /** flag determining whether comments are allowed in input String. */
+ private final boolean stripComment;
+ private final boolean encodeQuotes;
+ private boolean vDebug = false;
+ /**
+ * flag determining whether to try to make tags when presented with "unbalanced"
+ * angle brackets (e.g. "" becomes " text "). If set to false,
+ * unbalanced angle brackets will be html escaped.
+ */
+ private final boolean alwaysMakeTags;
+
+ /** Default constructor.
+ *
+ */
+ public HTMLFilter() {
+ vAllowed = new HashMap<>();
+
+ final ArrayList a_atts = new ArrayList();
+ a_atts.add("href");
+ a_atts.add("target");
+ vAllowed.put("a", a_atts);
+
+ final ArrayList img_atts = new ArrayList();
+ img_atts.add("src");
+ img_atts.add("width");
+ img_atts.add("height");
+ img_atts.add("alt");
+ vAllowed.put("img", img_atts);
+
+ final ArrayList no_atts = new ArrayList();
+ vAllowed.put("b", no_atts);
+ vAllowed.put("strong", no_atts);
+ vAllowed.put("i", no_atts);
+ vAllowed.put("em", no_atts);
+
+ vSelfClosingTags = new String[]{"img"};
+ vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"};
+ vDisallowed = new String[]{};
+ vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp.
+ vProtocolAtts = new String[]{"src", "href"};
+ vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"};
+ vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"};
+ stripComment = true;
+ encodeQuotes = true;
+ alwaysMakeTags = true;
+ }
+
+ /** Set debug flag to true. Otherwise use default settings. See the default constructor.
+ *
+ * @param debug turn debug on with a true argument
+ */
+ public HTMLFilter(final boolean debug) {
+ this();
+ vDebug = debug;
+
+ }
+
+ /** Map-parameter configurable constructor.
+ *
+ * @param conf map containing configuration. keys match field names.
+ */
+ public HTMLFilter(final Map conf) {
+
+ assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
+ assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
+ assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
+ assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
+ assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
+ assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
+ assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
+ assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
+
+ vAllowed = Collections.unmodifiableMap((HashMap>) conf.get("vAllowed"));
+ vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
+ vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
+ vDisallowed = (String[]) conf.get("vDisallowed");
+ vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
+ vProtocolAtts = (String[]) conf.get("vProtocolAtts");
+ vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
+ vAllowedEntities = (String[]) conf.get("vAllowedEntities");
+ stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
+ encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
+ alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
+ }
+
+ private void reset() {
+ vTagCounts.clear();
+ }
+
+ private void debug(final String msg) {
+ if (vDebug) {
+ Logger.getAnonymousLogger().info(msg);
+ }
+ }
+
+ //---------------------------------------------------------------
+ // my versions of some PHP library functions
+ public static String chr(final int decimal) {
+ return String.valueOf((char) decimal);
+ }
+
+ public static String htmlSpecialChars(final String s) {
+ String result = s;
+ result = regexReplace(P_AMP, "&", result);
+ result = regexReplace(P_QUOTE, """, result);
+ result = regexReplace(P_LEFT_ARROW, "<", result);
+ result = regexReplace(P_RIGHT_ARROW, ">", result);
+ return result;
+ }
+
+ //---------------------------------------------------------------
+ /**
+ * given a user submitted input String, filter out any invalid or restricted
+ * html.
+ *
+ * @param input text (i.e. submitted by a user) than may contain html
+ * @return "clean" version of input, with only valid, whitelisted html elements allowed
+ */
+ public String filter(final String input) {
+ reset();
+ String s = input;
+
+ debug("************************************************");
+ debug(" INPUT: " + input);
+
+ s = escapeComments(s);
+ debug(" escapeComments: " + s);
+
+ s = balanceHTML(s);
+ debug(" balanceHTML: " + s);
+
+ s = checkTags(s);
+ debug(" checkTags: " + s);
+
+ s = processRemoveBlanks(s);
+ debug("processRemoveBlanks: " + s);
+
+ s = validateEntities(s);
+ debug(" validateEntites: " + s);
+
+ debug("************************************************\n\n");
+ return s;
+ }
+
+ public boolean isAlwaysMakeTags(){
+ return alwaysMakeTags;
+ }
+
+ public boolean isStripComments(){
+ return stripComment;
+ }
+
+ private String escapeComments(final String s) {
+ final Matcher m = P_COMMENTS.matcher(s);
+ final StringBuffer buf = new StringBuffer();
+ if (m.find()) {
+ final String match = m.group(1); //(.*?)
+ m.appendReplacement(buf, Matcher.quoteReplacement(""));
+ }
+ m.appendTail(buf);
+
+ return buf.toString();
+ }
+
+ private String balanceHTML(String s) {
+ if (alwaysMakeTags) {
+ //
+ // try and form html
+ //
+ s = regexReplace(P_END_ARROW, "", s);
+ s = regexReplace(P_BODY_TO_END, "<$1>", s);
+ s = regexReplace(P_XML_CONTENT, "$1<$2", s);
+
+ } else {
+ //
+ // escape stray brackets
+ //
+ s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s);
+ s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s);
+
+ //
+ // the last regexp causes '<>' entities to appear
+ // (we need to do a lookahead assertion so that the last bracket can
+ // be used in the next pass of the regexp)
+ //
+ s = regexReplace(P_BOTH_ARROWS, "", s);
+ }
+
+ return s;
+ }
+
+ private String checkTags(String s) {
+ Matcher m = P_TAGS.matcher(s);
+
+ final StringBuffer buf = new StringBuffer();
+ while (m.find()) {
+ String replaceStr = m.group(1);
+ replaceStr = processTag(replaceStr);
+ m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
+ }
+ m.appendTail(buf);
+
+ s = buf.toString();
+
+ // these get tallied in processTag
+ // (remember to reset before subsequent calls to filter method)
+ for (String key : vTagCounts.keySet()) {
+ for (int ii = 0; ii < vTagCounts.get(key); ii++) {
+ s += "" + key + ">";
+ }
+ }
+
+ return s;
+ }
+
+ private String processRemoveBlanks(final String s) {
+ String result = s;
+ for (String tag : vRemoveBlanks) {
+ if(!P_REMOVE_PAIR_BLANKS.containsKey(tag)){
+ P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?>" + tag + ">"));
+ }
+ result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
+ if(!P_REMOVE_SELF_BLANKS.containsKey(tag)){
+ P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
+ }
+ result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
+ }
+
+ return result;
+ }
+
+ private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) {
+ Matcher m = regex_pattern.matcher(s);
+ return m.replaceAll(replacement);
+ }
+
+ private String processTag(final String s) {
+ // ending tags
+ Matcher m = P_END_TAG.matcher(s);
+ if (m.find()) {
+ final String name = m.group(1).toLowerCase();
+ if (allowed(name)) {
+ if (!inArray(name, vSelfClosingTags)) {
+ if (vTagCounts.containsKey(name)) {
+ vTagCounts.put(name, vTagCounts.get(name) - 1);
+ return "" + name + ">";
+ }
+ }
+ }
+ }
+
+ // starting tags
+ m = P_START_TAG.matcher(s);
+ if (m.find()) {
+ final String name = m.group(1).toLowerCase();
+ final String body = m.group(2);
+ String ending = m.group(3);
+
+ //debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
+ if (allowed(name)) {
+ String params = "";
+
+ final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
+ final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
+ final List paramNames = new ArrayList();
+ final List paramValues = new ArrayList();
+ while (m2.find()) {
+ paramNames.add(m2.group(1)); //([a-z0-9]+)
+ paramValues.add(m2.group(3)); //(.*?)
+ }
+ while (m3.find()) {
+ paramNames.add(m3.group(1)); //([a-z0-9]+)
+ paramValues.add(m3.group(3)); //([^\"\\s']+)
+ }
+
+ String paramName, paramValue;
+ for (int ii = 0; ii < paramNames.size(); ii++) {
+ paramName = paramNames.get(ii).toLowerCase();
+ paramValue = paramValues.get(ii);
+
+// debug( "paramName='" + paramName + "'" );
+// debug( "paramValue='" + paramValue + "'" );
+// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
+
+ if (allowedAttribute(name, paramName)) {
+ if (inArray(paramName, vProtocolAtts)) {
+ paramValue = processParamProtocol(paramValue);
+ }
+ params += " " + paramName + "=\"" + paramValue + "\"";
+ }
+ }
+
+ if (inArray(name, vSelfClosingTags)) {
+ ending = " /";
+ }
+
+ if (inArray(name, vNeedClosingTags)) {
+ ending = "";
+ }
+
+ if (ending == null || ending.length() < 1) {
+ if (vTagCounts.containsKey(name)) {
+ vTagCounts.put(name, vTagCounts.get(name) + 1);
+ } else {
+ vTagCounts.put(name, 1);
+ }
+ } else {
+ ending = " /";
+ }
+ return "<" + name + params + ending + ">";
+ } else {
+ return "";
+ }
+ }
+
+ // comments
+ m = P_COMMENT.matcher(s);
+ if (!stripComment && m.find()) {
+ return "<" + m.group() + ">";
+ }
+
+ return "";
+ }
+
+ private String processParamProtocol(String s) {
+ s = decodeEntities(s);
+ final Matcher m = P_PROTOCOL.matcher(s);
+ if (m.find()) {
+ final String protocol = m.group(1);
+ if (!inArray(protocol, vAllowedProtocols)) {
+ // bad protocol, turn into local anchor link instead
+ s = "#" + s.substring(protocol.length() + 1, s.length());
+ if (s.startsWith("#//")) {
+ s = "#" + s.substring(3, s.length());
+ }
+ }
+ }
+
+ return s;
+ }
+
+ private String decodeEntities(String s) {
+ StringBuffer buf = new StringBuffer();
+
+ Matcher m = P_ENTITY.matcher(s);
+ while (m.find()) {
+ final String match = m.group(1);
+ final int decimal = Integer.decode(match).intValue();
+ m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
+ }
+ m.appendTail(buf);
+ s = buf.toString();
+
+ buf = new StringBuffer();
+ m = P_ENTITY_UNICODE.matcher(s);
+ while (m.find()) {
+ final String match = m.group(1);
+ final int decimal = Integer.valueOf(match, 16).intValue();
+ m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
+ }
+ m.appendTail(buf);
+ s = buf.toString();
+
+ buf = new StringBuffer();
+ m = P_ENCODE.matcher(s);
+ while (m.find()) {
+ final String match = m.group(1);
+ final int decimal = Integer.valueOf(match, 16).intValue();
+ m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
+ }
+ m.appendTail(buf);
+ s = buf.toString();
+
+ s = validateEntities(s);
+ return s;
+ }
+
+ private String validateEntities(final String s) {
+ StringBuffer buf = new StringBuffer();
+
+ // validate entities throughout the string
+ Matcher m = P_VALID_ENTITIES.matcher(s);
+ while (m.find()) {
+ final String one = m.group(1); //([^&;]*)
+ final String two = m.group(2); //(?=(;|&|$))
+ m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
+ }
+ m.appendTail(buf);
+
+ return encodeQuotes(buf.toString());
+ }
+
+ private String encodeQuotes(final String s){
+ if(encodeQuotes){
+ StringBuffer buf = new StringBuffer();
+ Matcher m = P_VALID_QUOTES.matcher(s);
+ while (m.find()) {
+ final String one = m.group(1); //(>|^)
+ final String two = m.group(2); //([^<]+?)
+ final String three = m.group(3); //(<|$)
+ m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, """, two) + three));
+ }
+ m.appendTail(buf);
+ return buf.toString();
+ }else{
+ return s;
+ }
+ }
+
+ private String checkEntity(final String preamble, final String term) {
+
+ return ";".equals(term) && isValidEntity(preamble)
+ ? '&' + preamble
+ : "&" + preamble;
+ }
+
+ private boolean isValidEntity(final String entity) {
+ return inArray(entity, vAllowedEntities);
+ }
+
+ private static boolean inArray(final String s, final String[] array) {
+ for (String item : array) {
+ if (item != null && item.equals(s)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean allowed(final String name) {
+ return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
+ }
+
+ private boolean allowedAttribute(final String name, final String paramName) {
+ return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/msdw/tms/common/xss/SQLFilter.java b/src/main/java/com/msdw/tms/common/xss/SQLFilter.java
new file mode 100644
index 0000000..3ea59ab
--- /dev/null
+++ b/src/main/java/com/msdw/tms/common/xss/SQLFilter.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2016-2019 人人开源 All rights reserved.
+ *
+ * https://www.renren.io
+ *
+ * 版权所有,侵权必究!
+ */
+
+package com.msdw.tms.common.xss;
+
+import com.msdw.tms.common.exception.RRException;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * SQL过滤
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public class SQLFilter {
+
+ /**
+ * SQL注入过滤
+ * @param str 待验证的字符串
+ */
+ public static String sqlInject(String str){
+ if(StringUtils.isBlank(str)){
+ return null;
+ }
+ //去掉'|"|;|\字符
+ str = StringUtils.replace(str, "'", "");
+ str = StringUtils.replace(str, "\"", "");
+ str = StringUtils.replace(str, ";", "");
+ str = StringUtils.replace(str, "\\", "");
+
+ //转换成小写
+ str = str.toLowerCase();
+
+ //非法字符
+ String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"};
+
+ //判断是否包含非法字符
+ for(String keyword : keywords){
+ if(str.indexOf(keyword) != -1){
+ throw new RRException("包含非法字符");
+ }
+ }
+
+ return str;
+ }
+}
diff --git a/src/main/java/com/msdw/tms/config/AliyunOssConfig.java b/src/main/java/com/msdw/tms/config/AliyunOssConfig.java
new file mode 100644
index 0000000..3bc4d74
--- /dev/null
+++ b/src/main/java/com/msdw/tms/config/AliyunOssConfig.java
@@ -0,0 +1,59 @@
+package com.msdw.tms.config;
+
+import com.aliyun.oss.OSSClient;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+@Component
+@PropertySource(value = "classpath:aliyun.properties")
+@Configuration
+public class AliyunOssConfig {
+
+ @Value("${oss.endpoint}")
+ private String endpoint;// oss外网访问域名
+ @Value("${oss.accessKeyId}")
+ private String accessKeyId;// oss中的密匙keyId
+ @Value("${oss.secretAccessKey}")
+ private String secretAccessKey;// oss中的密钥
+ @Value("${oss.bucketName}")
+ private String bucketName;// 仓库名称
+ @Value("${oss.sufferUrl}")
+ private String sufferUrl;
+ @Value("${user.userAvatars}")//用户头像
+ private String userAvatars;
+
+ @Bean
+ @Scope("prototype")
+ public OSSClient ossClient() {
+ return new OSSClient(endpoint, accessKeyId, secretAccessKey);
+ }
+
+ public String getEndpoint() {
+ return endpoint;
+ }
+
+ public String getAccessKeyId() {
+ return accessKeyId;
+ }
+
+ public String getSecretAccessKey() {
+ return secretAccessKey;
+ }
+
+ public String getBucketName() {
+ return bucketName;
+ }
+
+ public String getSufferUrl() {
+ return sufferUrl;
+ }
+
+ public String getUserAvatars() {
+ return userAvatars;
+ }
+
+}
diff --git a/src/main/java/com/msdw/tms/config/SwaggerConfig.java b/src/main/java/com/msdw/tms/config/SwaggerConfig.java
new file mode 100644
index 0000000..4a3fe69
--- /dev/null
+++ b/src/main/java/com/msdw/tms/config/SwaggerConfig.java
@@ -0,0 +1,35 @@
+package com.msdw.tms.config;
+
+import io.swagger.annotations.ApiOperation;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@Configuration
+@EnableSwagger2
+//@Profile({"dev","test"})
+//@ConditionalOnProperty(name = "swagger.enable", havingValue = "true")
+public class SwaggerConfig {
+
+ @Bean
+ public Docket productApi() {
+ return new Docket(DocumentationType.SWAGGER_2)
+ .apiInfo(apiInfo())
+ .select()//添加ApiOperiation注解的被扫描
+ .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+ .paths(PathSelectors.any())
+ .build();
+ }
+
+ private ApiInfo apiInfo() {
+ return new ApiInfoBuilder().title("网站管理").description("网站管理")
+ .version("1.0").build();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/msdw/tms/controller/EvaluationRulesController.java b/src/main/java/com/msdw/tms/controller/EvaluationRulesController.java
new file mode 100644
index 0000000..0efa731
--- /dev/null
+++ b/src/main/java/com/msdw/tms/controller/EvaluationRulesController.java
@@ -0,0 +1,49 @@
+package com.msdw.tms.controller;
+
+import com.msdw.tms.api.EvaluationRulesControllerApi;
+import com.msdw.tms.common.utils.R;
+import com.msdw.tms.entity.EvaluationRulesEntity;
+import com.msdw.tms.entity.vo.EvaluationRulesVO;
+import com.msdw.tms.service.EvaluationRulesService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+
+/**
+ * 测评规则信息记录,只记录一条信息
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-19 09:28:06
+ */
+@RestController
+@RequestMapping("tms/evaluationrules")
+public class EvaluationRulesController implements EvaluationRulesControllerApi {
+ @Autowired
+ private EvaluationRulesService evaluationRulesService;
+
+ /**
+ * 测评规则信息的展示
+ */
+ @Override
+ @GetMapping("/info")
+ //@RequiresPermissions("qms:evaluationrules:info")
+ public R info() {
+ EvaluationRulesVO evaluationRulesVO = evaluationRulesService.getEvaluationRules();
+
+ return R.ok().put("data", evaluationRulesVO);
+ }
+
+ /**
+ * 修改
+ */
+ @Override
+ @PutMapping("/update")
+ //@RequiresPermissions("qms:evaluationrules:update")
+ public R update(@RequestBody EvaluationRulesEntity evaluationRules) {
+ boolean b = evaluationRulesService.updateEvaluationRulesById(evaluationRules);
+
+ return b ? R.ok() : R.error();
+ }
+
+}
diff --git a/src/main/java/com/msdw/tms/controller/QuestionsController.java b/src/main/java/com/msdw/tms/controller/QuestionsController.java
new file mode 100644
index 0000000..bce1ca3
--- /dev/null
+++ b/src/main/java/com/msdw/tms/controller/QuestionsController.java
@@ -0,0 +1,160 @@
+package com.msdw.tms.controller;
+
+import com.msdw.tms.api.QuestionsControllerApi;
+import com.msdw.tms.common.utils.FilesResult;
+import com.msdw.tms.common.utils.PageUtils;
+import com.msdw.tms.common.utils.R;
+import com.msdw.tms.entity.request.QuestionsAddRequest;
+import com.msdw.tms.entity.request.QuestionsQueryRequest;
+import com.msdw.tms.entity.request.QuestionsUpdateRequest;
+import com.msdw.tms.entity.vo.EvaluationVO;
+import com.msdw.tms.entity.vo.QuestionsDetailVO;
+import com.msdw.tms.service.AliyunOssService;
+import com.msdw.tms.service.QuestionsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Arrays;
+
+
+/**
+ * 记录试题信息
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-19 09:28:06
+ */
+@RestController
+@RequestMapping("tms/questions")
+public class QuestionsController implements QuestionsControllerApi {
+ @Autowired
+ private QuestionsService questionsService;
+
+ @Autowired
+ private AliyunOssService ossService;
+
+ /**
+ * 列表
+ */
+ @Override
+ @GetMapping("/list")
+ //@RequiresPermissions("qms:questions:list")
+ public R list(@RequestParam Integer page,
+ @RequestParam Integer size,
+ QuestionsQueryRequest request) {
+
+ PageUtils questionsQueryPage = questionsService.queryQuestionsPage(page, size, request);
+
+ return R.ok().put("page", questionsQueryPage);
+ }
+
+ /**
+ * 信息
+ */
+ @Override
+ @GetMapping("/info/{id}")
+ //@RequiresPermissions("qms:questions:info")
+ public R info(@PathVariable("id") Integer id) {
+ QuestionsDetailVO questions = questionsService.getQuestionDetailById(id);
+
+ return R.ok().put("questions", questions);
+ }
+
+ /**
+ * 保存
+ */
+ @Override
+ @PostMapping("/save")
+ //@RequiresPermissions("qms:questions:save")
+ public R save(@RequestBody QuestionsAddRequest questions) {
+ boolean save = questionsService.saveQuestion(questions);
+
+ return save ? R.ok() : R.error();
+ }
+
+ /**
+ * 根据试题id修改试题信息
+ */
+ @Override
+ @PutMapping("/update")
+ //@RequiresPermissions("qms:questions:update")
+ public R update(@RequestBody QuestionsUpdateRequest questions) {
+ boolean update = questionsService.updateQuestionById(questions);
+
+ return update ? R.ok() : R.error();
+ }
+
+ /**
+ * 是否禁用试题
+ */
+ @Override
+ @PutMapping("/isnable")
+ //@RequiresPermissions("qms:questions:isnable")
+ public R isnable(Integer id) {
+ boolean b = questionsService.isnable(id);
+
+ return b ? R.ok() : R.error();
+ }
+
+ /**
+ * 删除
+ */
+ @Override
+ @DeleteMapping("/delete")
+ //@RequiresPermissions("qms:questions:delete")
+ public R delete(@RequestBody Integer[] ids) {
+ boolean delete = questionsService.deleteByIds(Arrays.asList(ids));
+
+ return delete ? R.ok() : R.error();
+ }
+
+ /**
+ * 通过excel批量导入
+ */
+ @Override
+ @PostMapping("/import")
+ //@RequiresPermissions("qms:questions:import")
+ public R importQuestion(@RequestParam(name = "file") MultipartFile file) throws IOException {
+ boolean b = questionsService.importQuestion(file);
+
+ return b ? R.ok() : R.error();
+ }
+
+ /**
+ * excel模板文件上传
+ *
+ * @param file
+ * @return
+ */
+ @Override
+ @PostMapping("/upload")
+ //@RequiresPermissions("qms:questions:upload")
+ public R uploadFiles(MultipartFile file) throws IOException {
+ FilesResult filesResult = questionsService.uploadFiles(file);
+ return R.ok().put("data", filesResult);
+ }
+
+ /**
+ * excel模板文件下载
+ *
+ * @return
+ */
+ @Override
+ @GetMapping("/download")
+ //@RequiresPermissions("qms:questions:download")
+ public R downloadFiles(HttpServletResponse response) throws IOException {
+ questionsService.downloadFiles(response);
+ return R.ok();
+ }
+
+ @Override
+ @GetMapping("/evaluation")
+ public R evaluation() {
+ EvaluationVO evaluation = questionsService.evaluation();
+ return R.ok().put("data", evaluation);
+ }
+
+}
diff --git a/src/main/java/com/msdw/tms/dao/EvaluationRulesDao.java b/src/main/java/com/msdw/tms/dao/EvaluationRulesDao.java
new file mode 100644
index 0000000..d1a5c22
--- /dev/null
+++ b/src/main/java/com/msdw/tms/dao/EvaluationRulesDao.java
@@ -0,0 +1,17 @@
+package com.msdw.tms.dao;
+
+import com.msdw.tms.entity.EvaluationRulesEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 测评规则信息记录,只记录一条信息
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-19 09:28:06
+ */
+@Mapper
+public interface EvaluationRulesDao extends BaseMapper {
+
+}
diff --git a/src/main/java/com/msdw/tms/dao/QuestionsDao.java b/src/main/java/com/msdw/tms/dao/QuestionsDao.java
new file mode 100644
index 0000000..6775d13
--- /dev/null
+++ b/src/main/java/com/msdw/tms/dao/QuestionsDao.java
@@ -0,0 +1,17 @@
+package com.msdw.tms.dao;
+
+import com.msdw.tms.entity.QuestionsEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 记录试题信息
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-19 09:28:06
+ */
+@Mapper
+public interface QuestionsDao extends BaseMapper {
+
+}
diff --git a/src/main/java/com/msdw/tms/dao/XlsxTemplateDao.java b/src/main/java/com/msdw/tms/dao/XlsxTemplateDao.java
new file mode 100644
index 0000000..169e869
--- /dev/null
+++ b/src/main/java/com/msdw/tms/dao/XlsxTemplateDao.java
@@ -0,0 +1,17 @@
+package com.msdw.tms.dao;
+
+import com.msdw.tms.entity.XlsxTemplateEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 模板文件信息记录
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-19 09:28:06
+ */
+@Mapper
+public interface XlsxTemplateDao extends BaseMapper {
+
+}
diff --git a/src/main/java/com/msdw/tms/entity/EvaluationRulesEntity.java b/src/main/java/com/msdw/tms/entity/EvaluationRulesEntity.java
new file mode 100644
index 0000000..88f776e
--- /dev/null
+++ b/src/main/java/com/msdw/tms/entity/EvaluationRulesEntity.java
@@ -0,0 +1,64 @@
+package com.msdw.tms.entity;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import java.io.Serializable;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * 测评规则信息记录,只记录一条信息
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-19 09:28:06
+ */
+@Data
+@TableName("tms_evaluation_rules")
+public class EvaluationRulesEntity implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键
+ */
+ @TableId
+ private Integer id;
+ /**
+ * 测评类型:1:随机类型,0:自定义类型
+ */
+ private Integer evaluationType;
+ /**
+ * 测评时长,单位:分钟
+ */
+ private Integer duration;
+ /**
+ * 测评总题数
+ */
+ private Integer questionNum;
+ /**
+ * 单选题数
+ */
+ private Integer singleNum;
+ /**
+ * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用
+ */
+ private Integer isSingleEnable;
+ /**
+ * 多选题数
+ */
+ private Integer multipleNum;
+ /**
+ * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用
+ */
+ private Integer isMultipleEnable;
+ /**
+ * 判断题数
+ */
+ private Integer judgmentNum;
+ /**
+ * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用
+ */
+ private Integer isJudgmentEnable;
+
+}
diff --git a/src/main/java/com/msdw/tms/entity/QuestionsEntity.java b/src/main/java/com/msdw/tms/entity/QuestionsEntity.java
new file mode 100644
index 0000000..f6ea702
--- /dev/null
+++ b/src/main/java/com/msdw/tms/entity/QuestionsEntity.java
@@ -0,0 +1,100 @@
+package com.msdw.tms.entity;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import java.io.Serializable;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * 记录试题信息
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-19 09:28:06
+ */
+@Data
+@TableName("tms_questions")
+public class QuestionsEntity implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 自增主键
+ */
+ @TableId
+ private Integer id;
+ /**
+ * 题型号:用于区分是什么题型
+ */
+ private Integer questionTypeNo;
+ /**
+ * 题型名称
+ */
+ private String questionType;
+ /**
+ * 题干信息
+ */
+ private String questionStem;
+ /**
+ * A选项内容
+ */
+ private String optionA;
+ /**
+ * B选项内容
+ */
+ private String optionB;
+ /**
+ * C选项内容
+ */
+ private String optionC;
+ /**
+ * D选项内容
+ */
+ private String optionD;
+ /**
+ * E选项内容
+ */
+ private String optionE;
+ /**
+ * F选项内容
+ */
+ private String optionF;
+ /**
+ * 正确答案
+ */
+ private String answer;
+ /**
+ * 答案解析
+ */
+ private String answerAnalysis;
+ /**
+ * 是否禁用:1:启用,0:禁用,默认是1启用
+ */
+ private Integer isEnable;
+ /**
+ * 是否删除:1使用,0删除,默认1使用
+ */
+ private Integer isDel;
+ /**
+ * 创建人
+ */
+ private String createUser;
+ /**
+ * 创建时间
+ */
+ private Date createTime;
+ /**
+ * 修改人
+ */
+ private String modifyUser;
+ /**
+ * 修改时间,用于排序,创建时,修改时间等于创建时间
+ */
+ private Date modifyTime;
+ /**
+ * 试题科目
+ */
+ private String subjects;
+
+}
diff --git a/src/main/java/com/msdw/tms/entity/XlsxTemplateEntity.java b/src/main/java/com/msdw/tms/entity/XlsxTemplateEntity.java
new file mode 100644
index 0000000..cb3757a
--- /dev/null
+++ b/src/main/java/com/msdw/tms/entity/XlsxTemplateEntity.java
@@ -0,0 +1,40 @@
+package com.msdw.tms.entity;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import java.io.Serializable;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * 模板文件信息记录
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-19 09:28:06
+ */
+@Data
+@TableName("tms_xlsx_template")
+public class XlsxTemplateEntity implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键
+ */
+ @TableId
+ private Integer id;
+ /**
+ * 文件名
+ */
+ private String fileName;
+ /**
+ * 文件全路径
+ */
+ private String fileUrl;
+ /**
+ * 状态
+ */
+ private Integer status;
+
+}
diff --git a/src/main/java/com/msdw/tms/entity/request/QuestionsAddRequest.java b/src/main/java/com/msdw/tms/entity/request/QuestionsAddRequest.java
new file mode 100644
index 0000000..3949b36
--- /dev/null
+++ b/src/main/java/com/msdw/tms/entity/request/QuestionsAddRequest.java
@@ -0,0 +1,61 @@
+package com.msdw.tms.entity.request;
+
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 试题的基本信息表
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-14 16:05:06
+ */
+@Data
+public class QuestionsAddRequest {
+ /**
+ * 题型名称
+ */
+ private String questionType;
+ /**
+ * 题干信息
+ */
+ private String questionStem;
+ /**
+ * A选项内容
+ */
+ private String optionA;
+ /**
+ * B选项内容
+ */
+ private String optionB;
+ /**
+ * C选项内容
+ */
+ private String optionC;
+ /**
+ * D选项内容
+ */
+ private String optionD;
+ /**
+ * E选项内容
+ */
+ private String optionE;
+ /**
+ * F选项内容
+ */
+ private String optionF;
+ /**
+ * 正确答案
+ */
+ private String answer;
+ /**
+ * 答案解析
+ */
+ private String answerAnalysis;
+ /**
+ * 试题科目
+ */
+ private String subjects;
+}
diff --git a/src/main/java/com/msdw/tms/entity/request/QuestionsImportRequest.java b/src/main/java/com/msdw/tms/entity/request/QuestionsImportRequest.java
new file mode 100644
index 0000000..6ae49e1
--- /dev/null
+++ b/src/main/java/com/msdw/tms/entity/request/QuestionsImportRequest.java
@@ -0,0 +1,70 @@
+package com.msdw.tms.entity.request;
+
+import com.msdw.tms.common.utils.poi.ExcelAttribute;
+import lombok.Data;
+
+/**
+ * 试题的基本信息表
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-14 16:05:06
+ */
+@Data
+public class QuestionsImportRequest {
+ /**
+ * 试题科目
+ */
+ @ExcelAttribute(sort = 0)
+ private String subjects;
+ /**
+ * 题干,问题描述
+ */
+ @ExcelAttribute(sort = 1)
+ private String questionStem;
+ /**
+ * 题型
+ */
+ @ExcelAttribute(sort = 2)
+ private String questionType;
+ /**
+ * 选项A
+ */
+ @ExcelAttribute(sort = 3)
+ private String optionA;
+ /**
+ * 选项B
+ */
+ @ExcelAttribute(sort = 4)
+ private String optionB;
+ /**
+ * 选项C
+ */
+ @ExcelAttribute(sort = 5)
+ private String optionC;
+ /**
+ * 选项D
+ */
+ @ExcelAttribute(sort = 6)
+ private String optionD;
+ /**
+ * 选项E
+ */
+ @ExcelAttribute(sort = 7)
+ private String optionE;
+ /**
+ * 选项F
+ */
+ @ExcelAttribute(sort = 8)
+ private String optionF;
+ /**
+ * 正确答案
+ */
+ @ExcelAttribute(sort = 9)
+ private String answer;
+ /**
+ * 答案解析
+ */
+ @ExcelAttribute(sort = 10)
+ private String answerAnalysis;
+}
diff --git a/src/main/java/com/msdw/tms/entity/request/QuestionsQueryRequest.java b/src/main/java/com/msdw/tms/entity/request/QuestionsQueryRequest.java
new file mode 100644
index 0000000..bc7c3f0
--- /dev/null
+++ b/src/main/java/com/msdw/tms/entity/request/QuestionsQueryRequest.java
@@ -0,0 +1,36 @@
+package com.msdw.tms.entity.request;
+
+import lombok.Data;
+
+/**
+ * 试题的基本信息表
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-14 16:05:06
+ */
+@Data
+public class QuestionsQueryRequest {
+
+ /**
+ * 题干,问题描述
+ */
+ private String questionStem;
+
+ // /**
+ // * 题型id
+ // */
+ // private Integer questionType;
+ // /**
+ // * 参考答案
+ // */
+ // private String answer;
+ // /**
+ // * 答案解析
+ // */
+ // private String answerAnalysis;
+ // /**
+ // * 创建时,修改时间即为创建时间,修改时间用于前端显示和排序
+ // */
+ // private Date modifyTime;
+}
diff --git a/src/main/java/com/msdw/tms/entity/request/QuestionsUpdateRequest.java b/src/main/java/com/msdw/tms/entity/request/QuestionsUpdateRequest.java
new file mode 100644
index 0000000..d86496c
--- /dev/null
+++ b/src/main/java/com/msdw/tms/entity/request/QuestionsUpdateRequest.java
@@ -0,0 +1,62 @@
+package com.msdw.tms.entity.request;
+
+import lombok.Data;
+
+/**
+ * 试题的基本信息表
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-14 16:05:06
+ */
+@Data
+public class QuestionsUpdateRequest {
+ /**
+ * 主键
+ */
+ private Integer id;
+ /**
+ * 题型名称
+ */
+ private String questionType;
+ /**
+ * 题干信息
+ */
+ private String questionStem;
+ /**
+ * A选项内容
+ */
+ private String optionA;
+ /**
+ * B选项内容
+ */
+ private String optionB;
+ /**
+ * C选项内容
+ */
+ private String optionC;
+ /**
+ * D选项内容
+ */
+ private String optionD;
+ /**
+ * E选项内容
+ */
+ private String optionE;
+ /**
+ * F选项内容
+ */
+ private String optionF;
+ /**
+ * 正确答案
+ */
+ private String answer;
+ /**
+ * 答案解析
+ */
+ private String answerAnalysis;
+ /**
+ * 试题科目
+ */
+ private String subjects;
+}
diff --git a/src/main/java/com/msdw/tms/entity/response/CommonCode.java b/src/main/java/com/msdw/tms/entity/response/CommonCode.java
new file mode 100644
index 0000000..5f33b78
--- /dev/null
+++ b/src/main/java/com/msdw/tms/entity/response/CommonCode.java
@@ -0,0 +1,54 @@
+package com.msdw.tms.entity.response;
+
+import lombok.ToString;
+
+/**
+ * @Author: mrt.
+ * @Description:
+ * @Date:Created in 2018/1/24 18:33.
+ * @Modified By:
+ */
+
+@ToString
+public enum CommonCode implements ResultCode {
+
+ SUCCESS(true, 10000, "操作成功!"),
+ UNAUTHENTICATED(false, 10001, "此操作需要登陆系统!"),
+ UNAUTHORISE(false, 10002, "权限不足,无权操作!"),
+ INVALID_PARAM(false, 10003, "非法参数!"),
+ QUESTION_NUM_INVALID(false, 10004, "测评题目数量设置超出范围!"),
+ QUESTION_EXISTS(false, 10005, "此题目已存在!"),
+ QUESTIONTYPE_INVALID(false, 10005, "题型错误!"),
+ FAIL(false, 11111, "操作失败!"),
+ SERVER_ERROR(false, 99999, "抱歉,系统繁忙,请稍后重试!");
+ // private static ImmutableMap codes ;
+ //操作是否成功
+ boolean success;
+ //操作代码
+ int code;
+ //提示信息
+ String message;
+
+ private CommonCode(boolean success, int code, String message) {
+ this.success = success;
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public boolean success() {
+ return success;
+ }
+
+ @Override
+ public int code() {
+ return code;
+ }
+
+ @Override
+ public String message() {
+ return message;
+ }
+
+
+}
diff --git a/src/main/java/com/msdw/tms/entity/response/Response.java b/src/main/java/com/msdw/tms/entity/response/Response.java
new file mode 100644
index 0000000..9c159ea
--- /dev/null
+++ b/src/main/java/com/msdw/tms/entity/response/Response.java
@@ -0,0 +1,9 @@
+package com.msdw.tms.entity.response;
+
+/**
+ * Created by admin on 2018/3/5.
+ */
+public interface Response {
+ public static final boolean SUCCESS = true;
+ public static final int SUCCESS_CODE = 10000;
+}
diff --git a/src/main/java/com/msdw/tms/entity/response/ResponseResult.java b/src/main/java/com/msdw/tms/entity/response/ResponseResult.java
new file mode 100644
index 0000000..0897404
--- /dev/null
+++ b/src/main/java/com/msdw/tms/entity/response/ResponseResult.java
@@ -0,0 +1,41 @@
+package com.msdw.tms.entity.response;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+/**
+ * @Author: mrt.
+ * @Description:
+ * @Date:Created in 2018/1/24 18:33.
+ * @Modified By:
+ */
+@Data
+@ToString
+@NoArgsConstructor
+public class ResponseResult implements Response {
+
+ //操作是否成功
+ boolean success = SUCCESS;
+
+ //操作代码
+ int code = SUCCESS_CODE;
+
+ //提示信息
+ String message;
+
+ public ResponseResult(ResultCode resultCode) {
+ this.success = resultCode.success();
+ this.code = resultCode.code();
+ this.message = resultCode.message();
+ }
+
+ public static ResponseResult SUCCESS() {
+ return new ResponseResult(CommonCode.SUCCESS);
+ }
+
+ public static ResponseResult FAIL() {
+ return new ResponseResult(CommonCode.FAIL);
+ }
+
+}
diff --git a/src/main/java/com/msdw/tms/entity/response/ResultCode.java b/src/main/java/com/msdw/tms/entity/response/ResultCode.java
new file mode 100644
index 0000000..0c380c8
--- /dev/null
+++ b/src/main/java/com/msdw/tms/entity/response/ResultCode.java
@@ -0,0 +1,21 @@
+package com.msdw.tms.entity.response;
+
+/**
+ * Created by mrt on 2018/3/5.
+ * 10000-- 通用错误代码
+ * 22000-- 媒资错误代码
+ * 23000-- 用户中心错误代码
+ * 24000-- cms错误代码
+ * 25000-- 文件系统
+ */
+public interface ResultCode {
+ //操作是否成功,true为成功,false操作失败
+ boolean success();
+
+ //操作代码
+ int code();
+
+ //提示信息
+ String message();
+
+}
diff --git a/src/main/java/com/msdw/tms/entity/vo/EvaluationRulesVO.java b/src/main/java/com/msdw/tms/entity/vo/EvaluationRulesVO.java
new file mode 100644
index 0000000..d8e375e
--- /dev/null
+++ b/src/main/java/com/msdw/tms/entity/vo/EvaluationRulesVO.java
@@ -0,0 +1,76 @@
+package com.msdw.tms.entity.vo;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 测评规则信息记录,只记录一条信息
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-19 09:28:06
+ */
+@Data
+public class EvaluationRulesVO implements Serializable {
+
+ /**
+ * 主键
+ */
+ private Integer id;
+ /**
+ * 测评类型:1:随机类型,0:自定义类型
+ */
+ private Integer evaluationType;
+ /**
+ * 测评时长,单位:分钟
+ */
+ private Integer duration;
+ /**
+ * 测评总题数
+ */
+ private Integer questionNum;
+ /**
+ * 题库总题数
+ */
+ private Integer totalQuestionNum;
+ /**
+ * 单选题数
+ */
+ private Integer singleNum;
+ /**
+ * 题库单选题总数
+ */
+ private Integer totalSingleNum;
+ /**
+ * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用
+ */
+ private Integer isSingleEnable;
+ /**
+ * 多选题数
+ */
+ private Integer multipleNum;
+ /**
+ * 题库多选题总数
+ */
+ private Integer totalMultipleNum;
+ /**
+ * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用
+ */
+ private Integer isMultipleEnable;
+ /**
+ * 判断题数
+ */
+ private Integer judgmentNum;
+ /**
+ * 题库判断题总数
+ */
+ private Integer totalJudgmentNum;
+ /**
+ * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用
+ */
+ private Integer isJudgmentEnable;
+
+}
diff --git a/src/main/java/com/msdw/tms/entity/vo/EvaluationVO.java b/src/main/java/com/msdw/tms/entity/vo/EvaluationVO.java
new file mode 100644
index 0000000..c40b6e5
--- /dev/null
+++ b/src/main/java/com/msdw/tms/entity/vo/EvaluationVO.java
@@ -0,0 +1,66 @@
+package com.msdw.tms.entity.vo;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.msdw.tms.entity.QuestionsEntity;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Set;
+
+/**
+ * 测评规则信息记录,只记录一条信息
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-19 09:28:06
+ */
+@Data
+@TableName("tms_evaluation_rules")
+public class EvaluationVO implements Serializable {
+
+ /**
+ * 主键
+ */
+ private Integer id;
+ /**
+ * 测评类型:1:随机类型,0:自定义类型
+ */
+ private Integer evaluationType;
+ /**
+ * 测评时长,单位:分钟
+ */
+ private Integer duration;
+ /**
+ * 测评总题数
+ */
+ private Integer questionNum;
+ /**
+ * 单选题数
+ */
+ private Integer singleNum;
+ /**
+ * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用
+ */
+ private Integer isSingleEnable;
+ /**
+ * 多选题数
+ */
+ private Integer multipleNum;
+ /**
+ * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用
+ */
+ private Integer isMultipleEnable;
+ /**
+ * 判断题数
+ */
+ private Integer judgmentNum;
+ /**
+ * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用
+ */
+ private Integer isJudgmentEnable;
+ /**
+ *试题列表
+ */
+ private Set Questions;
+}
diff --git a/src/main/java/com/msdw/tms/entity/vo/QuestionsDetailVO.java b/src/main/java/com/msdw/tms/entity/vo/QuestionsDetailVO.java
new file mode 100644
index 0000000..182d643
--- /dev/null
+++ b/src/main/java/com/msdw/tms/entity/vo/QuestionsDetailVO.java
@@ -0,0 +1,121 @@
+package com.msdw.tms.entity.vo;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 记录试题信息
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-19 09:28:06
+ */
+@Data
+public class QuestionsDetailVO implements Serializable {
+
+ /**
+ * 主键
+ */
+ private Integer id;
+ /**
+ * 题型号:用于区分是什么题型
+ */
+ private Integer questionTypeNo;
+ /**
+ * 题型名称
+ */
+ private String questionType;
+ /**
+ * 题干信息
+ */
+ private String questionStem;
+ /**
+ * A选项内容
+ */
+ private String optionA;
+ /**
+ * A选项是否为正确答案
+ */
+ private boolean AIsTrue = false;
+ /**
+ * B选项内容
+ */
+ private String optionB;
+ /**
+ * B选项是否为正确答案
+ */
+ private boolean BIsTrue = false;
+ /**
+ * C选项内容
+ */
+ private String optionC;
+ /**
+ * C选项是否为正确答案
+ */
+ private boolean CIsTrue = false;
+ /**
+ * D选项内容
+ */
+ private String optionD;
+ /**
+ * D选项是否为正确答案
+ */
+ private boolean DIsTrue = false;
+ /**
+ * E选项内容
+ */
+ private String optionE;
+ /**
+ * E选项是否为正确答案
+ */
+ private boolean EIsTrue = false;
+ /**
+ * F选项内容
+ */
+ private String optionF;
+ /**
+ * F选项是否为正确答案
+ */
+ private boolean FIsTrue = false;
+ /**
+ * 正确答案
+ */
+ private String answer;
+ /**
+ * 答案解析
+ */
+ private String answerAnalysis;
+ /**
+ * 是否禁用:1:启用,0:禁用,默认是1启用
+ */
+ private Integer isEnable;
+ /**
+ * 是否删除:1使用,0删除,默认1使用
+ */
+ private Integer isDel;
+ /**
+ * 创建人
+ */
+ private String createUser;
+ /**
+ * 创建时间
+ */
+ private Date createTime;
+ /**
+ * 修改人
+ */
+ private String modifyUser;
+ /**
+ * 修改时间,用于排序,创建时,修改时间等于创建时间
+ */
+ private Date modifyTime;
+ /**
+ * 试题科目
+ */
+ private String subjects;
+
+}
diff --git a/src/main/java/com/msdw/tms/service/AliyunOssService.java b/src/main/java/com/msdw/tms/service/AliyunOssService.java
new file mode 100644
index 0000000..5c12e80
--- /dev/null
+++ b/src/main/java/com/msdw/tms/service/AliyunOssService.java
@@ -0,0 +1,32 @@
+package com.msdw.tms.service;
+
+import com.msdw.tms.common.utils.FilesResult;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+public interface AliyunOssService {
+
+ /**
+ * 上传文件
+ *
+ * @param file 上传文件
+ */
+ FilesResult uploadFiles(MultipartFile file) throws IOException;
+
+ /**
+ * 下载文件
+ *
+ * @param response
+ * @param objectName 本地路径
+ */
+ void downloadFiles(HttpServletResponse response, String objectName) throws IOException;
+
+ /**
+ * 根据文件路径+文件名称,删除该文件
+ *
+ * @param filename
+ */
+ void deleteFile(String filename);
+}
diff --git a/src/main/java/com/msdw/tms/service/EvaluationRulesService.java b/src/main/java/com/msdw/tms/service/EvaluationRulesService.java
new file mode 100644
index 0000000..a9578a3
--- /dev/null
+++ b/src/main/java/com/msdw/tms/service/EvaluationRulesService.java
@@ -0,0 +1,19 @@
+package com.msdw.tms.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.msdw.tms.entity.EvaluationRulesEntity;
+import com.msdw.tms.entity.vo.EvaluationRulesVO;
+
+/**
+ * 测评规则信息记录,只记录一条信息
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-19 09:28:06
+ */
+public interface EvaluationRulesService extends IService {
+ EvaluationRulesVO getEvaluationRules();
+
+ boolean updateEvaluationRulesById(EvaluationRulesEntity evaluationRules);
+}
+
diff --git a/src/main/java/com/msdw/tms/service/QuestionsService.java b/src/main/java/com/msdw/tms/service/QuestionsService.java
new file mode 100644
index 0000000..f3d4544
--- /dev/null
+++ b/src/main/java/com/msdw/tms/service/QuestionsService.java
@@ -0,0 +1,48 @@
+package com.msdw.tms.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.msdw.tms.common.utils.FilesResult;
+import com.msdw.tms.common.utils.PageUtils;
+import com.msdw.tms.entity.QuestionsEntity;
+import com.msdw.tms.entity.request.QuestionsAddRequest;
+import com.msdw.tms.entity.request.QuestionsQueryRequest;
+import com.msdw.tms.entity.request.QuestionsUpdateRequest;
+import com.msdw.tms.entity.vo.EvaluationVO;
+import com.msdw.tms.entity.vo.QuestionsDetailVO;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 记录试题信息
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-19 09:28:06
+ */
+public interface QuestionsService extends IService {
+
+ PageUtils queryQuestionsPage(Integer page, Integer size, QuestionsQueryRequest request);
+
+ QuestionsDetailVO getQuestionDetailById(Integer id);
+
+ boolean saveQuestion(QuestionsAddRequest questions);
+
+ boolean updateQuestionById(QuestionsUpdateRequest questions);
+
+ boolean isnable(Integer id);
+
+ boolean deleteByIds(List asList);
+
+ boolean importQuestion(MultipartFile file) throws IOException;
+
+ FilesResult uploadFiles(MultipartFile file) throws IOException;
+
+ void downloadFiles(HttpServletResponse response) throws IOException;
+
+ EvaluationVO evaluation();
+}
+
diff --git a/src/main/java/com/msdw/tms/service/XlsxTemplateService.java b/src/main/java/com/msdw/tms/service/XlsxTemplateService.java
new file mode 100644
index 0000000..9f36b79
--- /dev/null
+++ b/src/main/java/com/msdw/tms/service/XlsxTemplateService.java
@@ -0,0 +1,15 @@
+package com.msdw.tms.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.msdw.tms.entity.XlsxTemplateEntity;
+
+/**
+ * 模板文件信息记录
+ *
+ * @author gongsj
+ * @email gongsj@gmail.com
+ * @date 2020-08-19 09:28:06
+ */
+public interface XlsxTemplateService extends IService {
+}
+
diff --git a/src/main/java/com/msdw/tms/service/impl/AliyunOssServiceImpl.java b/src/main/java/com/msdw/tms/service/impl/AliyunOssServiceImpl.java
new file mode 100644
index 0000000..e5acfc7
--- /dev/null
+++ b/src/main/java/com/msdw/tms/service/impl/AliyunOssServiceImpl.java
@@ -0,0 +1,58 @@
+package com.msdw.tms.service.impl;
+
+import com.aliyun.oss.OSSClient;
+import com.msdw.tms.common.utils.AliyunOssUtil;
+import com.msdw.tms.common.utils.FilesResult;
+import com.msdw.tms.config.AliyunOssConfig;
+import com.msdw.tms.service.AliyunOssService;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 阿里云OSSUtil
+ */
+@Service
+public class AliyunOssServiceImpl implements AliyunOssService {
+
+ @Autowired
+ private AliyunOssConfig config;
+
+ @Autowired
+ private BeanFactory beanFactory;
+
+ /**
+ * 上传文件
+ *
+ * @param file 上传文件
+ */
+ public FilesResult uploadFiles(MultipartFile file) throws IOException {
+ OSSClient client = beanFactory.getBean(OSSClient.class);
+ return AliyunOssUtil.uploadFiles(file, client, config);
+ }
+
+ /**
+ * 下载文件
+ *
+ * @param response
+ * @param objectName 本地路径
+ */
+ public void downloadFiles(HttpServletResponse response, String objectName) throws IOException {
+ OSSClient client = beanFactory.getBean(OSSClient.class);
+ AliyunOssUtil.downloadFiles(response, client, config, objectName);
+ }
+
+ /**
+ * 根据文件路径+文件名称,删除该文件
+ *
+ * @param filename
+ */
+ public void deleteFile(String filename) {
+ OSSClient client = beanFactory.getBean(OSSClient.class);
+ AliyunOssUtil.deleteFile(client, config.getBucketName(), filename);
+ }
+}
diff --git a/src/main/java/com/msdw/tms/service/impl/EvaluationRulesServiceImpl.java b/src/main/java/com/msdw/tms/service/impl/EvaluationRulesServiceImpl.java
new file mode 100644
index 0000000..66afb7d
--- /dev/null
+++ b/src/main/java/com/msdw/tms/service/impl/EvaluationRulesServiceImpl.java
@@ -0,0 +1,116 @@
+package com.msdw.tms.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.msdw.tms.common.exception.ExceptionCast;
+import com.msdw.tms.common.utils.Constant;
+import com.msdw.tms.dao.EvaluationRulesDao;
+import com.msdw.tms.entity.EvaluationRulesEntity;
+import com.msdw.tms.entity.QuestionsEntity;
+import com.msdw.tms.entity.response.CommonCode;
+import com.msdw.tms.entity.vo.EvaluationRulesVO;
+import com.msdw.tms.service.EvaluationRulesService;
+import com.msdw.tms.service.QuestionsService;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+
+@Service("evaluationRulesService")
+public class EvaluationRulesServiceImpl extends ServiceImpl implements EvaluationRulesService {
+
+ @Autowired
+ QuestionsService questionsService;
+
+ @Override
+ public EvaluationRulesVO getEvaluationRules() {
+ EvaluationRulesVO evaluationRulesVO = new EvaluationRulesVO();
+
+ EvaluationRulesEntity evaluationRules = this.getById(Constant.EVALUATION_RULES_ID);
+
+ if (evaluationRules.getEvaluationType() == Constant.RulesType.CUSTOMIZE.getType()) {//自定义
+
+ int totalNum = 0;
+ if (evaluationRules.getIsSingleEnable() == Constant.IsEnable.ENABLE.getType()) {//启用
+ totalNum += evaluationRules.getSingleNum();
+ }
+ if (evaluationRules.getIsMultipleEnable() == Constant.IsEnable.ENABLE.getType()) {//启用
+ totalNum += evaluationRules.getMultipleNum();
+ }
+ if (evaluationRules.getIsJudgmentEnable() == Constant.IsEnable.ENABLE.getType()) {//启用
+ totalNum += evaluationRules.getJudgmentNum();
+ }
+
+ //类型为自定义,测评试题数量是各个参与测评的试题类型数量之和
+ evaluationRules.setQuestionNum(totalNum);
+ }
+
+ BeanUtils.copyProperties(evaluationRules, evaluationRulesVO);
+
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.eq("is_del", Constant.IsDel.NOT_DEL.getType()) //未删除
+ .eq("is_enable", Constant.IsEnable.ENABLE.getType()); //启用
+
+ evaluationRulesVO.setTotalQuestionNum(questionsService.count(queryWrapper));//总题数
+
+ int totalSingleNum = questionsService.count(queryWrapper.eq("question_type_no",
+ Constant.QuestionType.SINGLE_CHOICE.getType()));//单选题总数
+ int totalMultipleNum = questionsService.count(queryWrapper.eq("question_type_no",
+ Constant.QuestionType.MULTIPLE_CHOICE.getType()));//多选题总数
+ int totalJudgmentNum = questionsService.count(queryWrapper.eq("question_type_no",
+ Constant.QuestionType.TRUE_OR_FALSE.getType()));//判断题总数
+
+ evaluationRulesVO.setTotalSingleNum(totalSingleNum);
+ evaluationRulesVO.setTotalMultipleNum(totalMultipleNum);
+ evaluationRulesVO.setTotalJudgmentNum(totalJudgmentNum);
+
+ return evaluationRulesVO;
+ }
+
+ @Override
+ public boolean updateEvaluationRulesById(EvaluationRulesEntity evaluationRules) {
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.eq("is_del", Constant.IsDel.NOT_DEL.getType()) //未删除
+ .eq("is_enable", Constant.IsEnable.ENABLE.getType()); //启用
+
+ //判断题目是否超出范围
+ //判断类型
+ Integer evaluationType = evaluationRules.getEvaluationType();
+ if (evaluationType == Constant.RulesType.RANDOM.getType()) {//随机
+ Integer questionNum = evaluationRules.getQuestionNum();
+
+ //查询总题数
+ int count = questionsService.count(queryWrapper);//总题数
+ numIncalid(questionNum, count);
+
+ } else if (evaluationType == Constant.RulesType.CUSTOMIZE.getType()) {//自定义
+ if (evaluationRules.getIsSingleEnable() == Constant.IsEnable.ENABLE.getType()) {//启用
+ int singleNum = evaluationRules.getSingleNum();
+ int totalSingleNum = questionsService.count(queryWrapper.eq("question_type_no",
+ Constant.QuestionType.SINGLE_CHOICE.getType()));//单选题总数
+ numIncalid(singleNum, totalSingleNum);
+ }
+ if (evaluationRules.getIsMultipleEnable() == Constant.IsEnable.ENABLE.getType()) {//启用
+ int multipleNum = evaluationRules.getMultipleNum();
+ int totalMultipleNum = questionsService.count(queryWrapper.eq("question_type_no",
+ Constant.QuestionType.MULTIPLE_CHOICE.getType()));//多选题总数
+ numIncalid(multipleNum, totalMultipleNum);
+ }
+ if (evaluationRules.getIsJudgmentEnable() == Constant.IsEnable.ENABLE.getType()) {//启用
+ int judgmentNum = evaluationRules.getJudgmentNum();
+ int totalJudgmentNum = questionsService.count(queryWrapper.eq("question_type_no",
+ Constant.QuestionType.TRUE_OR_FALSE.getType()));//判断题总数
+ numIncalid(judgmentNum, totalJudgmentNum);
+ }
+
+ }
+
+ return this.updateById(evaluationRules);
+ }
+
+ private void numIncalid(int num, int totalNum) {
+ if (num < 0 || num > totalNum) {
+ ExceptionCast.cast(CommonCode.QUESTION_NUM_INVALID);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/msdw/tms/service/impl/QuestionsServiceImpl.java b/src/main/java/com/msdw/tms/service/impl/QuestionsServiceImpl.java
new file mode 100644
index 0000000..fe5e00a
--- /dev/null
+++ b/src/main/java/com/msdw/tms/service/impl/QuestionsServiceImpl.java
@@ -0,0 +1,404 @@
+package com.msdw.tms.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.msdw.tms.common.exception.ExceptionCast;
+import com.msdw.tms.common.utils.Constant;
+import com.msdw.tms.common.utils.FilesResult;
+import com.msdw.tms.common.utils.PageUtils;
+import com.msdw.tms.common.utils.Query;
+import com.msdw.tms.common.utils.poi.ExcelImportUtil;
+import com.msdw.tms.dao.QuestionsDao;
+import com.msdw.tms.entity.QuestionsEntity;
+import com.msdw.tms.entity.XlsxTemplateEntity;
+import com.msdw.tms.entity.request.QuestionsAddRequest;
+import com.msdw.tms.entity.request.QuestionsImportRequest;
+import com.msdw.tms.entity.request.QuestionsQueryRequest;
+import com.msdw.tms.entity.request.QuestionsUpdateRequest;
+import com.msdw.tms.entity.response.CommonCode;
+import com.msdw.tms.entity.vo.EvaluationRulesVO;
+import com.msdw.tms.entity.vo.EvaluationVO;
+import com.msdw.tms.entity.vo.QuestionsDetailVO;
+import com.msdw.tms.service.AliyunOssService;
+import com.msdw.tms.service.EvaluationRulesService;
+import com.msdw.tms.service.QuestionsService;
+import com.msdw.tms.service.XlsxTemplateService;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+@Service("questionsService")
+public class QuestionsServiceImpl extends ServiceImpl implements QuestionsService {
+
+ @Autowired
+ private AliyunOssService ossService;
+
+ @Autowired
+ XlsxTemplateService xlsxTemplateService;
+
+ @Autowired
+ EvaluationRulesService evaluationRulesService;
+
+ /**
+ * 条件加分页查询,题干模糊查询,未删除,修改时间降序
+ *
+ * @param page
+ * @param size
+ * @param request
+ * @return
+ */
+ @Override
+ public PageUtils queryQuestionsPage(Integer page, Integer size, QuestionsQueryRequest request) {
+ //请求包装类
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+
+ //只查询未被删除的试题
+ queryWrapper.eq("is_del", Constant.IsDel.NOT_DEL.getType());
+
+ //判断请求体是否为空
+ if (request != null) {
+ // 题干:判断题干是否为空,不为空则加入搜索条件
+ if (request.getQuestionStem() != null) {
+ queryWrapper.like("question_stem", request.getQuestionStem());
+ }
+ // 题型:判断题型是否为空,不为空则加入搜索条件
+ // if (questionsRequest.getQuestionType() != null) {
+ // queryWrapper.eq("question_type", questionsRequest.getQuestionType());
+ // }
+ // 修改时间:判断修改时间是否为空,不为空则加入搜索条件
+ // if (questionsRequest.getModifyTime() != null) {
+ // queryWrapper.eq("modify_time", questionsRequest.getModifyTime());
+ // }
+ }
+
+ //修改时间降序
+ queryWrapper.orderByDesc("modify_time");
+
+ IPage questionsEntityIPage = this.page(
+ new Query().getPage(page, size),
+ queryWrapper
+ );
+
+ return new PageUtils(questionsEntityIPage);
+ }
+
+ @Override
+ public QuestionsDetailVO getQuestionDetailById(Integer id) {
+ {
+ QuestionsDetailVO questionsDetailVO = new QuestionsDetailVO();
+ //查询试题信息
+ QuestionsEntity questionsEntity = this.getById(id);
+ BeanUtils.copyProperties(questionsEntity, questionsDetailVO);
+ //处理每个选项是否为被设置为答案
+ String answer = questionsEntity.getAnswer();
+
+ if (answer.contains(Constant.A)) {
+ questionsDetailVO.setAIsTrue(true);
+ }
+ if (answer.contains(Constant.B)) {
+ questionsDetailVO.setBIsTrue(true);
+ }
+ if (answer.contains(Constant.C)) {
+ questionsDetailVO.setCIsTrue(true);
+ }
+ if (answer.contains(Constant.D)) {
+ questionsDetailVO.setDIsTrue(true);
+ }
+ if (answer.contains(Constant.E)) {
+ questionsDetailVO.setEIsTrue(true);
+ }
+ if (answer.contains(Constant.F)) {
+ questionsDetailVO.setFIsTrue(true);
+ }
+ return questionsDetailVO;
+ }
+ }
+
+ /**
+ * 保存试题,根据题型名称得到题型号,设置创建时间和修改时间
+ *
+ * @param questions
+ * @return
+ */
+ @Override
+ @Transactional
+ public boolean saveQuestion(QuestionsAddRequest questions) {
+ if (questions == null || StringUtils.isEmpty(questions.getQuestionStem())) {
+ ExceptionCast.cast(CommonCode.INVALID_PARAM);
+ }
+
+ // 判断是否题干重复。。。
+ isStemRepeat(questions.getQuestionStem());
+
+ QuestionsEntity questionsEntity = new QuestionsEntity();
+ BeanUtils.copyProperties(questions, questionsEntity);
+
+ String questionType = questions.getQuestionType();
+ //根据题型名称得到题型号
+ if (questionType.equals(Constant.QuestionType.SINGLE_CHOICE.getDesc())) {
+ //单选题
+ questionsEntity.setQuestionTypeNo(Constant.QuestionType.SINGLE_CHOICE.getType());
+ } else if (questionType.equals(Constant.QuestionType.MULTIPLE_CHOICE.getDesc())) {
+ //多选题
+ questionsEntity.setQuestionTypeNo(Constant.QuestionType.MULTIPLE_CHOICE.getType());
+ } else if (questionType.equals(Constant.QuestionType.TRUE_OR_FALSE.getDesc())) {
+ //判断题
+ questionsEntity.setQuestionTypeNo(Constant.QuestionType.TRUE_OR_FALSE.getType());
+ } else {// 判断题型是否不存在。。。
+ //说明题型不正确
+ ExceptionCast.cast(CommonCode.QUESTIONTYPE_INVALID);
+ }
+
+ questionsEntity.setCreateTime(new Date());
+ questionsEntity.setModifyTime(new Date());
+ //TODO 创建者和修改者。。。
+
+ return this.save(questionsEntity);
+ }
+
+ @Override
+ @Transactional
+ public boolean updateQuestionById(QuestionsUpdateRequest questions) {
+ if (questions == null || questions.getId() == null || StringUtils.isEmpty(questions.getQuestionStem())) {
+ ExceptionCast.cast(CommonCode.INVALID_PARAM);
+ }
+
+ // 判断是否题干重复
+ isStemRepeat(questions.getQuestionStem());
+
+ // 判断id是否存在
+ if (this.getById(questions.getId()) == null) {
+ ExceptionCast.cast(CommonCode.INVALID_PARAM);
+ }
+
+ QuestionsEntity questionsEntity = new QuestionsEntity();
+ BeanUtils.copyProperties(questions, questionsEntity);
+
+ String questionType = questions.getQuestionType();
+ //根据题型名称得到题型号
+ if (questionType.equals(Constant.QuestionType.SINGLE_CHOICE.getDesc())) {
+ //单选题
+ questionsEntity.setQuestionTypeNo(Constant.QuestionType.SINGLE_CHOICE.getType());
+ } else if (questionType.equals(Constant.QuestionType.MULTIPLE_CHOICE.getDesc())) {
+ //多选题
+ questionsEntity.setQuestionTypeNo(Constant.QuestionType.MULTIPLE_CHOICE.getType());
+ } else if (questionType.equals(Constant.QuestionType.TRUE_OR_FALSE.getDesc())) {
+ //判断题
+ questionsEntity.setQuestionTypeNo(Constant.QuestionType.TRUE_OR_FALSE.getType());
+ } else {
+ //说明题型不正确
+ ExceptionCast.cast(CommonCode.QUESTIONTYPE_INVALID);
+ }
+
+ questionsEntity.setModifyTime(new Date());
+ //TODO 设置修改者。。。
+
+ return this.updateById(questionsEntity);
+ }
+
+ private void isStemRepeat(String stem) {
+ int count = this.count(new QueryWrapper().eq("question_stem", stem));
+ if (count > 0) {//说明已存在
+ //抛出题目已存在异常
+ ExceptionCast.cast(CommonCode.QUESTION_EXISTS);
+ }
+ }
+
+ @Override
+ @Transactional
+ public boolean isnable(Integer id) {
+ QuestionsEntity questionsEntity = new QuestionsEntity();
+ questionsEntity.setId(id);
+ QuestionsEntity byId = this.getById(id);
+ if (byId.getIsEnable() == Constant.IsEnable.ENABLE.getType()) {
+ questionsEntity.setIsEnable(Constant.IsEnable.NOT_ENABLE.getType());
+ }
+
+ if (byId.getIsEnable() == Constant.IsEnable.NOT_ENABLE.getType()) {
+ questionsEntity.setIsEnable(Constant.IsEnable.ENABLE.getType());
+ }
+
+ return this.updateById(questionsEntity);
+ }
+
+ @Override
+ @Transactional
+ public boolean deleteByIds(List asList) {
+ List collect = asList.stream().map(item -> {
+ QuestionsEntity questionsEntity = new QuestionsEntity();
+ questionsEntity.setId(item);
+ questionsEntity.setIsDel(Constant.IsDel.DEL.getType());
+ return questionsEntity;
+ }).collect(Collectors.toList());
+
+ return updateBatchById(collect);
+ }
+
+ /**
+ * 校验题干重复和题型不对的,从列表中将该题剔除,名称相同的要去重
+ *
+ * @param file
+ * @return
+ * @throws IOException
+ */
+ @Override
+ @Transactional
+ public boolean importQuestion(MultipartFile file) throws IOException {
+ List list = new ExcelImportUtil(QuestionsImportRequest.class)
+ .readExcel(file.getInputStream(), Constant.STARTING_ROW, Constant.STARTING_CELL);
+
+ if (list == null || list.size() == 0) {
+ ExceptionCast.cast(CommonCode.INVALID_PARAM);
+ }
+ //List unique = persons.stream().collect(
+ // Collectors.collectingAndThen(
+ // Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Person::getName))), ArrayList::new)
+ //);
+
+ List collect = list.stream().map(item -> {
+
+ int count = this.count(new QueryWrapper().eq("question_stem", item.getQuestionStem()));
+ if (count > 0) {//说明已存在
+ return null;
+ }
+ QuestionsEntity questionsEntity = new QuestionsEntity();
+ BeanUtils.copyProperties(item, questionsEntity);
+ String questionType = item.getQuestionType();
+ //根据题型名称得到题型号
+ if (questionType.equals(Constant.QuestionType.SINGLE_CHOICE.getDesc())) {
+ //单选题
+ questionsEntity.setQuestionTypeNo(Constant.QuestionType.SINGLE_CHOICE.getType());
+ } else if (questionType.equals(Constant.QuestionType.MULTIPLE_CHOICE.getDesc())) {
+ //多选题
+ questionsEntity.setQuestionTypeNo(Constant.QuestionType.MULTIPLE_CHOICE.getType());
+ } else if (questionType.equals(Constant.QuestionType.TRUE_OR_FALSE.getDesc())) {
+ //判断题
+ questionsEntity.setQuestionTypeNo(Constant.QuestionType.TRUE_OR_FALSE.getType());
+ } else {
+ // 题型不正确
+ return null;
+ }
+ questionsEntity.setCreateTime(new Date());
+ questionsEntity.setModifyTime(new Date());
+ //TODO 创建者和修改者。。。
+ return questionsEntity;
+ }).filter(question -> question != null).collect(Collectors.collectingAndThen(
+ Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(QuestionsEntity::getQuestionStem))),
+ ArrayList::new
+ ));
+
+ return this.saveBatch(collect);
+ }
+
+ /**
+ * 上传模板文件,修改模板信息表数据
+ *
+ * @param file
+ * @return
+ */
+ @Override
+ @Transactional
+ public FilesResult uploadFiles(MultipartFile file) throws IOException {
+ FilesResult filesResult = ossService.uploadFiles(file);
+
+ XlsxTemplateEntity xlsxTemplateEntity = new XlsxTemplateEntity();
+ BeanUtils.copyProperties(filesResult, xlsxTemplateEntity);
+ xlsxTemplateEntity.setId(Constant.XLSX_TEMPLATE_ID);
+ xlsxTemplateService.updateById(xlsxTemplateEntity);
+
+ return filesResult;
+ }
+
+ @Override
+ public void downloadFiles(HttpServletResponse response) throws IOException {
+ XlsxTemplateEntity xlsxTemplate = xlsxTemplateService.getById(Constant.XLSX_TEMPLATE_ID);
+ ossService.downloadFiles(response, xlsxTemplate.getFileName());
+ }
+
+ @Override
+ public EvaluationVO evaluation() {
+
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.eq("is_del", Constant.IsDel.NOT_DEL.getType()) //未删除
+ .eq("is_enable", Constant.IsEnable.ENABLE.getType()); //启用
+
+ Set set = new HashSet<>();
+
+ // 查询测评规则类型
+ EvaluationRulesVO evaluationRules = evaluationRulesService.getEvaluationRules();
+
+ EvaluationVO evaluation = new EvaluationVO();
+
+ BeanUtils.copyProperties(evaluationRules, evaluation);
+
+ Integer evaluationType = evaluationRules.getEvaluationType();
+ if (evaluationType == Constant.RulesType.RANDOM.getType()) {//随机
+ // 类型为随机,直接用题目数量
+ Integer questionNum = evaluationRules.getQuestionNum();
+ // 查询题库所有未删除,未禁用的题目id
+ List questions = this.list(queryWrapper);
+
+ set = getRandomList(questionNum, questions);
+
+ } else if (evaluationType == Constant.RulesType.CUSTOMIZE.getType()) {//自定义
+
+ int singleNum = 0;
+ int multipleNum = 0;
+ int judgmentNum = 0;
+
+ //判断各条目的题型是否启用
+ if (evaluationRules.getIsSingleEnable() == Constant.IsEnable.ENABLE.getType()) {
+ singleNum = evaluationRules.getSingleNum();
+
+ List singleChoice = this.list(queryWrapper.eq("question_type_no",
+ Constant.QuestionType.SINGLE_CHOICE.getType()));
+ set.addAll(getRandomList(singleNum, singleChoice));
+ }
+ if (evaluationRules.getIsMultipleEnable() == Constant.IsEnable.ENABLE.getType()) {
+ multipleNum = evaluationRules.getMultipleNum();
+
+ List multipleChoice = this.list(queryWrapper.eq("question_type_no",
+ Constant.QuestionType.MULTIPLE_CHOICE.getType()));
+
+ set.addAll(getRandomList(multipleNum, multipleChoice));
+ }
+ if (evaluationRules.getIsJudgmentEnable() == Constant.IsEnable.ENABLE.getType()) {
+ judgmentNum = evaluationRules.getJudgmentNum();
+ List judgments = this.list(queryWrapper.eq("question_type_no",
+ Constant.QuestionType.TRUE_OR_FALSE.getType()));
+
+ set.addAll(getRandomList(judgmentNum, judgments));
+ }
+
+ evaluation.setQuestionNum(singleNum + multipleNum + judgmentNum);
+
+ }
+ evaluation.setQuestions(set);
+
+ return evaluation;
+ }
+
+ private Set getRandomList(int len, List list) {
+ Set set = new HashSet<>();
+ Random random = new Random();
+ int i = 0;
+ while (true) {
+ i = random.nextInt(list.size());
+ set.add(list.get(i));
+ if (set.size() >= len) {
+ break;
+ }
+ }
+ return set;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/msdw/tms/service/impl/XlsxTemplateServiceImpl.java b/src/main/java/com/msdw/tms/service/impl/XlsxTemplateServiceImpl.java
new file mode 100644
index 0000000..8d5738d
--- /dev/null
+++ b/src/main/java/com/msdw/tms/service/impl/XlsxTemplateServiceImpl.java
@@ -0,0 +1,12 @@
+package com.msdw.tms.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.msdw.tms.dao.XlsxTemplateDao;
+import com.msdw.tms.entity.XlsxTemplateEntity;
+import com.msdw.tms.service.XlsxTemplateService;
+import org.springframework.stereotype.Service;
+
+
+@Service("xlsxTemplateService")
+public class XlsxTemplateServiceImpl extends ServiceImpl implements XlsxTemplateService {
+}
\ No newline at end of file
diff --git a/src/main/resources/aliyun.properties b/src/main/resources/aliyun.properties
new file mode 100644
index 0000000..acb5672
--- /dev/null
+++ b/src/main/resources/aliyun.properties
@@ -0,0 +1,6 @@
+oss.endpoint=oss-cn-shenzhen.aliyuncs.com
+oss.accessKeyId=LTAIHIkGqaILObBm
+oss.secretAccessKey=QDTxKMrfDPeJ3bsr3AqjYHwnlL6PdM
+oss.bucketName=liuwanr
+oss.sufferUrl=http://liuwanr.oss-cn-shenzhen.aliyuncs.com/
+user.userAvatars=userAvatars
\ No newline at end of file
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000..8a03b75
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,15 @@
+spring:
+ datasource:
+ url: jdbc:mysql://www.liuwanr.cn:3306/msdw_tms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
+ username: super
+ password: huoran888
+ driver-class-name: com.mysql.jdbc.Driver
+mybatis-plus:
+ configuration:
+ log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
+ mapper-locations: classpath:/mapper/**/*.xml
+ global-config:
+ db-config:
+ id-type: auto
+server:
+ port: 7000
\ No newline at end of file
diff --git a/src/main/resources/excel-template/试题导入模板.xlsx b/src/main/resources/excel-template/试题导入模板.xlsx
new file mode 100644
index 0000000..4c064f0
Binary files /dev/null and b/src/main/resources/excel-template/试题导入模板.xlsx differ
diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000..d09983d
--- /dev/null
+++ b/src/main/resources/logback-spring.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+ utf8
+
+
+
+
+
+
+
+ ${LOG_HOME}/tms.%d{yyyy-MM-dd}.log
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+ 0
+
+ 512
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mapper/tms/EvaluationRulesDao.xml b/src/main/resources/mapper/tms/EvaluationRulesDao.xml
new file mode 100644
index 0000000..edf0605
--- /dev/null
+++ b/src/main/resources/mapper/tms/EvaluationRulesDao.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mapper/tms/QuestionsDao.xml b/src/main/resources/mapper/tms/QuestionsDao.xml
new file mode 100644
index 0000000..30a3679
--- /dev/null
+++ b/src/main/resources/mapper/tms/QuestionsDao.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mapper/tms/XlsxTemplateDao.xml b/src/main/resources/mapper/tms/XlsxTemplateDao.xml
new file mode 100644
index 0000000..9994315
--- /dev/null
+++ b/src/main/resources/mapper/tms/XlsxTemplateDao.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/java/com/msdw/tms/TmsApplicationTests.java b/src/test/java/com/msdw/tms/TmsApplicationTests.java
new file mode 100644
index 0000000..c8e9a17
--- /dev/null
+++ b/src/test/java/com/msdw/tms/TmsApplicationTests.java
@@ -0,0 +1,13 @@
+package com.msdw.tms;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class TmsApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}