新增,修改,批量导入试题,重复校验修改

hehai
shijie 4 years ago
parent c3988b9618
commit 0fd60e01f9
  1. 10
      pom.xml
  2. 2
      src/main/java/com/msdw/tms/api/QuestionsControllerApi.java
  3. 3
      src/main/java/com/msdw/tms/common/utils/poi/ExcelImportUtil.java
  4. 9
      src/main/java/com/msdw/tms/controller/QuestionsController.java
  5. 3
      src/main/java/com/msdw/tms/dao/QuestionsDao.java
  6. 9
      src/main/java/com/msdw/tms/entity/QuestionsEntity.java
  7. 13
      src/main/java/com/msdw/tms/entity/request/QuestionsAddRequest.java
  8. 6
      src/main/java/com/msdw/tms/entity/request/QuestionsImportRequest.java
  9. 6
      src/main/java/com/msdw/tms/entity/request/QuestionsQueryRequest.java
  10. 6
      src/main/java/com/msdw/tms/entity/request/QuestionsUpdateRequest.java
  11. 6
      src/main/java/com/msdw/tms/entity/response/CommonCode.java
  12. 4
      src/main/java/com/msdw/tms/entity/vo/EvaluationVO.java
  13. 35
      src/main/java/com/msdw/tms/entity/vo/QuestionsDetailVO.java
  14. 8
      src/main/java/com/msdw/tms/entity/vo/QuestionsListVO.java
  15. 43
      src/main/java/com/msdw/tms/entity/vo/QuestionsVO.java
  16. 4
      src/main/java/com/msdw/tms/service/QuestionsService.java
  17. 330
      src/main/java/com/msdw/tms/service/impl/QuestionsServiceImpl.java
  18. 5
      src/main/resources/application.yml
  19. 5
      src/main/resources/mapper/tms/QuestionsDao.xml
  20. 128
      src/test/java/com/msdw/tms/TmsApplicationTests.java
  21. 6
      src/test/java/com/msdw/tms/service/QuestionsServiceTest.java

@ -118,6 +118,16 @@
<version>1.4</version>
<scope>test</scope>
</dependency>
<!--JSR303校验-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- springboot整合redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
<build>

