欢送退出常识星球
互联网收废铁社区
帮忙你学习编程,带你少走弯路,少踩坑,一起学习、一起交换、一起做我的项目的常识交换圈
星球目前是 88 一年,前 100 名有 10 元优惠卷
明天次要给大家带来新的性能,题库性能
所谓题库性能,次要就是保留咱们的题目信息,咱们在考试的时候就会用到题库,须要从题库中抽取题库组成一套试卷;或者咱们进行刷题训练的时候也会冲题库中抽取题目信息等等中央都会用到
性能展现
从下面咱们能够看进去,咱们的性能已全副实现,题目类型次要分为单选题、多选题、填空题、解答题、判断题
次要性能点:
次要技术点:
- 应用工厂模式 + 策略模式实现不同类型题目的增加或批改
- 导入导出性能,导出到多个 sheet 或者多个 sheet 导入数据
针对以上的内容将一一进行解说
性能技术解说
分页查问题目
性能展现
查问条件:
- 学院
- 业余
- 课程
- 题目内容
- 题目类型
- 题目难度
const searchParam = reactive({
page: 1,
size: 10,
content: '',
type: '',
collegeUuid: '',
majorUuid: '',
courseUuid: '',
difficultyType: ''
})
次要的 sql 语句
<select id="pageListToManager"
parameterType="com.codedancer.campuslink.mapper.qo.QuestionPageSearchQo"
resultMap="questionResult">
select q.uuid AS q_uuid,
q.content AS q_content,
q.course_uuid AS q_course_uuid,
q.difficulty_type AS q_difficulty_type,
q.type AS q_type,
q.score AS q_score,
q.create_time AS q_create_time,
q.update_time AS q_update_time
from question AS q
left join course AS c on c.uuid = q.course_uuid
left join major AS m on m.uuid = c.major_uuid
left join college AS c2 on c2.uuid = m.college_uuid
<where>
<if test="questionPageSearchQo.content != null and questionPageSearchQo.content !=''">
and q.content like "%"#{questionPageSearchQo.content}"%"
</if>
<if test="questionPageSearchQo.type != null">
and q.type = #{questionPageSearchQo.type}
</if>
<if test="questionPageSearchQo.difficultyType != null">
and q.difficulty_type =#{questionPageSearchQo.difficultyType}
</if>
<if
test="questionPageSearchQo.collegeUuid != null and questionPageSearchQo.collegeUuid !=''">
and c2.uuid = #{questionPageSearchQo.collegeUuid}
</if>
<if test="questionPageSearchQo.majorUuid != null and questionPageSearchQo.majorUuid !=''">
and m.uuid = #{questionPageSearchQo.majorUuid}
</if>
<if test="questionPageSearchQo.courseUuid != null and questionPageSearchQo.courseUuid !=''">
and c.uuid = #{questionPageSearchQo.courseUuid}
</if>
and q.deleted = 0
</where>
order by q.create_time DESC
</select>
查问知识点很少,只须要根本的 sql 能力即可解决
增加题目
题目的增加咱们针对到具体的课程,每个学院以及每个业余下的课程题目都是不一样的
工厂模式 + 策略模式
创立 QuestionFactory 工厂
@Component
public class QuestionFactory implements InitializingBean, ApplicationContextAware {
private ApplicationContext applicationContext;
private static final Map<QuestionType, QuestionCreateHandler> QUESTION_HANDLER_MAP = new HashMap<>();
/**
* 依据题目类型获取对应的处理器
*
* @param type
* @return
*/
public QuestionCreateHandler getQuestionCreateHandler(Integer type) {if (Objects.equals(RADIO.getValue(), type)) {
// 单选题
return QUESTION_HANDLER_MAP.get(RADIO);
} else if (Objects.equals(MULTIPLE_CHOICE.getValue(), type)) {
// 多选题
return QUESTION_HANDLER_MAP.get(MULTIPLE_CHOICE);
} else if (Objects.equals(PACK.getValue(), type)) {
// 填空题
return QUESTION_HANDLER_MAP.get(PACK);
} else if (Objects.equals(SOLUTION.getValue(), type)) {
// 解答题
return QUESTION_HANDLER_MAP.get(SOLUTION);
} else if (Objects.equals(JUDGEMENT.getValue(), type)) {
// 判断题
return QUESTION_HANDLER_MAP.get(JUDGEMENT);
} else {throw new BusinessException("题目类型不正确!");
}
}
@Override
public void afterPropertiesSet() throws Exception {applicationContext.getBeansOfType(QuestionCreateHandler.class).values().forEach(bean -> {QUESTION_HANDLER_MAP.put(bean.getType(), bean);
});
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}
咱们从下面能够看出配置了五种题目类型,依据不同的类型获取到你不同的处理器
题目创立处理器
@Component
public interface QuestionCreateHandler {
/**
* 增加题目
*
* @param questionCreateParamModel
*/
void addQuestion(QuestionCreateParamModel questionCreateParamModel);
/**
* 题目类型
*
* @return
*/
QuestionType getType();
/**
* 批改题目
*
* @param questionCreateParamModel
*/
void updateQuestion(QuestionCreateParamModel questionCreateParamModel);
/**
* 导入题目
*
* @param questionCreateParamModels
*/
void importQuestion(List<QuestionCreateParamModel> questionCreateParamModels);
}
定义了四个接口:
- 增加题目
- 题目类型
- 批改题目
- 导入题目
处理器具体实现
- 单选题解决实现 QuestionRadionHandlerImpl
- 多选题解决实现 QuestionMultipleChoiceHandlerImpl
- 填空题解决实现 QuestionPackHandlerImpl
- 解答题解决实现 QuestionSolutionHandlerImpl
- 判断题解决实现 QuestionJudgementHandlerImpl
单选题
性能展现
在这里咱们也设计成了单选题该有的内容:
- 题目类型
- 题目内容(题目题目)
- 题目分数
- 四个选项内容
- 正确选项
- 单选解析内容
参数
const addOrUpdateParam = reactive({
collegeUuid: '',
majorUuid: '',
difficultyType: '',
content: '',
type: '',
analysisContent: '',
isRight: '',
rightAnswer: '',
rightOptions: [],
options: [],
optionA: '',
optionB: '',
optionC: '',
optionD: '',
radioRightOption: '',
score: ''
});
咱们把五种类型的题目参数全副放在这个对象外面不便咱们进行治理
次要逻辑
Question question = new Question();
question.setContent(questionCreateParamModel.getContent());
question.setScore(questionCreateParamModel.getScore());
question.setAnalysisContent(questionCreateParamModel.getAnalysisContent());
List<Map<String, String>> optionsMap = Lists.newArrayList();
IntStream.range(0, questionCreateParamModel.getOptions().size()).forEach(index -> {Map<String, String> map = new HashMap<>();
map.put(optionsArray[index], questionCreateParamModel.getOptions().get(index));
optionsMap.add(map);
});
question.setOptions(optionsMap);
question.setRightOptions(questionCreateParamModel.getRightOptions());
question.setCourseUuid(questionCreateParamModel.getCourseUuid());
QuestionType type = QuestionType.fromValue(questionCreateParamModel.getType());
if (ObjectUtil.isEmpty(type)) {throw new BusinessException("题目类型不正确,请查看");
}
question.setType(type);
QuestionDifficultyType difficultyType = QuestionDifficultyType.fromValue(questionCreateParamModel.getDifficultyType());
if (ObjectUtil.isEmpty(difficultyType)) {throw new BusinessException("题目难度参数不正确,请查看");
}
question.setDifficultyType(difficultyType);
questionMapper.insert(question);
多选题
性能展现
这里咱们设计的多选题也是默认四个选项,没有新增选项,能够在正确选项中抉择多个选项来作为正确答案
参数
和单选题统一
次要逻辑
Question question = new Question();
question.setContent(questionCreateParamModel.getContent());
question.setScore(questionCreateParamModel.getScore());
question.setAnalysisContent(questionCreateParamModel.getAnalysisContent());
List<Map<String, String>> optionsMap = Lists.newArrayList();
IntStream.range(0, questionCreateParamModel.getOptions().size()).forEach(index -> {Map<String, String> map = new HashMap<>();
map.put(optionsArray[index], questionCreateParamModel.getOptions().get(index));
optionsMap.add(map);
});
question.setOptions(optionsMap);
question.setRightOptions(questionCreateParamModel.getRightOptions());
question.setCourseUuid(questionCreateParamModel.getCourseUuid());
QuestionType type = QuestionType.fromValue(questionCreateParamModel.getType());
if (ObjectUtil.isEmpty(type)) {throw new BusinessException("题目类型不正确,请查看");
}
question.setType(type);
QuestionDifficultyType difficultyType = QuestionDifficultyType.fromValue(questionCreateParamModel.getDifficultyType());
if (ObjectUtil.isEmpty(difficultyType)) {throw new BusinessException("题目难度参数不正确,请查看");
}
question.setDifficultyType(difficultyType);
questionMapper.insert(question);
填空题
性能展现
这里就和单选题或多选题不统一的中央,该有的内容:
- 题目类型
- 题目难度
- 题目内容
- 题目分数
- 正确答案
- 解析内容
参数
和单选题统一
次要逻辑
Question question = new Question();
question.setContent(questionCreateParamModel.getContent());
question.setScore(questionCreateParamModel.getScore());
question.setAnalysisContent(questionCreateParamModel.getAnalysisContent());
question.setRightAnswer(questionCreateParamModel.getRightAnswer());
question.setCourseUuid(questionCreateParamModel.getCourseUuid());
QuestionType type = QuestionType.fromValue(questionCreateParamModel.getType());
if (ObjectUtil.isEmpty(type)) {throw new BusinessException("题目类型不正确,请查看");
}
question.setType(type);
QuestionDifficultyType difficultyType = QuestionDifficultyType.fromValue(questionCreateParamModel.getDifficultyType());
if (ObjectUtil.isEmpty(difficultyType)) {throw new BusinessException("题目难度参数不正确,请查看");
}
question.setDifficultyType(difficultyType);
questionMapper.insert(question);
解答题
齐全和填空题统一
判断题
性能展现
判断题和以上的题米都不统一,该有的内容:
- 题目类型
- 题目难度
- 题目内容
- 题目分数
- 是否正确
- 解析内容
参数
和单选题统一
次要逻辑
Question question = new Question();
question.setContent(questionCreateParamModel.getContent());
question.setScore(questionCreateParamModel.getScore());
question.setAnalysisContent(questionCreateParamModel.getAnalysisContent());
question.setIsRight(questionCreateParamModel.getIsRight());
question.setCourseUuid(questionCreateParamModel.getCourseUuid());
QuestionType type = QuestionType.fromValue(questionCreateParamModel.getType());
if (ObjectUtil.isEmpty(type)) {throw new BusinessException("题目类型不正确,请查看");
}
question.setType(type);
QuestionDifficultyType difficultyType = QuestionDifficultyType.fromValue(questionCreateParamModel.getDifficultyType());
if (ObjectUtil.isEmpty(difficultyType)) {throw new BusinessException("题目难度参数不正确,请查看");
}
question.setDifficultyType(difficultyType);
questionMapper.insert(question);
批改题目
和增加题目大抵一样,具体能够详见代码
导入题目
题目的导入也是该项目标亮点,咱们应用的多个 sheet 作为不同类型的题目,咱们次要在指定的工作区进行增加题目即可
咱们就开始来摸索这个导入性能
应用的 maven 依赖
<!-- easypoi -->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
这里咱们应用的 easypoi 第三方工具来进行反对
读取文件配置参数
Workbook workBook = ExcelUtil.getWorkBook(file);
// 执行循环导入
int numberOfSheets = workBook.getNumberOfSheets();
ImportParams params = new ImportParams();
循环读取不同的 sheet 来进行不同的解决逻辑
公共校验
// 校验学院
College college = collegeMapper.findByColumn("name",
radioQuestionImportExcel.getCollegeName())
.orElseThrow(() -> new BusinessException("单选题中第" + radioQuestionImportExcel.getRowNum() + "行谬误是:【"
+ radioQuestionImportExcel.getCollegeName() + "】所属学院不存在"));
// 校验业余
Major major = majorMapper.getByCollegeUuidAndMajorName(college.getUuid(),
radioQuestionImportExcel.getMajorName());
if (ObjectUtil.isEmpty(major)) {
String errorMsg =
"单选题中第" + radioQuestionImportExcel.getRowNum() + "行谬误是:所属学院【"
+ college.getName() + "】下【"
+ radioQuestionImportExcel.getMajorName()
+ "】业余不存在,请查看";
throw new BusinessException(errorMsg);
}
// 校验课程
Course course = courseMapper.getByMajorUuidAndCourseName(major.getUuid(),
radioQuestionImportExcel.getCourseName());
if (ObjectUtil.isEmpty(course)) {
String errorMsg =
"单选题中第" + radioQuestionImportExcel.getRowNum() + "行谬误是:所属业余【"
+ major.getName() + "】下【"
+ radioQuestionImportExcel.getCourseName()
+ "】课程不存在,请查看";
throw new BusinessException(errorMsg);
}
// 校验难度类型
QuestionDifficultyType questionDifficultyType = QuestionDifficultyType.fromName(radioQuestionImportExcel.getDifficultyType());
if (ObjectUtil.isEmpty(questionDifficultyType)) {
String errorMsg =
"单选题中第" + radioQuestionImportExcel.getRowNum() + "行谬误是:难度类型【"
+ radioQuestionImportExcel.getDifficultyType() + "不正确,请查看";
throw new BusinessException(errorMsg);
}
导入单选题逻辑
// 转化数据
QuestionCreateParamModel questionCreateParamModel = new QuestionCreateParamModel();
questionCreateParamModel.setContent(radioQuestionImportExcel.getContent());
questionCreateParamModel.setCourseUuid(course.getUuid());
questionCreateParamModel.setScore(radioQuestionImportExcel.getScore());
questionCreateParamModel.setType(QuestionType.RADIO.getValue());
questionCreateParamModel.setDifficultyType(questionDifficultyType.getValue());
questionCreateParamModel.setAnalysisContent(radioQuestionImportExcel.getAnalysisContent());
List<String> options = Lists.newArrayList();
options.add(radioQuestionImportExcel.getOptionA());
options.add(radioQuestionImportExcel.getOptionB());
options.add(radioQuestionImportExcel.getOptionC());
options.add(radioQuestionImportExcel.getOptionD());
questionCreateParamModel.setOptions(options);
// 将正确选项用,宰割开
String[] split = radioQuestionImportExcel.getRightOptions().split(",");
if (split.length != 1) {String errorMsg = "单选题中第" + radioQuestionImportExcel.getRowNum()
+ "行谬误是:正确选项只能是一个,请查看";
throw new BusinessException(errorMsg);
}
List<String> rightOptions = Arrays.asList(split);
questionCreateParamModel.setRightOptions(rightOptions);
log.info("单选题转化后的数据:{}", questionCreateParamModel);
questionCreateParamModels.add(questionCreateParamModel);
}
QuestionCreateHandler questionCreateHandler = questionFactory.getQuestionCreateHandler(sheetQuestionType.getValue());
questionCreateHandler.importQuestion(questionCreateParamModels);
导入多选题逻辑
// 转化数据
QuestionCreateParamModel questionCreateParamModel = new QuestionCreateParamModel();
questionCreateParamModel.setContent(multipleChoiceQuestionImportExcel.getContent());
questionCreateParamModel.setCourseUuid(course.getUuid());
questionCreateParamModel.setScore(multipleChoiceQuestionImportExcel.getScore());
questionCreateParamModel.setType(QuestionType.MULTIPLE_CHOICE.getValue());
questionCreateParamModel.setDifficultyType(questionDifficultyType.getValue());
questionCreateParamModel.setAnalysisContent(multipleChoiceQuestionImportExcel.getAnalysisContent());
List<String> options = Lists.newArrayList();
options.add(multipleChoiceQuestionImportExcel.getOptionA());
options.add(multipleChoiceQuestionImportExcel.getOptionB());
options.add(multipleChoiceQuestionImportExcel.getOptionC());
options.add(multipleChoiceQuestionImportExcel.getOptionD());
questionCreateParamModel.setOptions(options);
// 将正确选项用,宰割开
String[] split = multipleChoiceQuestionImportExcel.getRightOptions().split(",");
if (split.length != 1) {
String errorMsg =
"多选题中第" + multipleChoiceQuestionImportExcel.getRowNum()
+ "行谬误是:正确选项只能是一个,请查看";
throw new BusinessException(errorMsg);
}
List<String> rightOptions = Arrays.asList(split);
questionCreateParamModel.setRightOptions(rightOptions);
log.info("多选题转化后的数据:{}", questionCreateParamModel);
questionCreateParamModels.add(questionCreateParamModel);
}
QuestionCreateHandler questionCreateHandler = questionFactory.getQuestionCreateHandler(sheetQuestionType.getValue());
questionCreateHandler.importQuestion(questionCreateParamModels);
导入填空题逻辑
// 转化数据
QuestionCreateParamModel questionCreateParamModel = new QuestionCreateParamModel();
questionCreateParamModel.setContent(packQuestionImportExcel.getContent());
questionCreateParamModel.setCourseUuid(course.getUuid());
questionCreateParamModel.setScore(packQuestionImportExcel.getScore());
questionCreateParamModel.setType(QuestionType.PACK.getValue());
questionCreateParamModel.setDifficultyType(questionDifficultyType.getValue());
questionCreateParamModel.setAnalysisContent(packQuestionImportExcel.getAnalysisContent());
questionCreateParamModel.setRightAnswer(packQuestionImportExcel.getRightAnswer());
log.info("填空题转化后的数据:{}", questionCreateParamModel);
questionCreateParamModels.add(questionCreateParamModel);
}
QuestionCreateHandler questionCreateHandler = questionFactory.getQuestionCreateHandler(sheetQuestionType.getValue());
questionCreateHandler.importQuestion(questionCreateParamModels);
导入解答题逻辑
// 转化数据
QuestionCreateParamModel questionCreateParamModel = new QuestionCreateParamModel();
questionCreateParamModel.setContent(solutionQuestionImportExcel.getContent());
questionCreateParamModel.setCourseUuid(course.getUuid());
questionCreateParamModel.setScore(solutionQuestionImportExcel.getScore());
questionCreateParamModel.setType(QuestionType.SOLUTION.getValue());
questionCreateParamModel.setDifficultyType(questionDifficultyType.getValue());
questionCreateParamModel.setAnalysisContent(solutionQuestionImportExcel.getAnalysisContent());
questionCreateParamModel.setRightAnswer(solutionQuestionImportExcel.getRightAnswer());
log.info("解答题转化后的数据:{}", questionCreateParamModel);
questionCreateParamModels.add(questionCreateParamModel);
}
QuestionCreateHandler questionCreateHandler = questionFactory.getQuestionCreateHandler(sheetQuestionType.getValue());
questionCreateHandler.importQuestion(questionCreateParamModels);
导入判断题逻辑
// 转化数据
QuestionCreateParamModel questionCreateParamModel = new QuestionCreateParamModel();
questionCreateParamModel.setContent(judgementQuestionImportExcel.getContent());
questionCreateParamModel.setCourseUuid(course.getUuid());
questionCreateParamModel.setScore(judgementQuestionImportExcel.getScore());
questionCreateParamModel.setType(QuestionType.JUDGEMENT.getValue());
questionCreateParamModel.setDifficultyType(questionDifficultyType.getValue());
questionCreateParamModel.setAnalysisContent(judgementQuestionImportExcel.getAnalysisContent());
questionCreateParamModel.setIsRight(judgementQuestionImportExcel.getIsRight().equals("是"));
log.info("判断题转化后的数据:{}", questionCreateParamModel);
questionCreateParamModels.add(questionCreateParamModel);
}
QuestionCreateHandler questionCreateHandler = questionFactory.getQuestionCreateHandler(sheetQuestionType.getValue());
questionCreateHandler.importQuestion(questionCreateParamModels);
以上就是全副类型的题目导入性能逻辑,想看具体理解请查看退出常识星球
导出题目
题目的导出性能咱们还是通过 easypoi 来实现的,具体性能代码
log.info("开始导出题目数据,导出工夫:{}", DateUtil.now());
QuestionPageSearchQo questionPageSearchQo = BeanUtil.copyProperties(questionPageSearchBo,
QuestionPageSearchQo.class);
List<Question> questions = questionMapper.listExportData(questionPageSearchQo);
// 筛选出单选题
List<Question> radioQuestions = questions.stream()
.filter(question -> question.getType() == QuestionType.RADIO).collect(Collectors.toList());
// 筛选出多选题
List<Question> multipleChoiceQuestions = questions.stream()
.filter(question -> question.getType() == QuestionType.MULTIPLE_CHOICE).collect(Collectors.toList());
// 筛选出填空题
List<Question> packQuestions = questions.stream()
.filter(question -> question.getType() == QuestionType.PACK).collect(Collectors.toList());
// 筛选出解答题
List<Question> solutionQuestions = questions.stream()
.filter(question -> question.getType() == QuestionType.SOLUTION).collect(Collectors.toList());
// 筛选出判断题
List<Question> judgementQuestions = questions.stream()
.filter(question -> question.getType() == QuestionType.JUDGEMENT).collect(Collectors.toList());
// 组装单选数据
List<RadioQuestionExportExcel> radioQuestionExportExcels = assembleRadioData(radioQuestions);
// 组装多选数据
List<MultipleChoiceQuestionExportExcel> multipleChoiceQuestionExportExcels = assembleMultipleChoiceData(multipleChoiceQuestions);
// 组装填空数据
List<PackQuestionExportExcel> packQuestionExportExcels = assemblePackData(packQuestions);
// 组装解答数据
List<SolutionQuestionExportExcel> solutionQuestionExportExcels = assembleSolutionData(solutionQuestions);
// 组装判断数据
List<JudgementQuestionExportExcel> judgementQuestionExportExcels = assembleJudgementData(judgementQuestions);
List<Map<String, Object>> sheetsList = new ArrayList<>();
// 创立参数对象
ExportParams radioParams = new ExportParams();
radioParams.setSheetName("单选题");
ExportParams multipleChoiceParams = new ExportParams();
multipleChoiceParams.setSheetName("多选题");
ExportParams packParams = new ExportParams();
packParams.setSheetName("填空题");
ExportParams solutionParams = new ExportParams();
solutionParams.setSheetName("解答题");
ExportParams judgementParams = new ExportParams();
judgementParams.setSheetName("判断题");
Map<String, Object> radioMap = new HashMap<>();
radioMap.put("title", radioParams);
radioMap.put("entity", RadioQuestionExportExcel.class);
radioMap.put("data", radioQuestionExportExcels);
Map<String, Object> multipleChoiceMap = new HashMap<>();
multipleChoiceMap.put("title", multipleChoiceParams);
multipleChoiceMap.put("entity", MultipleChoiceQuestionExportExcel.class);
multipleChoiceMap.put("data", multipleChoiceQuestionExportExcels);
Map<String, Object> packMap = new HashMap<>();
packMap.put("title", packParams);
packMap.put("entity", PackQuestionExportExcel.class);
packMap.put("data", packQuestionExportExcels);
Map<String, Object> solutionMap = new HashMap<>();
solutionMap.put("title", solutionParams);
solutionMap.put("entity", SolutionQuestionExportExcel.class);
solutionMap.put("data", solutionQuestionExportExcels);
Map<String, Object> judgementMap = new HashMap<>();
judgementMap.put("title", judgementParams);
judgementMap.put("entity", JudgementQuestionExportExcel.class);
judgementMap.put("data", judgementQuestionExportExcels);
sheetsList.add(radioMap);
sheetsList.add(multipleChoiceMap);
sheetsList.add(packMap);
sheetsList.add(solutionMap);
sheetsList.add(judgementMap);
Workbook workbook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);
ExcelUtil.downLoadExcel("题目信息" + DateUtil.format(new Date(), "yyyy-MM-dd") + ".xls",
response,
workbook);
log.info("题目数据导出实现,导出实现工夫:{}", DateUtil.now());
总结
以上就是本次题库的全副性能,实现的货色也有很多,次要是在工厂模式 + 策略模式的应用,怎么做到代码优雅,那就是设计模式啦,
以及题目的导入导出性能,次要实现多 sheet 的导入和导出,应用 easypoi 实现其性能。
本文由 mdnice 多平台公布