word方式导入试题

beetlsql3-dev
Mlxa0324 2 years ago
parent 0d1ebd8f4a
commit d458f1b90c

@ -34,4 +34,6 @@ public interface ResourcesQuestionDao extends BaseMapper<ResourcesQuestion>{
* @return * @return
*/ */
List<QuestionTypeCountVO> getGroupQuestionTypeCount(Long courseInfoId); List<QuestionTypeCountVO> getGroupQuestionTypeCount(Long courseInfoId);
int checkUnique(ResourcesQuestion question);
} }

@ -1,5 +1,7 @@
package com.ibeetl.jlw.entity; package com.ibeetl.jlw.entity;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.jlw.validate.ValidateConfig; import cn.jlw.validate.ValidateConfig;
import com.ibeetl.admin.core.annotation.Dict; import com.ibeetl.admin.core.annotation.Dict;
import com.ibeetl.admin.core.annotation.DictEnum; import com.ibeetl.admin.core.annotation.DictEnum;
@ -8,7 +10,10 @@ import com.ibeetl.jlw.enums.AddTypeEnum;
import org.beetl.sql.annotation.entity.AutoID; import org.beetl.sql.annotation.entity.AutoID;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/* /*
* - * -
@ -285,4 +290,28 @@ public class ResourcesQuestion extends BaseEntity{
public void setAddType(AddTypeEnum addType) { public void setAddType(AddTypeEnum addType) {
this.addType = addType; this.addType = addType;
} }
/**,
*@return
*/
public String getQuestionStemRegexp(){
return ReUtil.escape(questionStem)
.replaceAll("<img.*?[^<]/>", "<img.*?[^<]/>")
.replace("(","").replace(")","");
}
public List<String> takeQuestionOptionConcatList() {
List<String> result = new ArrayList<>();
Field[] fields = ReflectUtil.getFields(this.getClass(), f -> f.getName().startsWith("questionOption"));
for (Field field : fields) {
Object fieldValue = ReflectUtil.getFieldValue(this, field);
if (fieldValue != null) {
result.add(fieldValue.toString());
}
}
return result;
}
} }

