|
|
package com.ibeetl.jlw.entity;
|
|
|
|
|
|
import cn.hutool.core.collection.ConcurrentHashSet;
|
|
|
import cn.hutool.core.lang.Assert;
|
|
|
import cn.hutool.core.util.ArrayUtil;
|
|
|
import cn.hutool.core.util.ObjectUtil;
|
|
|
import cn.hutool.core.util.ReflectUtil;
|
|
|
|
|
|
import java.lang.reflect.Field;
|
|
|
import java.util.*;
|
|
|
|
|
|
import static org.apache.commons.lang3.StringUtils.join;
|
|
|
import static org.apache.commons.lang3.StringUtils.upperCase;
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 选择题选项实体, 部分参数封装
|
|
|
* 题目选项随机工具
|
|
|
*
|
|
|
* @author mlx
|
|
|
*/
|
|
|
public class ResourcesQuestionOptionEntity {
|
|
|
|
|
|
private Map<String, Boolean> optionTextMap = new HashMap(6);
|
|
|
|
|
|
public void put(String optionText, Boolean value) {
|
|
|
optionTextMap.put(optionText, value);
|
|
|
}
|
|
|
|
|
|
public Boolean get(String optionText) {
|
|
|
return optionTextMap.getOrDefault(optionText, false);
|
|
|
}
|
|
|
|
|
|
public boolean remove(String optionText) {
|
|
|
return optionTextMap.remove(optionText);
|
|
|
}
|
|
|
|
|
|
public boolean contains(String optionText) {
|
|
|
return optionTextMap.containsKey(optionText);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取是正确答案的列表,无序
|
|
|
*
|
|
|
* @return
|
|
|
*/
|
|
|
public List<String> getOptionTextList() {
|
|
|
List arrayList = new ArrayList(optionTextMap.keySet());
|
|
|
Collections.shuffle(arrayList);
|
|
|
return Collections.unmodifiableList(arrayList);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取乱序后的ABCDE答案
|
|
|
*
|
|
|
* @param answerMap <题目,ABCD..>
|
|
|
* @return
|
|
|
*/
|
|
|
public Set<String> getAnswerList(Map<String, String> answerMap) {
|
|
|
// 最后的答案
|
|
|
Set<String> answerList = new ConcurrentHashSet<>();
|
|
|
answerMap.forEach((optionText, newAnswer) -> {
|
|
|
optionTextMap.forEach((optionText2, isAnswer) -> {
|
|
|
if (optionText2.equals(optionText) && isAnswer) {
|
|
|
answerList.add(newAnswer);
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
return answerList;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 随机打乱选项的顺序, 支持所有题型的处理
|
|
|
*
|
|
|
* @param answerFieldName 答案的字段名,只能是逗号分割
|
|
|
* @param prefix 选项的属性前缀 questionOption
|
|
|
* @param lastIsUppercase 最后一个字段是否大写
|
|
|
*/
|
|
|
public static void shuffleOrderOptions(Object obj, final String answerFieldName, final String prefix, Boolean lastIsUppercase) {
|
|
|
String questionAnswer = (String)ReflectUtil.getFieldValue(obj, answerFieldName);
|
|
|
Assert.notBlank(questionAnswer, "答案不能为空!");
|
|
|
Assert.notBlank(prefix, "选项的属性前缀不能为空!");
|
|
|
|
|
|
// Map的简单封装
|
|
|
ResourcesQuestionOptionEntity optionEntity = new ResourcesQuestionOptionEntity();
|
|
|
|
|
|
// 答案字段处理
|
|
|
String[] options = ArrayUtil.removeBlank(questionAnswer.split(","));
|
|
|
|
|
|
// 记录属性名中的最后一位字符,记录ABCDEF....
|
|
|
List<String> lastLetterFieldNameList = new ArrayList<>(6);
|
|
|
|
|
|
// 遍历当前对象的所有属性,不包含父类
|
|
|
for (Field field : ReflectUtil.getFieldsDirectly(obj.getClass(), false)) {
|
|
|
|
|
|
// 选项questionOption 开头的属性
|
|
|
if (field.getName().startsWith(prefix)) {
|
|
|
// 反射,来获取当前属性最后一个字母:选项
|
|
|
String lastLetter = field.getName().substring(field.getName().length() - 1);
|
|
|
// 转大写控制
|
|
|
lastLetter = lastIsUppercase.equals(true)? upperCase(lastLetter): lastLetter;
|
|
|
// 选项里的内容
|
|
|
String optionText = (String)ReflectUtil.getFieldValue(obj, field);
|
|
|
if (null == optionText) { continue; }
|
|
|
// 记录ABCDEF....
|
|
|
lastLetterFieldNameList.add(lastLetter);
|
|
|
optionEntity.put(optionText, false);
|
|
|
|
|
|
// 正确答案中,是否包含当前选项
|
|
|
if (ArrayUtil.containsIgnoreCase(options, lastLetter)) {
|
|
|
// 标记为正确答案
|
|
|
optionEntity.put(optionText, true);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 乱序后
|
|
|
List<String> optionTextList = optionEntity.getOptionTextList();
|
|
|
// 答案和选项ABCDEF..对应
|
|
|
Map<String, String> answerMap = new HashMap<>(6);
|
|
|
// 判断题目是否有重复的值
|
|
|
Assert.isTrue(optionTextList.size() == lastLetterFieldNameList.size(),
|
|
|
"答案中有重复的值,请检查!");
|
|
|
|
|
|
// 乱序集合处理
|
|
|
for (int i = 0; i < lastLetterFieldNameList.size(); i++) {
|
|
|
// 选项的子母
|
|
|
String optionLetter = lastLetterFieldNameList.get(i);
|
|
|
// 选项中的文本
|
|
|
String optionText = optionTextList.get(i);
|
|
|
answerMap.put(optionText, optionLetter);
|
|
|
// 等价于这样赋值:this.questionOptionA = "";
|
|
|
ReflectUtil.setFieldValue(obj, prefix.concat(optionLetter), optionText);
|
|
|
}
|
|
|
|
|
|
// 如果没有选项,可能是单选或者其他类型的题目
|
|
|
Set<String> answerList = optionEntity.getAnswerList(answerMap);
|
|
|
Set<String> defaultAnswer = Collections.singleton(questionAnswer);
|
|
|
Set<String> answer = ObjectUtil.isNotEmpty(answerList)? answerList: defaultAnswer;
|
|
|
// 乱序后的正确答案赋值
|
|
|
ReflectUtil.setFieldValue(obj, answerFieldName, join(answer, ","));
|
|
|
}
|
|
|
}
|