@ -81,7 +81,7 @@ public interface QuestionsControllerApi {
* 抽题测评
*/
@ApiOperation(value = "抽题测评", notes = "抽题测评")
R evaluation ();
R evaluation (Integer userId);
/**
* 通过excel批量导出

@ -53,6 +53,9 @@ public class ExcelImportUtil<T> {
}
}
}
Field field = entity.getClass().getDeclaredField("index");
field.setAccessible(true);
field.set(entity, rowNum);
list.add(entity);
}
} catch (Exception e) {

@ -115,9 +115,10 @@ public class QuestionsController implements QuestionsControllerApi {
@PostMapping("/import")
//@RequiresPermissions("qms:questions:import")
public R importQuestion(@RequestParam(name = "file") MultipartFile file) throws IOException {
boolean b = questionsService.importQuestion(file);
//TODO boolean b = questionsService.importQuestion(file);
return b ? R.ok() : R.error();
//return b ? R.ok() : R.error();
return null;
}
/**
@ -144,8 +145,8 @@ public class QuestionsController implements QuestionsControllerApi {
@Override
@GetMapping("/evaluation")
public R evaluation() {
EvaluationVO evaluation = questionsService.evaluation();
public R evaluation(Integer userId) {
EvaluationVO evaluation = questionsService.evaluation(userId);
return R.ok().put("data", evaluation);
}

@ -1,7 +1,7 @@
package com.msdw.tms.dao;
import com.msdw.tms.entity.QuestionsEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.msdw.tms.entity.QuestionsEntity;
import org.apache.ibatis.annotations.Mapper;
/**
@ -13,5 +13,4 @@ import org.apache.ibatis.annotations.Mapper;
*/
@Mapper
public interface QuestionsDao extends BaseMapper<QuestionsEntity> {
}

@ -23,13 +23,9 @@ public class QuestionsEntity implements Serializable {
@TableId
private Integer id;
/**
* 题型1单选题2多选题3判断题
* 题型1单选题2多选题3判断题
*/
private Integer questionTypeNo;
/**
* 题型名称
*/
private String questionType;
private Integer questionType;
/**
* 题干信息
*/
@ -94,5 +90,4 @@ public class QuestionsEntity implements Serializable {
* 试题科目
*/
private String subjects;
}

@ -4,6 +4,8 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* 试题的基本信息表
*
@ -13,10 +15,10 @@ import lombok.Data;
@ApiModel(value = "QuestionsAddRequest", description = "添加试题请求体对象")
public class QuestionsAddRequest {
/**
* 题型名称
* 题型1单选题2多选题3判断题
*/
@ApiModelProperty(value = "题型名称", name = "questionType", example = "单选题", required = true)
private String questionType;
@ApiModelProperty(value = "题型:1、单选题,2、多选题,3、判断题", name = "questionType", example = "1", required = true)
private Integer questionType;
/**
* 题干信息
*/
@ -62,9 +64,4 @@ public class QuestionsAddRequest {
*/
@ApiModelProperty(value = "答案解析", name = "answerAnalysis", example = "鲸鱼是最大的哺乳动物")
private String answerAnalysis;
/**
* 试题科目
*/
@ApiModelProperty(value = "试题科目", name = "subjects", example = "基础通识")
private String subjects;
}

@ -10,6 +10,10 @@ import lombok.Data;
*/
@Data
public class QuestionsImportRequest {
/**
* 第几行
*/
private Integer index;
/**
* 题干问题描述
@ -20,7 +24,7 @@ public class QuestionsImportRequest {
* 题型
*/
@ExcelAttribute(sort = 1)
private String questionType;
private String questionTypeName;
/**
* 选项A
*/

@ -20,10 +20,10 @@ public class QuestionsQueryRequest {
private String questionStem;
/**
* 题型id
* 题型
*/
@ApiModelProperty(value = "题型:1、单选题,2、多选题,3、判断题", name = "questionTypeNo", example = "1")
private Integer questionTypeNo;
@ApiModelProperty(value = "题型:1、单选题,2、多选题,3、判断题", name = "questionType", example = "1")
private Integer questionType;
// /**
// * 参考答案
// */

@ -18,10 +18,10 @@ public class QuestionsUpdateRequest {
@ApiModelProperty(value = "主键", name = "id", example = "1", required = true)
private Integer id;
/**
* 题型名称
* 题型1单选题2多选题3判断题
*/
@ApiModelProperty(value = "题型名称", name = "questionType", example = "单选题", required = true)
private String questionType;
@ApiModelProperty(value = "题型:1、单选题,2、多选题,3、判断题", name = "questionType", example = "1", required = true)
private Integer questionType;
/**
* 题干信息
*/

@ -10,8 +10,10 @@ public enum CommonCode implements ResultCode {
UNAUTHORISE(false, 10002, "权限不足,无权操作!"),
INVALID_PARAM(false, 10003, "非法参数!"),
QUESTION_NUM_INVALID(false, 10004, "测评题目数量设置超出范围!"),
QUESTION_EXISTS(false, 10005, "此题目已存在!"),
QUESTIONTYPE_INVALID(false, 10005, "题型错误!"),
QUESTION_EXISTS(false, 10005, "此题已存在!"),
QUESTIONTYPE_INVALID(false, 10006, "题型错误!"),
EXCEL_INVALID(false, 10007, "excel表内容错误!"),
EVALUATION_TIME_INVALID(false, 10008, "测评时间错误!"),
FAIL(false, 11111, "操作失败!"),
SERVER_ERROR(false, 99999, "抱歉,系统繁忙,请稍后重试!");
//操作是否成功

@ -27,6 +27,10 @@ public class EvaluationVO implements Serializable {
* 测评时长单位分钟
*/
private Integer duration;
/**
* 当前用户的剩余时长格式 HH:ss
*/
private String remainingDuration;
/**
* 测评总题数
*/

@ -17,13 +17,13 @@ public class QuestionsDetailVO implements Serializable {
*/
private Integer id;
/**
* 题型用于区分是什么题型1单选2多选3判断
* 题型用于区分是什么题型1单选2多选3判断
*/
private Integer questionTypeNo;
private Integer questionType;
/**
* 题型名称
*/
private String questionType;
private String questionTypeName;
/**
* 题干信息
*/
@ -84,33 +84,4 @@ public class QuestionsDetailVO implements Serializable {
* 答案解析
*/
private String answerAnalysis;
/**
* 是否禁用1启用0禁用默认是1启用
*/
private Integer isEnable;
/**
* 是否删除0使用1删除默认0使用
*/
private Integer isDel;
/**
* 创建人
*/
private String createUser;
/**
* 创建时间
*/
private String createTime;
/**
* 修改人
*/
private String modifyUser;
/**
* 修改时间用于排序创建时修改时间等于创建时间
*/
private String modifyTime;
/**
* 试题科目
*/
private String subjects;
}

@ -19,13 +19,9 @@ public class QuestionsListVO implements Serializable {
*/
private Integer id;
/**
* 题型用于区分是什么题型
* 题型1单选题2多选题3判断题
*/
private Integer questionTypeNo;
/**
* 题型名称
*/
private String questionType;
private String questionTypeName;
/**
* 题干信息
*/

@ -18,14 +18,10 @@ public class QuestionsVO implements Serializable {
* 主键
*/
private Integer id;
/**
* 题型号用于区分是什么题型
*/
private Integer questionTypeNo;
/**
* 题型名称
*/
private String questionType;
private String questionTypeName;
/**
* 题干信息
*/
@ -54,41 +50,4 @@ public class QuestionsVO implements Serializable {
* F选项内容
*/
private String optionF;
/**
* 正确答案
*/
private String answer;
/**
* 答案解析
*/
private String answerAnalysis;
/**
* 是否禁用1启用0禁用默认是1启用
*/
private Integer isEnable;
/**
* 是否删除0使用1删除默认0使用
*/
private Integer isDel;
/**
* 创建人
*/
private String createUser;
/**
* 创建时间
*/
private String createTime;
/**
* 修改人
*/
private String modifyUser;
/**
* 修改时间用于排序创建时修改时间等于创建时间
*/
private String modifyTime;
/**
* 试题科目
*/
private String subjects;
}

@ -38,13 +38,13 @@ public interface QuestionsService extends IService<QuestionsEntity> {
boolean deleteByIds(List<Integer> asList);
boolean importQuestion(MultipartFile file) throws IOException;
List<String> importQuestion(MultipartFile file) throws IOException;
FilesResult uploadFiles(MultipartFile file) throws IOException;
void downloadFiles(HttpServletResponse response) throws IOException;
EvaluationVO evaluation();
EvaluationVO evaluation(Integer userId);
void exportQuestion(HttpServletResponse response) throws Exception;
}

@ -26,6 +26,8 @@ import com.msdw.tms.service.XlsxTemplateService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
@ -39,6 +41,7 @@ import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Service("questionsService")
@ -53,6 +56,11 @@ public class QuestionsServiceImpl extends ServiceImpl<QuestionsDao, QuestionsEnt
@Resource
EvaluationRulesService evaluationRulesService;
@Resource
StringRedisTemplate stringRedisTemplate;
private String REMAINING_TINE_KEY = "REMAINING_TINE";
/**
* 条件加分页查询题干模糊查询未删除修改时间降序
*/
@ -71,14 +79,10 @@ public class QuestionsServiceImpl extends ServiceImpl<QuestionsDao, QuestionsEnt
queryWrapper.like("question_stem", request.getQuestionStem());
}
// 题型:判断题型是否为空,不为空则加入搜索条件
if (request.getQuestionTypeNo() != null) {
queryWrapper.eq("question_type_no", request.getQuestionTypeNo());
if (request.getQuestionType() != null) {
queryWrapper.eq("question_type", request.getQuestionType());
}
//TODO 扩展搜索条件
// 修改时间:判断修改时间是否为空,不为空则加入搜索条件
// if (request.getModifyTime() != null) {
// queryWrapper.eq("modify_time", request.getModifyTime());
// }
//扩展其他搜索条件...
}
// 修改时间降序
@ -88,23 +92,20 @@ public class QuestionsServiceImpl extends ServiceImpl<QuestionsDao, QuestionsEnt
new Query<QuestionsEntity>().getPage(page, size),
queryWrapper
);
List<QuestionsEntity> records = questionsIPage.getRecords();
List<QuestionsListVO> questions = records.stream().map(question -> {
QuestionsListVO questionsListVO = new QuestionsListVO();
BeanUtils.copyProperties(question, questionsListVO);
//处理试题类型
String questionTypeName = getQuestionTypeName(question.getQuestionType());
questionsListVO.setQuestionTypeName(questionTypeName);
//处理时间格式
questionsListVO.setModifyTime(handleTime(question.getModifyTime()));
return questionsListVO;
}).collect(Collectors.toList());
PageUtils questionsPage = new PageUtils(questionsIPage);
questionsPage.setList(questions);
return questionsPage;
}
@ -123,11 +124,9 @@ public class QuestionsServiceImpl extends ServiceImpl<QuestionsDao, QuestionsEnt
//查询试题信息
QuestionsEntity questionsEntity = this.getById(id);
BeanUtils.copyProperties(questionsEntity, questionsDetailVO);
//处理时间
//处理时间格式
questionsDetailVO.setCreateTime(handleTime(questionsEntity.getCreateTime()));
questionsDetailVO.setModifyTime(handleTime(questionsEntity.getModifyTime()));
//处理试题类型
String questionTypeName = getQuestionTypeName(questionsEntity.getQuestionType());
questionsDetailVO.setQuestionTypeName(questionTypeName);
//处理每个选项是否为被设置为答案
String answer = questionsEntity.getAnswer();
@ -154,29 +153,56 @@ public class QuestionsServiceImpl extends ServiceImpl<QuestionsDao, QuestionsEnt
}
}
private String getQuestionTypeName(Integer questionType) {
String questionTypeName = "";
//处理试题类型
if (questionType.equals(Constant.QuestionType.SINGLE_CHOICE.getType())) {
//单选题
questionTypeName = Constant.QuestionType.SINGLE_CHOICE.getDesc();
} else if (questionType.equals(Constant.QuestionType.MULTIPLE_CHOICE.getType())) {
//多选题
questionTypeName = Constant.QuestionType.MULTIPLE_CHOICE.getDesc();
} else if (questionType.equals(Constant.QuestionType.TRUE_OR_FALSE.getType())) {
//判断题
questionTypeName = Constant.QuestionType.TRUE_OR_FALSE.getDesc();
} else {
ExceptionCast.cast(CommonCode.QUESTIONTYPE_INVALID);
}
return questionTypeName;
}
/**
* 保存试题根据题型名称得到题型号设置创建时间和修改时间
* 保存试题
* 1检验题型是否正确
* 2检验题干和选项是否有重复
* 3设置创建时间和修改时间
*/
@Override
@Transactional
public boolean saveQuestion(QuestionsAddRequest questions) {
if (questions == null || StringUtils.isEmpty(questions.getQuestionStem())) {
//试题对象为空或题干内容为空,抛出参数不合法异常
if (questions == null
|| StringUtils.isEmpty(questions.getQuestionStem())
|| questions.getQuestionType() == null) {
ExceptionCast.cast(CommonCode.INVALID_PARAM);
}
// 判断是否题干重复,
QueryWrapper<QuestionsEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("is_del", Constant.IsDel.NOT_DEL.getType())
.eq("question_stem", questions.getQuestionStem());
//校验题型是否正确
checkType(questions.getQuestionType());
// 校验重复,不仅要校验题干,还要校验选项
QuestionsEntity questionsEntity = new QuestionsEntity();
BeanUtils.copyProperties(questions, questionsEntity);
//构造根据内容查询试题数量的Wrapper
QueryWrapper<QuestionsEntity> queryWrapper = constructDistinctWrapper(questionsEntity);
int count = this.count(queryWrapper);
if (count > 0) {//说明已存在
//抛出题目已存在异常
ExceptionCast.cast(CommonCode.QUESTION_EXISTS);
}
// 将传入的对象内容拷贝到QuestionsEntity并返回
QuestionsEntity questionsEntity = getQuestionsEntity(questions);
questionsEntity.setCreateTime(new Date());
questionsEntity.setModifyTime(new Date());
//TODO 创建者和修改者。。。
@ -187,28 +213,33 @@ public class QuestionsServiceImpl extends ServiceImpl<QuestionsDao, QuestionsEnt
@Override
@Transactional
public boolean updateQuestionById(QuestionsUpdateRequest questions) {
if (questions == null || questions.getId() == null || StringUtils.isEmpty(questions.getQuestionStem())) {
if (questions == null
|| questions.getId() == null
|| StringUtils.isEmpty(questions.getQuestionStem())) {
ExceptionCast.cast(CommonCode.INVALID_PARAM);
}
// 判断是否题干重复,除了自己之外还有没有重复的题干,因为自己的题干可以不做修改
QueryWrapper<QuestionsEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id", questions.getId())
.eq("question_stem", questions.getQuestionStem())
.eq("is_del", Constant.IsDel.NOT_DEL.getType());
int count = this.count(queryWrapper);
if (count > 0) {//说明除了本题之外题干已存在
//抛出题目已存在异常
ExceptionCast.cast(CommonCode.QUESTION_EXISTS);
}
// 判断id是否存在
if (this.getById(questions.getId()) == null) {
ExceptionCast.cast(CommonCode.INVALID_PARAM);
}
// 将传入的对象内容拷贝到QuestionsEntity并返回
QuestionsEntity questionsEntity = getQuestionsEntity(questions);
//校验题型是否正确
checkType(questions.getQuestionType());
//校验题干和内容重复
QuestionsEntity questionsEntity = new QuestionsEntity();
BeanUtils.copyProperties(questions, questionsEntity);
//构造根据内容查询试题数量的Wrapper
QueryWrapper<QuestionsEntity> queryWrapper = constructDistinctWrapper(questionsEntity);
queryWrapper.notIn("id", questions.getId());
int count = this.count(queryWrapper);
if (count > 0) {//说明除了本题之外题干已存在
//抛出题目已存在异常
ExceptionCast.cast(CommonCode.QUESTION_EXISTS);
}
questionsEntity.setModifyTime(new Date());
//TODO 设置修改者。。。
@ -216,28 +247,41 @@ public class QuestionsServiceImpl extends ServiceImpl<QuestionsDao, QuestionsEnt
return this.updateById(questionsEntity);
}
// 将传入的对象内容拷贝到QuestionsEntity并返回
private <T> QuestionsEntity getQuestionsEntity(T questions) {
QuestionsEntity questionsEntity = new QuestionsEntity();
BeanUtils.copyProperties(questions, questionsEntity);
String questionType = questionsEntity.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 {// 判断题型是否不存在
//说明题型不正确
private void checkType(int type) {
boolean include = false;
for (Constant.QuestionType value : Constant.QuestionType.values()) {
if (value.getType().equals(type)) {
include = true;
}
}
if (!include) {//题型不在枚举类中,不正确
ExceptionCast.cast(CommonCode.QUESTIONTYPE_INVALID);
}
return questionsEntity;
}
private QueryWrapper<QuestionsEntity> constructDistinctWrapper(QuestionsEntity questions) {
QueryWrapper<QuestionsEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("is_del", Constant.IsDel.NOT_DEL.getType())
.eq("question_stem", questions.getQuestionStem());
if (StringUtils.isNotEmpty(questions.getOptionA())) {
queryWrapper.eq("option_a", questions.getOptionA());
}
if (StringUtils.isNotEmpty(questions.getOptionB())) {
queryWrapper.eq("option_b", questions.getOptionB());
}
if (StringUtils.isNotEmpty(questions.getOptionC())) {
queryWrapper.eq("option_c", questions.getOptionC());
}
if (StringUtils.isNotEmpty(questions.getOptionD())) {
queryWrapper.eq("option_d", questions.getOptionD());
}
if (StringUtils.isNotEmpty(questions.getOptionE())) {
queryWrapper.eq("option_e", questions.getOptionE());
}
if (StringUtils.isNotEmpty(questions.getOptionF())) {
queryWrapper.eq("option_f", questions.getOptionF());
}
return queryWrapper;
}
@Override
@ -248,10 +292,10 @@ public class QuestionsServiceImpl extends ServiceImpl<QuestionsDao, QuestionsEnt
QuestionsEntity byId = this.getById(id);
if (byId.getIsEnable().equals(Constant.IsEnable.ENABLE.getType())) {
questionsEntity.setIsEnable(Constant.IsEnable.NOT_ENABLE.getType());
}
if (byId.getIsEnable().equals(Constant.IsEnable.NOT_ENABLE.getType())) {
} else if (byId.getIsEnable().equals(Constant.IsEnable.NOT_ENABLE.getType())) {
questionsEntity.setIsEnable(Constant.IsEnable.ENABLE.getType());
} else {
ExceptionCast.cast(CommonCode.INVALID_PARAM);
}
return this.updateById(questionsEntity);
@ -271,53 +315,62 @@ public class QuestionsServiceImpl extends ServiceImpl<QuestionsDao, QuestionsEnt
}
/**
* 校验题干重复和题型不对的从列表中将该题剔除名称相同的要去重
* 1校验题干重复和题型不对的
* 2从列表中将该题剔除并记录index和导入失败的原因
* 3名称和选项内容都相同的要去重
*/
@Override
@Transactional
public boolean importQuestion(MultipartFile file) throws IOException {
public List<String> importQuestion(MultipartFile file) throws IOException {
// 使用excel导入工具类获取试题数据列表
List<QuestionsImportRequest> 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);
ExceptionCast.cast(CommonCode.EXCEL_INVALID);
}
List<QuestionsEntity> collect = list.stream().map(item -> {
int count = this.count(new QueryWrapper<QuestionsEntity>().eq("question_stem", item.getQuestionStem()));
if (count > 0) {//说明已存在
return null;
}
List<String> failureRecord = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
QuestionsImportRequest question = list.get(i);
//校验题干和内容重复
QuestionsEntity questionsEntity = new QuestionsEntity();
BeanUtils.copyProperties(item, questionsEntity);
String questionType = item.getQuestionType();
BeanUtils.copyProperties(question, questionsEntity);
String questionTypeName = question.getQuestionTypeName();
//根据题型名称得到题型号
if (questionType.equals(Constant.QuestionType.SINGLE_CHOICE.getDesc())) {
if (questionTypeName.equals(Constant.QuestionType.SINGLE_CHOICE.getDesc())) {
//单选题
questionsEntity.setQuestionTypeNo(Constant.QuestionType.SINGLE_CHOICE.getType());
} else if (questionType.equals(Constant.QuestionType.MULTIPLE_CHOICE.getDesc())) {
questionsEntity.setQuestionType(Constant.QuestionType.SINGLE_CHOICE.getType());
} else if (questionTypeName.equals(Constant.QuestionType.MULTIPLE_CHOICE.getDesc())) {
//多选题
questionsEntity.setQuestionTypeNo(Constant.QuestionType.MULTIPLE_CHOICE.getType());
} else if (questionType.equals(Constant.QuestionType.TRUE_OR_FALSE.getDesc())) {
questionsEntity.setQuestionType(Constant.QuestionType.MULTIPLE_CHOICE.getType());
} else if (questionTypeName.equals(Constant.QuestionType.TRUE_OR_FALSE.getDesc())) {
//判断题
questionsEntity.setQuestionTypeNo(Constant.QuestionType.TRUE_OR_FALSE.getType());
questionsEntity.setQuestionType(Constant.QuestionType.TRUE_OR_FALSE.getType());
} else {
// 题型不正确
return null;
failureRecord.add("第 " + question.getIndex() + " 行导入失败," + "题干:" + question.getQuestionStem() + ",失败信息:" + CommonCode.QUESTIONTYPE_INVALID.message());
continue;
}
//构造根据内容查询试题数量的Wrapper
QueryWrapper<QuestionsEntity> queryWrapper = constructDistinctWrapper(questionsEntity);
int count = this.count(queryWrapper);
if (count > 0) {//说明已存在
failureRecord.add("第 " + question.getIndex() + " 行导入失败," + "题干:" + question.getQuestionStem() + ",失败信息:" + CommonCode.QUESTION_EXISTS.message());
continue;
}
questionsEntity.setCreateTime(new Date());
questionsEntity.setModifyTime(new Date());
//TODO 创建者和修改者。。。
return questionsEntity;
}).filter(Objects::nonNull)// 过滤掉为null的对象
.collect(Collectors.collectingAndThen(// 去重收集
Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(QuestionsEntity::getQuestionStem))),
ArrayList::new
));
// 批量新增
return this.saveBatch(collect);
this.save(questionsEntity);
}
return failureRecord;
}
/**
@ -343,14 +396,12 @@ public class QuestionsServiceImpl extends ServiceImpl<QuestionsDao, QuestionsEnt
}
@Override
public EvaluationVO evaluation() {
public EvaluationVO evaluation(Integer userId) {
QueryWrapper<QuestionsEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("is_del", Constant.IsDel.NOT_DEL.getType()) //未删除
.eq("is_enable", Constant.IsEnable.ENABLE.getType()); //启用
Set<QuestionsEntity> set = new HashSet<>();
// 查询测评规则类型
EvaluationRulesVO evaluationRules = evaluationRulesService.getEvaluationRules();
@ -358,17 +409,46 @@ public class QuestionsServiceImpl extends ServiceImpl<QuestionsDao, QuestionsEnt
BeanUtils.copyProperties(evaluationRules, evaluation);
//TODO 处理时长,获取当前登录用户id,将用户剩余的时长实时计算,存在Redis中
//时长转成秒来计算
//先查询该用户有没有开始考试,既redis中有没有跟该用户id相关联的key
//如果没有,表示是开始测评,向redis中插入一条数据,key是前缀加用户id,value是当前时间,过期时间是测评时长加三十秒
//如果有,则得到value,既开始测评的时间,用当前时间和开始测评时间做差,测评时长减去该差值
//TODO 提交测评时删除redis中的该条数据
//得到总时长
Integer duration = evaluation.getDuration();
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
String key = REMAINING_TINE_KEY + userId;
String startTime = ops.get(key);
int remainingTime = duration;
if (StringUtils.isEmpty(startTime)) {
//如果没有,表示是开始测评,向redis中插入一条数据,key是前缀加用户id,value是当前时间,过期时间是测评时长加十秒
ops.set(key, getSecondTimestamp(new Date()) + "", duration * 60 + 10, TimeUnit.SECONDS);
} else {
int difference = getSecondTimestamp(new Date()) - Integer.valueOf(startTime);
remainingTime = duration - difference;
if (remainingTime < 0) {
ExceptionCast.cast(CommonCode.EVALUATION_TIME_INVALID);
}
}
evaluation.setRemainingDuration(formatDateTime(remainingTime));
//搜集随机抽取的试题
Set<QuestionsVO> set = new HashSet<>();
//根据测评规则的类型不同
Integer evaluationType = evaluationRules.getEvaluationType();
if (evaluationType.equals(Constant.RulesType.RANDOM.getType())) {//随机
// 类型为随机,直接用题目数量
Integer questionNum = evaluationRules.getQuestionNum();
// 查询题库所有未删除,未禁用的题目id
List<QuestionsEntity> questions = this.list(queryWrapper);
set = getRandomList(questionNum, questions);
} else if (evaluationType.equals(Constant.RulesType.CUSTOMIZE.getType())) {//自定义
// 单选题数量
int singleNum = 0;
// 多选题数量
@ -401,22 +481,51 @@ public class QuestionsServiceImpl extends ServiceImpl<QuestionsDao, QuestionsEnt
// 总题数等于各类题目数量之和
evaluation.setQuestionNum(singleNum + multipleNum + judgmentNum);
}
Set<QuestionsVO> collect = set.stream().map(item -> {
QuestionsVO questionsVO = new QuestionsVO();
BeanUtils.copyProperties(item, questionsVO);
questionsVO.setCreateTime(handleTime(item.getCreateTime()));
questionsVO.setModifyTime(handleTime(item.getModifyTime()));
return questionsVO;
}).collect(Collectors.toSet());
evaluation.setQuestions(collect);
// Set<QuestionsVO> collect = set.stream().map(item -> {
// QuestionsVO questionsVO = new QuestionsVO();
// BeanUtils.copyProperties(item, questionsVO);
// return questionsVO;
// }).collect(Collectors.toSet());
evaluation.setQuestions(set);
return evaluation;
}
private int getSecondTimestamp(Date date) {
if (null == date) {
return 0;
}
String timestamp = String.valueOf(date.getTime() / 1000 / 60);
return Integer.valueOf(timestamp);
}
private String formatDateTime(long mss) {
String DateTimes;
long hours = (mss % (60 * 24)) / (60);
long minutes = (mss % (60));
//long seconds = mss % 60;
if (hours > 0) {
if (hours < 10) {
DateTimes = "0" + hours + ":" + minutes;
} else {
DateTimes = hours + ":" + minutes;
}
} else {
DateTimes = "00:" + minutes;
}
return DateTimes;
}
@Override
public void exportQuestion(HttpServletResponse response) throws Exception {
// 请求包装类
QueryWrapper<QuestionsEntity> queryWrapper = new QueryWrapper<>();
// 只查询未被删除且启用的试题
queryWrapper.eq("is_del", Constant.IsDel.NOT_DEL.getType())
.eq("is_enable", Constant.IsEnable.ENABLE.getType()); //启用
//1.构造数据
List<QuestionsImportRequest> list = this.list().stream().map(item -> {
List<QuestionsImportRequest> list = this.list(queryWrapper).stream().map(item -> {
QuestionsImportRequest importRequest = new QuestionsImportRequest();
BeanUtils.copyProperties(item, importRequest);
return importRequest;
@ -432,13 +541,16 @@ public class QuestionsServiceImpl extends ServiceImpl<QuestionsDao, QuestionsEnt
}
private Set<QuestionsEntity> getRandomList(int len, List<QuestionsEntity> list) {
Set<QuestionsEntity> set = new HashSet<>();
private Set<QuestionsVO> getRandomList(int len, List<QuestionsEntity> list) {
Set<QuestionsVO> set = new HashSet<>();
Random random = new Random();
int i;
while (true) {
i = random.nextInt(list.size());
set.add(list.get(i));
QuestionsVO questionsVO = new QuestionsVO();
BeanUtils.copyProperties(list.get(i), questionsVO);
questionsVO.setQuestionTypeName(getQuestionTypeName(list.get(i).getQuestionType()));
set.add(questionsVO);
if (set.size() >= len) {
break;
}

@ -4,6 +4,10 @@ spring:
username: super
password: huoran888
driver-class-name: com.mysql.jdbc.Driver
redis:
host: www.liuwanr.cn
port: 6379
password: huoran
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
@ -13,3 +17,4 @@ mybatis-plus:
id-type: auto
server:
port: 7000

@ -3,10 +3,9 @@
<mapper namespace="com.msdw.tms.dao.QuestionsDao">
<!-- 可根据自己的需求,是否要使用 -->
<!-- 可根据自己的需求,是否要使用 -->
<resultMap type="com.msdw.tms.entity.QuestionsEntity" id="questionsMap">
<result property="id" column="id"/>
<result property="questionTypeNo" column="question_type_no"/>
<result property="questionType" column="question_type"/>
<result property="questionStem" column="question_stem"/>
<result property="optionA" column="option_a"/>
@ -25,6 +24,4 @@
<result property="modifyTime" column="modify_time"/>
<result property="subjects" column="subjects"/>
</resultMap>
</mapper>

@ -1,10 +1,21 @@
package com.msdw.tms;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.concurrent.TimeUnit;
@SpringBootTest
class TmsApplicationTests {
@ -87,4 +98,121 @@ class TmsApplicationTests {
return k;
}
private String formatDateTime(long mss) {
String DateTimes = null;
long days = mss / (60 * 60 * 24);
long hours = (mss % (60 * 60 * 24)) / (60 * 60);
long minutes = (mss % (60 * 60)) / 60;
long seconds = mss % 60;
if (days > 0) {
DateTimes = days + "天" + hours + "小时" + minutes + "分钟"
+ seconds + "秒";
} else if (hours > 0) {
DateTimes = hours + "小时" + minutes + "分钟"
+ seconds + "秒";
} else if (minutes > 0) {
DateTimes = minutes + "分钟"
+ seconds + "秒";
} else {
DateTimes = seconds + "秒";
}
return DateTimes;
}
private String formatDateTime2(long mss) {
String DateTimes;
long hours = (mss % (60 * 24)) / (60);
long minutes = (mss % (60));
//long seconds = mss % 60;
if (hours > 0) {
if (hours < 10) {
DateTimes = "0" + hours + ":" + minutes;
} else {
DateTimes = hours + ":" + minutes;
}
} else {
DateTimes = "00:" + minutes;
}
return DateTimes;
}
@Test
void t2() {
long mss = 150;
String ss = formatDateTime2(mss);
System.out.println(ss);
}
/**
* 获取精确到秒的时间戳
*
* @param date
* @return
*/
private int getSecondTimestampTwo(Date date) {
if (null == date) {
return 0;
}
String timestamp = String.valueOf(date.getTime() / 1000 / 60);
return Integer.valueOf(timestamp);
}
@Test
void t3() {
String s = handleTime(new Date());
System.out.println("ssss" + s);
int secondTimestampTwo = getSecondTimestampTwo(new Date());
System.out.println(secondTimestampTwo);
long l = System.currentTimeMillis();
System.out.println("----" + new Date().getTime());
System.out.println("====" + System.currentTimeMillis());
// System.currentTimeMillis() / (long)1000 / (long)60;
}
@Test
void t4() throws ParseException {
Date date = getDate("2020-08-26 09:13:51");
int secondTimestampTwo = getSecondTimestampTwo(date);
int secondTimestampTwo1 = getSecondTimestampTwo(new Date());
int i = secondTimestampTwo1 - secondTimestampTwo;
System.out.println(i);
// System.currentTimeMillis() / (long)1000 / (long)60;
}
//处理时间格式
private String handleTime(Date date) {
Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault();
LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
return localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); // 当前日期和时间
}
private Date getDate(String dateStr) throws ParseException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//注意月份是MM
Date date = simpleDateFormat.parse(dateStr);
System.out.println(date); //Mon Sep 02 00:00:00 CST 2019
System.out.println(simpleDateFormat.format(date)); //2019-09-02
return date;
}
@Autowired
StringRedisTemplate stringRedisTemplate;
@Test
void t5() throws ParseException {
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
ops.set("aaa", "sss", 30, TimeUnit.SECONDS);
}
}

@ -93,9 +93,9 @@ class QuestionsServiceTest {
IOUtils.copy(new FileInputStream(file), fileItem.getOutputStream());
MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
boolean b = questionsService.importQuestion(multipartFile);
List<String> strings = questionsService.importQuestion(multipartFile);
System.out.println(b);
System.out.println(strings.toString());
}
@Test
@ -121,7 +121,7 @@ class QuestionsServiceTest {
@Test
void evaluation() {
EvaluationVO evaluation = questionsService.evaluation();
EvaluationVO evaluation = questionsService.evaluation(1);
System.out.println(evaluation.toString());
}
}

Loading…
Cancel
Save