@ -1,36 +1,38 @@
package com.ibeetl.jlw.service; package com.ibeetl.jlw.service;
import cn.hutool.core.util.EnumUtil; import cn.hutool.core.util.*;
import cn.hutool.core.util.NumberUtil; import cn.jlw.Interceptor.GetFile;
import cn.hutool.core.util.ObjectUtil;
import cn.jlw.util.ToolUtils; import cn.jlw.util.ToolUtils;
import com.ibeetl.admin.core.entity.CoreUser;
import com.ibeetl.admin.core.service.CoreBaseService; import com.ibeetl.admin.core.service.CoreBaseService;
import com.ibeetl.admin.core.service.CorePlatformService; import com.ibeetl.admin.core.service.CorePlatformService;
import com.ibeetl.admin.core.util.BeanCopyUtil;
import com.ibeetl.admin.core.util.TimeTool; import com.ibeetl.admin.core.util.TimeTool;
import com.ibeetl.admin.core.web.JsonResult; import com.ibeetl.admin.core.web.JsonResult;
import com.ibeetl.admin.core.web.JsonReturnCode; import com.ibeetl.admin.core.web.JsonReturnCode;
import com.ibeetl.jlw.dao.CourseInfoDao; import com.ibeetl.jlw.dao.CourseInfoDao;
import com.ibeetl.jlw.dao.ResourcesQuestionDao; import com.ibeetl.jlw.dao.ResourcesQuestionDao;
import com.ibeetl.jlw.entity.CourseInfo; import com.ibeetl.jlw.entity.*;
import com.ibeetl.jlw.entity.FileEntity;
import com.ibeetl.jlw.entity.ResourcesQuestion;
import com.ibeetl.jlw.entity.UniversitiesCollegesJurisdictionExperimentalSystem;
import com.ibeetl.jlw.entity.dto.QuestionSettingDTO; import com.ibeetl.jlw.entity.dto.QuestionSettingDTO;
import com.ibeetl.jlw.entity.vo.QuestionTypeCountVO; import com.ibeetl.jlw.entity.vo.QuestionTypeCountVO;
import com.ibeetl.jlw.enums.AddTypeEnum; import com.ibeetl.jlw.enums.AddTypeEnum;
import com.ibeetl.jlw.enums.ResourcesQuestionTypeEnum; import com.ibeetl.jlw.enums.ResourcesQuestionTypeEnum;
import com.ibeetl.jlw.service.strategy.StrategyContext; import com.ibeetl.jlw.service.strategy.StrategyContext;
import com.ibeetl.jlw.validator.QuestionValidator;
import com.ibeetl.jlw.web.query.CourseInfoQuery; import com.ibeetl.jlw.web.query.CourseInfoQuery;
import com.ibeetl.jlw.web.query.ResourcesQuestionQuery; import com.ibeetl.jlw.web.query.ResourcesQuestionQuery;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.assertj.core.util.Lists; import org.assertj.core.util.Lists;
import org.beetl.sql.core.SqlId; import org.beetl.sql.core.SqlId;
import org.beetl.sql.core.engine.PageQuery; import org.beetl.sql.core.engine.PageQuery;
@ -43,17 +45,27 @@ import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.io.*; import java.io.*;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function; import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static cn.hutool.core.util.ArrayUtil.join; import static cn.hutool.core.util.ArrayUtil.join;
import static com.ibeetl.jlw.entity.ResourcesQuestionOptionEntity.shuffleOrderOptions; import static com.ibeetl.jlw.entity.ResourcesQuestionOptionEntity.shuffleOrderOptions;
import static com.ibeetl.jlw.service.strategy.StrategyContext.QuestionParagraphTypeEnum.OTHER;
import static com.ibeetl.jlw.service.strategy.StrategyContext.QuestionTypeConcatEnum.DECIDE;
import static com.ibeetl.jlw.service.strategy.StrategyContext.QuestionTypeConcatEnum.MULTIPLE;
import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.joining;
import static org.apache.poi.util.LocaleID.SE;
/** /**
@ -75,6 +87,7 @@ public class ResourcesQuestionService extends CoreBaseService<ResourcesQuestion>
@Autowired private ResourcesQuestionService resourcesQuestionService; @Autowired private ResourcesQuestionService resourcesQuestionService;
@Autowired private StrategyContext strategyContext; @Autowired private StrategyContext strategyContext;
@Autowired private QuestionValidator questionValidator;
public PageQuery<ResourcesQuestion> queryByCondition(PageQuery query){ public PageQuery<ResourcesQuestion> queryByCondition(PageQuery query){
PageQuery ret = resourcesQuestionDao.queryByCondition(query); PageQuery ret = resourcesQuestionDao.queryByCondition(query);
@ -776,254 +789,278 @@ public class ResourcesQuestionService extends CoreBaseService<ResourcesQuestion>
return g; return g;
} }
// @SneakyThrows @SneakyThrows
// public JsonResult importQBankWordTemplate(final Integer isPublic, @NotEmpty List<FileEntity> fileEntityList, CoreUser coreUser, String referer) { public JsonResult importQBankWordTemplate(@NotEmpty List<FileEntity> fileEntityList, CoreUser coreUser, String referer) {
// // 公共库题目导入,用于下面的部分验证 /** 找出段落, 逐段落处理 */
// final String publicReferer = "/jlw/question/importExcel.do"; AtomicReference<FileInputStream> inputStream = new AtomicReference<>();
// /** 找出段落, 逐段落处理 */ AtomicReference<XWPFDocument> xDocument = new AtomicReference<>();
// AtomicReference<FileInputStream> inputStream = new AtomicReference<>();
// AtomicReference<XWPFDocument> xDocument = new AtomicReference<>(); //装结果 key卷子访问地址 value{标题题目List}
// Map<String,Object[]> resultMap = new HashMap<>();
// //装结果 key卷子访问地址 value{标题题目List} /** 仅用于存放标题 */
// Map<String,Object[]> resultMap = new HashMap<>(); final String[] title = { Strings.EMPTY };
// /** 仅用于存放标题 */ /** 标题暂存,可能是多个 */
// final String[] title = { Strings.EMPTY }; final StringBuilder titleStb = new StringBuilder();
// /** 标题暂存,可能是多个 */
// final StringBuilder titleStb = new StringBuilder(); /** 循环文件集合 */
// fileEntityList.forEach(fileEntity -> {
// /** 循环文件集合 */ /** 上传文件的临时路径 */
// Long finalCorSchoolId = corSchoolId; String importPath = fileEntity.getAbsoluteUrl();
// fileEntityList.forEach(fileEntity -> { /** 新建文件夹绝对路径 */
// /** 上传文件的临时路径 */ String absoluteDirPath = String.format("%s%s%s%s%s%s", GetFile.p , SE , "filesystem" , SE , "temp" , SE );
// String importPath = fileEntity.getAbsoluteUrl(); /** 新建文件的绝对路径 */
// /** 新建文件夹绝对路径 */ String absolutePath = absoluteDirPath + fileEntity.getTempName();
// String absoluteDirPath = String.format("%s%s%s%s%s%s", GetFile.p , SE , "filesystem" , SE , "temp" , SE ); //各种流
// /** 新建文件的绝对路径 */ try {
// String absolutePath = absoluteDirPath + fileEntity.getTempName(); inputStream.set(new FileInputStream(importPath));
// //各种流 xDocument.set(new XWPFDocument(inputStream.get()));
// try { /** 集合拷贝 */
// inputStream.set(new FileInputStream(importPath)); List<MyXWPFParagraph> myParagraphs = BeanCopyUtil.copyListProperties(xDocument.get().getParagraphs() , MyXWPFParagraph::new, (t, d) -> {
// xDocument.set(new XWPFDocument(inputStream.get())); d.setXwpfParagraph(t);
// /** 集合拷贝 */ });
// List<MyXWPFParagraph> myParagraphs = BeanCopyUtil.copyListProperties(xDocument.get().getParagraphs() , MyXWPFParagraph::new, (t, d) -> {
// d.setXwpfParagraph(t); /** 需要存库的题目集合 */
// }); List<ResourcesQuestion> questionList = new CopyOnWriteArrayList<>();
// /** 题目类型 */
// /** 需要存库的题目集合 */ AtomicReference<StrategyContext.QuestionTypeConcatEnum> typeConcatEnum = new AtomicReference<>();
// List<ResourcesQuestion> questionList = new CopyOnWriteArrayList<>(); /** 段落类型 */
// /** 题目类型 */ AtomicReference<StrategyContext.QuestionParagraphTypeEnum> paragraphTypeEnum = new AtomicReference<>();
// AtomicReference<StrategyContext.QuestionTypeConcatEnum> typeConcatEnum = new AtomicReference<>(); /** 每题分数 */
// /** 段落类型 */ AtomicReference<BigDecimal> questionScore = new AtomicReference<>(BigDecimal.ZERO);
// AtomicReference<StrategyContext.QuestionParagraphTypeEnum> paragraphTypeEnum = new AtomicReference<>(); /** 题干 */
// /** 每题分数 */ AtomicReference<String> questionStem = new AtomicReference<>(Strings.EMPTY);
// AtomicReference<BigDecimal> questionScore = new AtomicReference<>(BigDecimal.ZERO); /** 答案 */
// /** 题干 */ AtomicReference<String> questionAnswer = new AtomicReference<>(Strings.EMPTY);
// AtomicReference<String> questionStem = new AtomicReference<>(Strings.EMPTY); /** 题目实体 */
// /** 答案 */ AtomicReference<ResourcesQuestion> question = new AtomicReference<>();
// AtomicReference<String> questionAnswer = new AtomicReference<>(Strings.EMPTY); /** 题干计数 */
// /** 题目实体 */ AtomicInteger recordsCount = new AtomicInteger();
// AtomicReference<ResourcesQuestion> question = new AtomicReference<>(); /** 遍历所有段落 */
// /** 题干计数 */ myParagraphs.forEach(e -> {
// AtomicInteger recordsCount = new AtomicInteger(); /** 策略中的参数设置 */
// /** 遍历所有段落 */ strategyContext.setText(e.getText(absoluteDirPath, fileEntity.getTempName())).start(c -> {
// myParagraphs.forEach(e -> { /** 第一行 */
// /** 策略中的参数设置 */ if (recordsCount.get() == 1 && StringUtils.isBlank(title[0])) {
// strategyContext.setText(e.getText(absoluteDirPath, fileEntity.getTempName())).start(c -> { /** 暴力取值 */
// /** 第一行 */ titleStb.append(title[0] = myParagraphs.get(0).getText(absoluteDirPath, fileEntity.getTempName()));
// if (recordsCount.get() == 1 && StringUtils.isBlank(title[0])) { }
// /** 暴力取值 */ /** k 策略枚举v 处理后的段落文字 */
// titleStb.append(title[0] = myParagraphs.get(0).getText(absoluteDirPath, fileEntity.getTempName())); c.forEach((k, v) -> {
// } /** 记录段落类型, 未查询类型之外的类型 */
// /** k 策略枚举v 处理后的段落文字 */ if (!k.equals(OTHER)) {paragraphTypeEnum.set(k);}
// c.forEach((k, v) -> { switch(k) {
// /** 记录段落类型, 未查询类型之外的类型 */ /** 未匹配到的段落 */
// if (!k.equals(OTHER)) {paragraphTypeEnum.set(k);} case OTHER: {
// switch(k) { /** 如果非标题字符,可能是前一个段落的副行。需要追加到相应的段落中 */
// /** 未匹配到的段落 */ insertCorrespondingParagraph(typeConcatEnum, paragraphTypeEnum.get() ,v, question, questionStem, questionAnswer);
// case OTHER: { } break;
// /** 如果非标题字符,可能是前一个段落的副行。需要追加到相应的段落中 */ /** 题目类型,分值,该类型的总分 */
// insertCorrespondingParagraph(typeConcatEnum, paragraphTypeEnum.get() ,v, question, questionStem, questionAnswer); case TYPE: {
// } break; /** 题目类型作用域 */
// /** 题目类型,分值,该类型的总分 */ String[] sp = v.split(",");
// case TYPE: { typeConcatEnum.set(StrategyContext.QuestionTypeConcatEnum.matchText(sp[2]));
// /** 题目类型作用域 */ questionScore.set(NumberUtil.toBigDecimal(sp[0]).setScale(1, RoundingMode.HALF_UP));
// String[] sp = v.split(","); } break;
// typeConcatEnum.set(StrategyContext.QuestionTypeConcatEnum.matchText(sp[2])); /** 题干 */
// questionScore.set(NumberUtil.toBigDecimal(sp[0]).setScale(1, RoundingMode.HALF_UP)); case STEM: {
// } break; final String numStartRegex = "^\\d+[\\.\\、\\]";
// /** 题干 */ if(ReUtil.contains(numStartRegex, v)) {
// case STEM: { /** 题干的编号需要移除掉 */
// final String numStartRegex = "^\\d+[\\.\\、\\]"; questionStem.set(v.replaceFirst(numStartRegex, Strings.EMPTY).trim());
// if(ReUtil.contains(numStartRegex, v)) { /** 题数++ */
// /** 题干的编号需要移除掉 */ recordsCount.incrementAndGet();
// questionStem.set(v.replaceFirst(numStartRegex, Strings.EMPTY).trim()); /** 清空变量 */
// /** 题数++ */ questionAnswer.set(Strings.EMPTY);
// recordsCount.incrementAndGet();
// /** 清空变量 */ /** 带有编号的段落,是主题干。需要创建新的题目对象 */
// questionAnswer.set(Strings.EMPTY); ResourcesQuestion qs = new ResourcesQuestion();
// /** 题目类型,查询插入操作 */
// /** 带有编号的段落,是主题干。需要创建新的题目对象 */ QuestionType questionType = selectOrInsert(typeConcatEnum.get(), coreUser);
// Question qs = new Question(); qs.setQuestionTypeId(questionType.getQuestionTypeId());
// /** 题目类型,查询插入操作 */ qs.putQuestionTypeConcat(questionType.getQuestionTypeConcat());
// QuestionType questionType = selectOrInsert(typeConcatEnum.get(), coreUser); qs.putQuestionTypeName(questionType.getQuestionTypeName());
// qs.setQuestionTypeId(questionType.getQuestionTypeId()); qs.setQuestionScore(questionScore.get());
// qs.putQuestionTypeConcat(questionType.getQuestionTypeConcat());
// qs.putQuestionTypeName(questionType.getQuestionTypeName()); if (StringUtils.isNotBlank(questionStem.get())){
// qs.setSourceCorSchoolId(finalCorSchoolId); qs.setQuestionStem(questionStem.get().replace("<","&lt;").replace(">","&gt;"));
// qs.setQuestionScore(questionScore.get()); }else {
// qs.setQuestionAddTime(new Date()); qs.setQuestionStem(questionStem.get());
// }
// if (StringUtils.isNotBlank(questionStem.get())){
// qs.setQuestionStem(questionStem.get().replace("<","&lt;").replace(">","&gt;")); qs.setQuestionStatus(1);
// }else { qs.setUserId(coreUser.getId());
// qs.setQuestionStem(questionStem.get()); qs.setOrgId(coreUser.getOrgId());
// }
// question.set(qs);
// qs.setQuestionStatus(1); questionList.add(question.get());
// qs.set("sign", 0); }
// qs.setUserId(coreUser.getId()); } break;
// qs.setOrgId(coreUser.getOrgId()); /** 选项 */
// case OPTION: {
// question.set(qs); putQuestionOption(v, question.get());
// questionList.add(question.get()); } break;
// } /** 答案 questionAnswer不包含答案 字样 */
// } break; case ANSWER: {
// /** 选项 */ questionAnswer.set(questionAnswer.get().concat(v));
// case OPTION: { // questionAnswer.get() 默认不包含 【答案】 字样
// putQuestionOption(v, question.get()); questionAnswer.set(secondFormat(questionAnswer.get(), typeConcatEnum.get()));
// } break; question.get().setQuestionAnswer(questionAnswer.get());
// /** 答案 questionAnswer不包含答案 字样 */ } break;
// case ANSWER: { }
// questionAnswer.set(questionAnswer.get().concat(v)); });
// // questionAnswer.get() 默认不包含 【答案】 字样 });
// questionAnswer.set(secondFormat(questionAnswer.get(), typeConcatEnum.get())); });
// question.get().setQuestionAnswer(questionAnswer.get());
// } break; titleStb.append("</br><font size=\"0.5\" color=\"blue\">解析结果:");
// } titleStb.append(recordsCount.get());
// }); titleStb.append(" 道题目</font>");
// });
// }); Object ids[] = getCourseIdsNew(title[0], groupByCourseId.get(), groupByCourseName.get());
// final Long courseId = (Long)ids[0];
// if (referer.contains(publicReferer)) { final Long chapterId = (Long)ids[1];
// if(questionList.size() == 0){ String finalTitle = !referer.contains(publicReferer)? titleStb.toString(): titleStb.append(ids[2] + Strings.EMPTY).toString();
// titleStb.append("</br><font size=\"0.5\" color=\"red\">没有解析到题目</font>");
// }else if(ObjectUtil.isEmpty(typeConcatEnum.get())) { /** 最后检测属性, 并行处理,没有向外部非线程安全的变量写入东西,无需担心丢数据 */
// titleStb.append("</br><font size=\"0.5\" color=\"red\">没有解析到题型</font>"); questionList.parallelStream().forEach(item -> {
// }else { item.set("chapterId", ObjectUtil.defaultIfNull(chapterId, courseId));
// titleStb.append("</br><font size=\"0.5\" color=\"blue\">解析结果:"); questionValidator.checkQuestion(item);
// titleStb.append(recordsCount.get()); checkUnique(item);
// titleStb.append(" 道题目</font>"); });
// }
// } /** 本次上传的题目判断唯一性 */
// checkLocalQuestionsUnique(questionList);
// Object ids[] = getCourseIdsNew(title[0], groupByCourseId.get(), groupByCourseName.get());
// final Long courseId = (Long)ids[0]; /** 拼成前端需要的数据 */
// final Long chapterId = (Long)ids[1]; resultMap.put(url2HttpUrl(fileEntity.getUrl()),new Object[]{finalTitle,questionList});
// String finalTitle = !referer.contains(publicReferer)? titleStb.toString(): titleStb.append(ids[2] + Strings.EMPTY).toString(); } catch (Exception ex) { ex.printStackTrace(); }
// finally {
// /** 最后检测属性, 并行处理,没有向外部非线程安全的变量写入东西,无需担心丢数据 */ try {inputStream.get().close();xDocument.get().close();}
// questionList.parallelStream().forEach(item -> { catch (Exception ioe) {ioe.printStackTrace();}
// item.set("chapterId", ObjectUtil.defaultIfNull(chapterId, courseId)); }
// questionValidator.checkQuestion(item); });
// if (referer.contains(publicReferer)) {
// checkUnique(isPublic, item); return JsonResult.success(resultMap);
// } }
// });
// /** 取选项的正则 */
// /** 本次上传的题目判断唯一性 */ private Pattern optionPattern = Pattern.compile("^[A-Za-z][\\.\\、\\  ]");
// checkLocalQuestionsUnique(questionList);
// /**
// /** 拼成前端需要的数据 */ *
// resultMap.put(url2HttpUrl(fileEntity.getUrl()),new Object[]{finalTitle,questionList}); * @param text
// } catch (Exception ex) { ex.printStackTrace(); } * @param question
// finally { */
// try {inputStream.get().close();xDocument.get().close();} public void putQuestionOption(String text, ResourcesQuestion question){
// catch (Exception ioe) {ioe.printStackTrace();} //text为选项
// } if (StringUtils.isNotBlank(text)){
// }); text = text.replace("<","&lt;").replace(">","&gt;");
// }
// return JsonResult.success(resultMap); Matcher matcher = optionPattern.matcher(text);
// } if(matcher.find()){
// QuestionOption questionOption = new QuestionOption();
// /** questionOption.setQuestionOptionContent(text.substring(2));
// * 验证本地待上传的题库 是否存在重复, if(null != question.takeQuestionOptionList()){
// * 本次上传的题目判断唯一性 List<QuestionOption> questionOptionList = question.takeQuestionOptionList();
// * @param questionList questionOptionList.add(questionOption);
// */ question.putQuestionOptionList(questionOptionList);
// private void checkLocalQuestionsUnique(List<Question> questionList) { }else {
// if (ObjectUtil.isEmpty(questionList)) { return; } List<QuestionOption> questionOptionList = new ArrayList<>();
// // 默认给50道题的容量 questionOptionList.add(questionOption);
// final Set<String> hashMap = new LinkedHashSet<>(50); question.putQuestionOptionList(questionOptionList);
// final List<String> strings = new ArrayList<>(50); }
// for (Question question : questionList) {
// String questionToString = question.toString(); if(null != question.takeQuestionOptionConcatList()){
// // 如果添加失败,则代表题目已经存在 List<String> questionOptionConcatList = question.takeQuestionOptionConcatList();
// if (!hashMap.add(questionToString)) { questionOptionConcatList.add(text.substring(2));
// // 告知前端 错误异常 question.putQuestionOptionConcatList(questionOptionConcatList);
// question.set("errMsg", String.format("可能与上面的第 【%s】 题重复",strings.indexOf(questionToString) + 1)); }else {
// } List<String> questionOptionConcatList = new ArrayList<>();
// else { strings.add(questionToString); } questionOptionConcatList.add(text.substring(2));
// } question.putQuestionOptionConcatList(questionOptionConcatList);
// }
// hashMap.clear(); }
// strings.clear();
// } }
//
// /** /**
// * 检测题目唯一 * ,
// * @param question *
// */ * @param questionList
// public void checkUnique(Integer isPublic, @NotNull Question question) { */
// /** 正则去尽可能的精准匹配, 模糊查询img标签和() 符号 */ private void checkLocalQuestionsUnique(List<ResourcesQuestion> questionList) {
// question.set("questionStemRegexp", null); if (ObjectUtil.isEmpty(questionList)) { return; }
// try { // 默认给50道题的容量
// question.set("questionStemRegexp", "^" + question.getQuestionStemRegexp() + "$"); final Set<String> hashSet = new LinkedHashSet<>(50);
// if (publicSqlManager.getMapper(QuestionDao.class).checkUnique(question) > 0) { final List<String> strings = new ArrayList<>(50);
// question.set("errMsg", ObjectUtil.defaultIfNull(question.get("errMsg"), "") + "该题目可能存在重复!"); for (ResourcesQuestion question : questionList) {
// } String questionToString = question.toString();
// }catch (Exception e){ // 如果添加失败,则代表题目已经存在
// log.error("报错了:"+question.getQuestionStemRegexp()); if (!hashSet.add(questionToString)) {
// e.printStackTrace(); // 告知前端 错误异常
// } question.set("errMsg", String.format("可能与上面的第 【%s】 题重复",strings.indexOf(questionToString) + 1));
// } }
// else { strings.add(questionToString); }
// /** }
// * 格式化答案
// * <ol> hashSet.clear();
// * <p>情况一:</p> strings.clear();
// * <li><p>ABC</p> 只取 ABC</li> }
// * <li>转大写</li>
// * <li>ABC => 转换成A,B,C</li> /**
// * </ol> *
// * <ol> * @param question
// * <p>情况二:</p> */
// * <li><p>对</p> 只取 对</li> public void checkUnique(@NotNull ResourcesQuestion question) {
// * <li>转大写</li> /** 正则去尽可能的精准匹配, 模糊查询img标签和() 符号 */
// * question.set("questionStemRegexp", null);
// * @param QuestionAnswer 答案 try {
// * @param questionTypeConcatEnum question.set("questionStemRegexp", "^" + question.getQuestionStemRegexp() + "$");
// * @return if (resourcesQuestionDao.checkUnique(question) > 0) {
// */ question.set("errMsg", ObjectUtil.defaultIfNull(question.get("errMsg"), "") + "该题目可能存在重复!");
// public String secondFormat(String questionAnswer, StrategyContext.QuestionTypeConcatEnum typeConcatEnum) { }
// if (StringUtils.isBlank(questionAnswer)) { return questionAnswer; } }catch (Exception e){
// // 去除各种空格 log.error("报错了:"+question.getQuestionStemRegexp());
// questionAnswer = org.springframework.util.StringUtils.trimAllWhitespace(questionAnswer); e.printStackTrace();
// // <p>ABC</p> 只获取ABC 删除所有</>标签元素。 }
// String replaced = questionAnswer.replaceAll(" |</?[a-zA-Z\\u4e00-\\u9fa5]*?[^<]>", ""); }
// // 取中文或者字母, 也有移除空格等符号的操作
// String res = ObjectUtil.defaultIfNull(ReUtil.getGroup0("[A-Za-z\\u4e00-\\u9fa5]+", replaced), replaced).toUpperCase(); /**
// // 如果只有字母,则拆分规则: ABC => A,B,C *
// if (typeConcatEnum.equals(MULTIPLE) && ReUtil.isMatch("^[A-Za-z]+$",res)) { * <ol>
// // ABC => A,B,C * <p></p>
// String[] split = res.split(""); * <li><p>ABC</p> ABC</li>
// Arrays.sort(split); * <li></li>
// res = ArrayUtil.join(split, ","); * <li>ABC => A,B,C</li>
// } * </ol>
// // 判断题逻辑 * <ol>
// if (typeConcatEnum.equals(DECIDE) && ReUtil.isMatch("(正确)|(错误)|A|B",res)) { * <p></p>
// // ABC => A,B,C * <li><p></p> </li>
// res = res.replaceAll("(正确)|A", "对").replaceAll("(错误)|B", "错"); * <li></li>
// } *
// return res; * @param questionAnswer
// } * @param typeConcatEnum
* @return
*/
public String secondFormat(String questionAnswer, StrategyContext.QuestionTypeConcatEnum typeConcatEnum) {
if (StringUtils.isBlank(questionAnswer)) { return questionAnswer; }
// 去除各种空格
questionAnswer = org.springframework.util.StringUtils.trimAllWhitespace(questionAnswer);
// <p>ABC</p> 只获取ABC 删除所有</>标签元素。
String replaced = questionAnswer.replaceAll(" |</?[a-zA-Z\\u4e00-\\u9fa5]*?[^<]>", "");
// 取中文或者字母, 也有移除空格等符号的操作
String res = ObjectUtil.defaultIfNull(ReUtil.getGroup0("[A-Za-z\\u4e00-\\u9fa5]+", replaced), replaced).toUpperCase();
// 如果只有字母,则拆分规则: ABC => A,B,C
if (typeConcatEnum.equals(MULTIPLE) && ReUtil.isMatch("^[A-Za-z]+$",res)) {
// ABC => A,B,C
String[] split = res.split("");
Arrays.sort(split);
res = ArrayUtil.join(split, ",");
}
// 判断题逻辑
if (typeConcatEnum.equals(DECIDE) && ReUtil.isMatch("(正确)|(错误)|A|B",res)) {
// ABC => A,B,C
res = res.replaceAll("(正确)|A", "对").replaceAll("(错误)|B", "错");
}
return res;
}
} }

@ -99,7 +99,8 @@ public class StrategyContext {
SINGLE("单选题", 1, "单.+题"), SINGLE("单选题", 1, "单.+题"),
MULTIPLE("多选题",2, "多.+题"), MULTIPLE("多选题",2, "多.+题"),
DECIDE("判断题",3, "[判断]{1,2}.+题"), DECIDE("判断题",3, "[判断]{1,2}.+题"),
SHORT("简答题",4, "简.+题"); FILL_QUESTION("填空题",4, "填.+题"),
ANALYSIS_QUESTION("分析题",5, "分析题");
private String typeName; private String typeName;
private Integer typeConcat; private Integer typeConcat;

@ -0,0 +1,126 @@
package com.ibeetl.jlw.validator;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.jlw.util.ToolUtils;
import com.ibeetl.jlw.entity.ResourcesQuestion;
import org.apache.commons.lang3.Range;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import static com.ibeetl.jlw.service.strategy.StrategyContext.QuestionTypeConcatEnum.*;
/**
*
*
* @author mlx
* @date 2022/6/1
**/
@Component
public class QuestionValidator {
/**
*
*/
private Range<String> options = Range.between("A", "Z");
/**
*
* @param question
*/
public String checkQuestion(ResourcesQuestion question) {
try {
checkQuestionThrow(question);
}catch (IllegalArgumentException e) {
/** 动态对象中传入一份errMsg */
question.set("errMsg", e.getMessage());
return e.getMessage();
}
return Strings.EMPTY;
}
/**
*
* @param question
* @return
*/
public void checkQuestionThrow(ResourcesQuestion question) {
Assert.notNull(question, "题目为空");
List<String> questionOptionConcatList = question.takeQuestionOptionConcatList();
String error = optionIncludeAnswer(question, questionOptionConcatList,question.getQuestionAnswer());
Assert.isTrue(StringUtils.isBlank(error), error);
Assert.notBlank(question.getQuestionStem(), "题干为空");
Assert.notBlank(question.getQuestionAnswer(), "答案为空");
// 有空值,返回异常
Assert.isFalse(optionIsBlank(questionOptionConcatList), "选项有空值");
// 判断题
if(MULTIPLE.getTypeConcat().equals(question.getQuestionType())){
Assert.isFalse(null == questionOptionConcatList || questionOptionConcatList.size()<2, "至少要有两个选项");
}
}
/**
*
* @param questionOptionConcatList
* @return
*/
private Boolean optionIsBlank(List<String> questionOptionConcatList) {
if(ObjectUtil.isEmpty(questionOptionConcatList)){
return true;
}
List<String> tempList = ToolUtils.deepCopyList(questionOptionConcatList);
List<String> nullList = new ArrayList<>();
nullList.add(null);
List<String> blackList = new ArrayList<>();
blackList.add("");
tempList.remove(nullList);
tempList.remove(blackList);
if(tempList.size() != questionOptionConcatList.size()){
return true;
}
return false;
}
/**
*
*
* @param question
* @param questionOptionConcatList
* @param questionAnswer
* @return
*/
private String optionIncludeAnswer(ResourcesQuestion question, List<String> questionOptionConcatList, String questionAnswer) {
if(ObjectUtil.isEmpty(questionOptionConcatList)) {
return "选项为空";
}
if(StringUtils.isBlank(questionAnswer)){
return "答案为空";
}
// 是判断题
if (DECIDE.getTypeConcat().equals(question.getQuestionType())) {
// 答案只能是对或错,前后不能有空格
return !questionAnswer.matches("^[对错]$") ? "判断题答案有误": "";
}
// 是单选题
if (SINGLE.getTypeConcat().equals(question.getQuestionType())) {
// 单选题只能有一个答案
return questionAnswer.length() != 1 ? "单选题只能有一个答案": "";
}
for (String s : questionAnswer.split(",")) {
if (!options.contains(s.toUpperCase())) {
return "答案不在选项内";
}
}
return "";
}
}

@ -374,4 +374,18 @@ getGroupQuestionTypeCount
GROUP BY GROUP BY
t.question_type t.question_type
ORDER BY ORDER BY
t.question_type ASC t.question_type ASC
checkUnique
===
* 验证题干是否可能存在重复
SELECT
COUNT(0) num
FROM
question t
WHERE
1 = 1
AND replace(replace(t.question_stem,'(',''),')','') REGEXP #questionStemRegexp#
AND t.question_status = 1
Loading…
Cancel
Save