|
@@ -9,32 +9,20 @@ import cn.com.qmth.examcloud.core.oe.admin.api.request.GetPagedToBeMarkExamRecor
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.api.response.GetPagedToBeMarkExamRecordResp;
|
|
|
import cn.com.qmth.examcloud.exchange.outer.api.ExamQuestionOuterService;
|
|
|
import cn.com.qmth.examcloud.exchange.outer.api.bean.*;
|
|
|
-import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetPaperStructReq;
|
|
|
import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetQuestionAnswerReq;
|
|
|
import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetSubjectivePaperStructReq;
|
|
|
import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetSubjectiveQuestionReq;
|
|
|
-import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetPaperStructResp;
|
|
|
import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetQuestionAnswerResp;
|
|
|
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetScoreQueueTopResp;
|
|
|
import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetSubjectivePaperStructResp;
|
|
|
import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetSubjectiveQuestionResp;
|
|
|
import cn.com.qmth.examcloud.exchange.outer.service.OutletPaperStructService;
|
|
|
import cn.com.qmth.examcloud.exchange.outer.service.bean.OuterCourseBean;
|
|
|
import cn.com.qmth.examcloud.exchange.outer.service.bean.OuterQuestionBean;
|
|
|
-import cn.com.qmth.examcloud.question.commons.core.paper.DefaultPaper;
|
|
|
-import cn.com.qmth.examcloud.question.commons.core.paper.DefaultQuestionGroup;
|
|
|
-import cn.com.qmth.examcloud.question.commons.core.paper.DefaultQuestionStructureWrapper;
|
|
|
-import cn.com.qmth.examcloud.question.commons.core.paper.DefaultQuestionUnitWrapper;
|
|
|
import cn.com.qmth.examcloud.question.commons.core.question.AnswerType;
|
|
|
import cn.com.qmth.examcloud.question.commons.core.question.QuestionType;
|
|
|
import cn.com.qmth.examcloud.support.cache.CacheHelper;
|
|
|
-import cn.com.qmth.examcloud.support.cache.bean.CourseCacheBean;
|
|
|
-import cn.com.qmth.examcloud.support.cache.bean.ExtractConfigPaperCacheBean;
|
|
|
import cn.com.qmth.examcloud.support.cache.bean.QuestionAnswerCacheBean;
|
|
|
-import cn.com.qmth.examcloud.support.enums.BlockType;
|
|
|
-import cn.com.qmth.examcloud.support.handler.richText.RichTextHandler;
|
|
|
-import cn.com.qmth.examcloud.support.handler.richText.RichTextHandlerFactory;
|
|
|
-import cn.com.qmth.examcloud.support.handler.richText.bean.SectionBean;
|
|
|
-import cn.com.qmth.examcloud.support.handler.richText.bean.SectionCollectionBean;
|
|
|
import cn.com.qmth.examcloud.support.helper.ExamCacheTransferHelper;
|
|
|
import cn.com.qmth.examcloud.web.support.ControllerSupport;
|
|
|
import cn.com.qmth.examcloud.web.support.StatusResponse;
|
|
@@ -44,6 +32,11 @@ import io.swagger.annotations.ApiOperation;
|
|
|
import io.swagger.annotations.ApiResponse;
|
|
|
import io.swagger.annotations.ApiResponses;
|
|
|
import org.apache.commons.collections.CollectionUtils;
|
|
|
+import org.jsoup.Jsoup;
|
|
|
+import org.jsoup.nodes.Document;
|
|
|
+import org.jsoup.nodes.Element;
|
|
|
+import org.jsoup.safety.Whitelist;
|
|
|
+import org.jsoup.select.Elements;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.web.bind.annotation.PostMapping;
|
|
|
import org.springframework.web.bind.annotation.RequestBody;
|
|
@@ -51,7 +44,11 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
import org.springframework.web.bind.annotation.RestController;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
|
|
|
/**
|
|
|
* @Description 考试作答服务
|
|
@@ -72,7 +69,6 @@ public class ExamQuestionOuterServiceProvider extends ControllerSupport implemen
|
|
|
@Autowired
|
|
|
private OutletPaperStructService outletPaperStructService;
|
|
|
|
|
|
-
|
|
|
@Override
|
|
|
@ApiOperation(value = "获取主观题试卷结构", httpMethod = "POST")
|
|
|
@ApiResponses({@ApiResponse(code = 200, message = "成功", response = OuterGetSubjectivePaperStructResp.class),
|
|
@@ -131,8 +127,6 @@ public class ExamQuestionOuterServiceProvider extends ControllerSupport implemen
|
|
|
@PostMapping("/getSubjectiveQuestion")
|
|
|
@Override
|
|
|
public OuterGetSubjectiveQuestionResp getSubjectiveQuestion(@RequestBody OuterGetSubjectiveQuestionReq req) {
|
|
|
- Long st = System.currentTimeMillis();
|
|
|
-
|
|
|
Long examId = req.getExamId();
|
|
|
if (null == examId) {
|
|
|
throw new StatusException("101001", "考试id不允许为空");
|
|
@@ -157,11 +151,6 @@ public class ExamQuestionOuterServiceProvider extends ControllerSupport implemen
|
|
|
throw new StatusException("101005", "数据量最大不得超过500");
|
|
|
}
|
|
|
|
|
|
- long startTime = System.currentTimeMillis();
|
|
|
- if (log.isDebugEnabled()) {
|
|
|
- log.debug("0 [GET_SUBJECTIVE_QUESTION-" + examId + "-" + subjectCode + "-" + startId + "] start...");
|
|
|
- }
|
|
|
-
|
|
|
GetPagedToBeMarkExamRecordReq pagedReq = new GetPagedToBeMarkExamRecordReq();
|
|
|
pagedReq.setExamId(examId);
|
|
|
pagedReq.setSubjectCode(subjectCode);
|
|
@@ -169,27 +158,10 @@ public class ExamQuestionOuterServiceProvider extends ControllerSupport implemen
|
|
|
pagedReq.setSize(size);
|
|
|
GetPagedToBeMarkExamRecordResp pagedResp = examRecordCloudService.getPagedToBeMarkExamRecord(pagedReq);
|
|
|
|
|
|
- if (log.isDebugEnabled()) {
|
|
|
- log.debug("1.[GET_SUBJECTIVE_QUESTION-" + examId + "-" + subjectCode + "-" + startId + "]" +
|
|
|
- "通过rpc获取待阅卷列表耗时:" + (System.currentTimeMillis() - startTime) + " ms");
|
|
|
- }
|
|
|
-
|
|
|
- startTime = System.currentTimeMillis();
|
|
|
-
|
|
|
OuterGetSubjectiveQuestionResp resp = new OuterGetSubjectiveQuestionResp();
|
|
|
resp.setNextId(pagedResp.getNextId());
|
|
|
resp.setDataList(getOuterExamRecordBean(pagedResp.getToBeMarkExamRecordBeanList()));
|
|
|
|
|
|
- if (log.isDebugEnabled()) {
|
|
|
- log.debug("2.[GET_SUBJECTIVE_QUESTION-" + examId + "-" + subjectCode + "-" + startId + "]" +
|
|
|
- "构造满足条件的考试记录集合耗时:" + (System.currentTimeMillis() - startTime) + " ms");
|
|
|
- }
|
|
|
-
|
|
|
- if (log.isDebugEnabled()) {
|
|
|
- log.debug("999.[GET_SUBJECTIVE_QUESTION-" + examId + "-" + subjectCode + "-" + startId + "] end..." +
|
|
|
- "合计耗时:" + (System.currentTimeMillis() - st) + " ms");
|
|
|
- }
|
|
|
-
|
|
|
return resp;
|
|
|
}
|
|
|
|
|
@@ -200,7 +172,7 @@ public class ExamQuestionOuterServiceProvider extends ControllerSupport implemen
|
|
|
@Override
|
|
|
public OuterGetQuestionAnswerResp getQuestionAnswer(@RequestBody OuterGetQuestionAnswerReq req) {
|
|
|
if (StringUtils.isNullOrEmpty(req.getQuestionId())) {
|
|
|
- throw new StatusException("102001", "题目id不允许为空");
|
|
|
+ throw new StatusException("102001","题目id不允许为空");
|
|
|
}
|
|
|
|
|
|
QuestionAnswerCacheBean questionAnswer = CacheHelper.getQuestionAnswer(req.getQuestionId());
|
|
@@ -211,94 +183,6 @@ public class ExamQuestionOuterServiceProvider extends ControllerSupport implemen
|
|
|
return resp;
|
|
|
}
|
|
|
|
|
|
- @ApiOperation(value = "获取试卷结构(题库中的原始试卷结构)", httpMethod = "POST")
|
|
|
- @ApiResponses({@ApiResponse(code = 200, message = "成功", response = OuterGetQuestionAnswerResp.class),
|
|
|
- @ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
|
|
|
- @PostMapping("/getPaperStruct")
|
|
|
- @Override
|
|
|
- public OuterGetPaperStructResp getPaperStruct(@RequestBody OuterGetPaperStructReq req) {
|
|
|
- if (null == req.getExamId()) {
|
|
|
- throw new StatusException("103001", "考试记录id不允许为空");
|
|
|
- }
|
|
|
-
|
|
|
- if (null == req.getCourseId()) {
|
|
|
- throw new StatusException("103002", "课程id不允许为空");
|
|
|
- }
|
|
|
-
|
|
|
- if (StringUtils.isNullOrEmpty(req.getPaperType())) {
|
|
|
- throw new StatusException("103003", "试卷类型不允许为空");
|
|
|
- }
|
|
|
-
|
|
|
- if (StringUtils.isNullOrEmpty(req.getBasePaperId())) {
|
|
|
- throw new StatusException("103004", "原始试卷id不允许为空");
|
|
|
- }
|
|
|
-
|
|
|
- CourseCacheBean course = CacheHelper.getCourse(req.getCourseId());
|
|
|
- if (null == course) {
|
|
|
- throw new StatusException("103005", "课程id不正确");
|
|
|
- }
|
|
|
-
|
|
|
- ExtractConfigPaperCacheBean extractConfigPaper = CacheHelper.getExtractConfigPaper(req.getExamId(),
|
|
|
- course.getCode(), req.getPaperType(), req.getBasePaperId());
|
|
|
-
|
|
|
- OuterGetPaperStructResp resp = new OuterGetPaperStructResp();
|
|
|
- if (null != extractConfigPaper.getDefaultPaper()) {
|
|
|
- resp.setDefaultPaper(transferPaperFrom(extractConfigPaper.getDefaultPaper()));
|
|
|
- }
|
|
|
-
|
|
|
- return resp;
|
|
|
- }
|
|
|
-
|
|
|
- private DefaultPaperBean transferPaperFrom(DefaultPaper defaultPaper) {
|
|
|
- DefaultPaperBean defaultPaperBean = new DefaultPaperBean();
|
|
|
- defaultPaperBean.setFullyObjective(defaultPaper.getFullyObjective());
|
|
|
- defaultPaperBean.setName(defaultPaper.getName());
|
|
|
-
|
|
|
- List<DefaultQuestionGroup> qgList = defaultPaper.getQuestionGroupList();
|
|
|
- List<DefaultQuestionGroupBean> qgBeanList = new ArrayList<>();
|
|
|
- for (DefaultQuestionGroup dqg : qgList) {
|
|
|
- DefaultQuestionGroupBean dqgBean = new DefaultQuestionGroupBean();
|
|
|
- dqgBean.setGroupName(dqg.getGroupName());
|
|
|
- dqgBean.setGroupScore(dqg.getGroupScore());
|
|
|
-
|
|
|
- List<DefaultQuestionStructureWrapper> qwList = dqg.getQuestionWrapperList();
|
|
|
- List<DefaultQuestionStructureWrapperBean> qwBeanList = new ArrayList<>();
|
|
|
- for (DefaultQuestionStructureWrapper qw : qwList) {
|
|
|
- DefaultQuestionStructureWrapperBean qwBean = new DefaultQuestionStructureWrapperBean();
|
|
|
- qwBean.setQuestionId(qw.getQuestionId());
|
|
|
- qwBean.setVersion(qw.getVersion());
|
|
|
- qwBean.setQuestionScore(qw.getQuestionScore());
|
|
|
- qwBean.setLimitedPlayTimes(qw.getLimitedPlayTimes());
|
|
|
- qwBean.setPlayedTimes(qw.getPlayedTimes());
|
|
|
- qwBean.setTimeLimit(qw.getTimeLimit());
|
|
|
-
|
|
|
- List<DefaultQuestionUnitWrapper> quwList = qw.getQuestionUnitWrapperList();
|
|
|
- List<DefaultQuestionUnitWrapperBean> quwBeanList = new ArrayList<>();
|
|
|
- for (DefaultQuestionUnitWrapper quw : quwList) {
|
|
|
- DefaultQuestionUnitWrapperBean quwBean = new DefaultQuestionUnitWrapperBean();
|
|
|
- quwBean.setOptionPermutation(quw.getOptionPermutation());
|
|
|
- quwBean.setQuestionScore(quw.getQuestionScore());
|
|
|
- quwBean.setQuestionType(quw.getQuestionType() == null ? null : quw.getQuestionType().name());
|
|
|
- quwBean.setAnswerType(quw.getAnswerType() == null ? null : quw.getAnswerType().name());
|
|
|
-
|
|
|
- quwBeanList.add(quwBean);
|
|
|
- }
|
|
|
-
|
|
|
- qwBean.setQuestionUnitWrapperList(quwBeanList);
|
|
|
-
|
|
|
- qwBeanList.add(qwBean);
|
|
|
- }
|
|
|
-
|
|
|
- dqgBean.setQuestionWrapperList(qwBeanList);
|
|
|
-
|
|
|
- qgBeanList.add(dqgBean);
|
|
|
- }
|
|
|
-
|
|
|
- defaultPaperBean.setQuestionGroupList(qgBeanList);
|
|
|
-
|
|
|
- return defaultPaperBean;
|
|
|
- }
|
|
|
-
|
|
|
|
|
|
/**
|
|
|
* 构造满足条件的考试记录集合
|
|
@@ -315,7 +199,7 @@ public class ExamQuestionOuterServiceProvider extends ControllerSupport implemen
|
|
|
for (PagedToBeMarkExamRecordBean pb : toBeMarkExamRecordBeanList) {
|
|
|
OuterExamRecordBean resultBean = new OuterExamRecordBean();
|
|
|
resultBean.setExamId(pb.getExamId());
|
|
|
- resultBean.setStudentCode(pb.getIdentityNumber());//因为外部接口定义的名字虽然叫studentCode,实际是身份证号
|
|
|
+ resultBean.setStudentCode(pb.getStudentCode());
|
|
|
resultBean.setName(pb.getStudentName());
|
|
|
resultBean.setCollege(pb.getGrade());
|
|
|
resultBean.setClassName(null);
|
|
@@ -341,7 +225,6 @@ public class ExamQuestionOuterServiceProvider extends ControllerSupport implemen
|
|
|
private List<OuterSubjectiveQuestionRecordBean> getSubjectives(Long examId,
|
|
|
List<PagedToBeMarkSubjectiveAnswerBean> subjectiveAnswerList) {
|
|
|
List<OuterSubjectiveQuestionRecordBean> resultList = new ArrayList<>();
|
|
|
- RichTextHandler complexRichTextHandler = RichTextHandlerFactory.getHandler("complex");
|
|
|
|
|
|
for (PagedToBeMarkSubjectiveAnswerBean pb : subjectiveAnswerList) {
|
|
|
OuterSubjectiveQuestionRecordBean resultBean = new OuterSubjectiveQuestionRecordBean();
|
|
@@ -349,110 +232,132 @@ public class ExamQuestionOuterServiceProvider extends ControllerSupport implemen
|
|
|
resultBean.setSubNumber(pb.getOrder());
|
|
|
resultBean.setQuestionId(pb.getQuestionId());
|
|
|
|
|
|
- resultBean.setAnswer(transferFrom(complexRichTextHandler.handle(pb.getAnswer())));
|
|
|
+ resultBean.setAnswer(getFormattedAnswer(pb.getAnswer()));
|
|
|
+ resultBean.setStudentAnswer(
|
|
|
+ getFormattedStudentAnswer(pb.getStudentAnswer(), pb.getAnswerType(), pb.getQuestionType(), examId));
|
|
|
+ resultBean.setBody(getFormattedBody(pb.getBody()));
|
|
|
+ resultBean.setParentBody(getFormattedParentBody(pb.getParentBody()));
|
|
|
|
|
|
- //格式化学生答案
|
|
|
- String transformedAnswerType = getTransformedAnswerType(pb.getAnswerType(), pb.getQuestionType(), examId);
|
|
|
+ resultList.add(resultBean);
|
|
|
+ }
|
|
|
+
|
|
|
+ return resultList;
|
|
|
+ }
|
|
|
|
|
|
- RichTextHandler richTextHandler = null;
|
|
|
- String stuAnswer = pb.getStudentAnswer();
|
|
|
- SectionCollectionBean formattedStudentAnswer = new SectionCollectionBean();
|
|
|
+ /**
|
|
|
+ * 格式化父题干
|
|
|
+ *
|
|
|
+ * @param parentBody
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private OuterSectionCollectionBean getFormattedParentBody(String parentBody) {
|
|
|
+ if (StringUtils.isNullOrEmpty(parentBody)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
|
|
|
- //图片作答特殊处理:将图片作答中的文字部分和图片部分拆开
|
|
|
- if (BlockType.image.name().equals(transformedAnswerType)) {
|
|
|
- if (!StringUtils.isNullOrEmpty(stuAnswer)) {
|
|
|
- //图片作答的标识
|
|
|
- String firstMatch = RegExpUtil.find(stuAnswer, "<div \\S*photo-answers-block\\S*>");
|
|
|
+ return getBodyOrAnswer(parentBody);
|
|
|
+ }
|
|
|
|
|
|
- int index;
|
|
|
- if (StringUtils.isNullOrEmpty(firstMatch)) {
|
|
|
- index = -1;
|
|
|
- } else {
|
|
|
- index = stuAnswer.indexOf(firstMatch);
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * 格式化小题题干
|
|
|
+ *
|
|
|
+ * @param body
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private OuterSectionCollectionBean getFormattedBody(String body) {
|
|
|
+ if (StringUtils.isNullOrEmpty(body)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
|
|
|
- //只有文字作答,处理文字
|
|
|
- if (index == -1) {
|
|
|
- richTextHandler = RichTextHandlerFactory.getHandler(BlockType.text.name());
|
|
|
- formattedStudentAnswer = richTextHandler.handle(stuAnswer);
|
|
|
- } else {
|
|
|
- //只有图片作答,处理图片
|
|
|
- if (index == 0) {
|
|
|
- richTextHandler = RichTextHandlerFactory.getHandler(BlockType.image.name());
|
|
|
- formattedStudentAnswer = richTextHandler.handle(stuAnswer);
|
|
|
- }
|
|
|
- //既有图片又有文字
|
|
|
- else {
|
|
|
- //文字部分
|
|
|
- String stuAnswer_text = stuAnswer.substring(0, index);
|
|
|
- SectionCollectionBean formattedStudentAnswer_text =
|
|
|
- RichTextHandlerFactory.getHandler(BlockType.text.name()).handle(stuAnswer_text);
|
|
|
-
|
|
|
- //图片部分
|
|
|
- String stuAnswer_image = stuAnswer.substring(index);
|
|
|
- SectionCollectionBean formattedStudentAnswer_image =
|
|
|
- RichTextHandlerFactory.getHandler(BlockType.image.name()).handle(stuAnswer_image);
|
|
|
-
|
|
|
- formattedStudentAnswer = new SectionCollectionBean();
|
|
|
- List<SectionBean> sections = new ArrayList<>();
|
|
|
- sections.addAll(formattedStudentAnswer_text.getSections());
|
|
|
- sections.addAll(formattedStudentAnswer_image.getSections());
|
|
|
- formattedStudentAnswer.setSections(sections);
|
|
|
+ return getBodyOrAnswer(body);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 格式化学生答案
|
|
|
+ *
|
|
|
+ * @param studentAnswer
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private OuterSectionCollectionBean getFormattedStudentAnswer(String studentAnswer,
|
|
|
+ AnswerType answerType,
|
|
|
+ QuestionType questionType, Long examId) {
|
|
|
+ String transformedAnswerType = getTransformedAnswerType(answerType, questionType, examId);
|
|
|
+
|
|
|
+ List<OuterSectionBean> sectionBeanList = new ArrayList<>();
|
|
|
+ List<OuterBlockBean> blockBeanList = new ArrayList<>();
|
|
|
+
|
|
|
+
|
|
|
+ //图片文件特殊处理
|
|
|
+ if ("image".equals(transformedAnswerType)) {
|
|
|
+ //图片文本部分
|
|
|
+ String txtStr = getImgTxt(studentAnswer);
|
|
|
+ if (!StringUtils.isNullOrEmpty(txtStr)) {
|
|
|
+ OuterBlockBean blockBean = new OuterBlockBean();
|
|
|
+ blockBean.setType("text");
|
|
|
+ blockBean.setValue(txtStr);
|
|
|
+ blockBeanList.add(blockBean);
|
|
|
+ }
|
|
|
+
|
|
|
+ //图片部分
|
|
|
+ if (validateImgAnswer(studentAnswer)) {
|
|
|
+ String imgSrc = getImgSrc(studentAnswer);
|
|
|
+ if (imgSrc.indexOf("|") > -1) {
|
|
|
+ String[] imgAnswers = imgSrc.split("\\|");
|
|
|
+
|
|
|
+ for (int i = 0; i < imgAnswers.length; i++) {
|
|
|
+ OuterBlockBean blockBean = new OuterBlockBean();
|
|
|
+ blockBean.setType(transformedAnswerType);
|
|
|
+ blockBean.setValue(getSimpleTransformedAnswer(transformedAnswerType, imgAnswers[i]));
|
|
|
+
|
|
|
+ //又拍云图片的宽*高
|
|
|
+ String imgWH = RegExpUtil.find(imgAnswers[i], "(\\d+)x(\\d+)");
|
|
|
+ if (!StringUtils.isNullOrEmpty(imgWH)) {
|
|
|
+ Map<String, Object> paramMap = new HashMap<>();
|
|
|
+ paramMap.put("width", Integer.valueOf(imgWH.split("x")[0]));
|
|
|
+ paramMap.put("height", Integer.valueOf(imgWH.split("x")[1]));
|
|
|
+ blockBean.setParam(paramMap);
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
+ blockBeanList.add(blockBean);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- //非图片作答,则直接根据作答类型进行处理
|
|
|
- else {
|
|
|
- richTextHandler = RichTextHandlerFactory.getHandler(transformedAnswerType);
|
|
|
- formattedStudentAnswer = richTextHandler.handle(stuAnswer);
|
|
|
+ } else if ("audio".equals(transformedAnswerType)) {
|
|
|
+ if (validateAudioAnswer(studentAnswer)) {
|
|
|
+ OuterBlockBean blockBean = new OuterBlockBean();
|
|
|
+ blockBean.setType(transformedAnswerType);
|
|
|
+ blockBean.setValue(getSimpleTransformedAnswer(transformedAnswerType, studentAnswer));
|
|
|
+ blockBeanList.add(blockBean);
|
|
|
}
|
|
|
|
|
|
- OuterSectionCollectionBean stuAnswerResult = transferFrom(formattedStudentAnswer);
|
|
|
-
|
|
|
- resultBean.setStudentAnswer(stuAnswerResult);
|
|
|
-
|
|
|
- resultBean.setBody(transferFrom(complexRichTextHandler.handle(pb.getBody())));
|
|
|
- resultBean.setParentBody(transferFrom(complexRichTextHandler.handle(pb.getParentBody())));
|
|
|
-
|
|
|
- resultList.add(resultBean);
|
|
|
+ } else {
|
|
|
+ OuterBlockBean blockBean = new OuterBlockBean();
|
|
|
+ blockBean.setType(transformedAnswerType);
|
|
|
+ blockBean.setValue(getSimpleTransformedAnswer(transformedAnswerType, studentAnswer));
|
|
|
+ blockBeanList.add(blockBean);
|
|
|
}
|
|
|
|
|
|
- return resultList;
|
|
|
+ OuterSectionBean sectionBean = new OuterSectionBean();
|
|
|
+ sectionBean.setBlocks(blockBeanList);
|
|
|
+ sectionBeanList.add(sectionBean);
|
|
|
+
|
|
|
+ OuterSectionCollectionBean resultBean = new OuterSectionCollectionBean();
|
|
|
+ resultBean.setSections(sectionBeanList);
|
|
|
+ return resultBean;
|
|
|
}
|
|
|
|
|
|
- private static OuterSectionCollectionBean transferFrom(SectionCollectionBean sectionCollection) {
|
|
|
- List<SectionBean> sections = sectionCollection.getSections();
|
|
|
- if (null == sections || sections.isEmpty()) {
|
|
|
- return new OuterSectionCollectionBean();
|
|
|
+ /**
|
|
|
+ * 格式化标准答案
|
|
|
+ *
|
|
|
+ * @param answer
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private OuterSectionCollectionBean getFormattedAnswer(String answer) {
|
|
|
+ if (StringUtils.isNullOrEmpty(answer)) {
|
|
|
+ return null;
|
|
|
}
|
|
|
|
|
|
- OuterSectionCollectionBean result = new OuterSectionCollectionBean();
|
|
|
-
|
|
|
- List<OuterSectionBean> outerSections = new ArrayList<>();
|
|
|
- sections.stream().forEach(sec -> {
|
|
|
- OuterSectionBean outerSection = new OuterSectionBean();
|
|
|
- List<OuterBlockBean> outerBlocks = new ArrayList<>();
|
|
|
-
|
|
|
- if (null != sec.getBlocks() && !sec.getBlocks().isEmpty()) {
|
|
|
- sec.getBlocks().stream().forEach(bl -> {
|
|
|
- OuterBlockBean outerBlock = new OuterBlockBean();
|
|
|
- outerBlock.setType(bl.getType());
|
|
|
- outerBlock.setValue(bl.getValue());
|
|
|
- outerBlock.setParam(bl.getParam());
|
|
|
- outerBlock.setPlayTime(bl.getPlayTime());
|
|
|
-
|
|
|
- outerBlocks.add(outerBlock);
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- outerSection.setBlocks(outerBlocks);
|
|
|
- outerSections.add(outerSection);
|
|
|
- });
|
|
|
-
|
|
|
- result.setSections(outerSections);
|
|
|
- return result;
|
|
|
+ return getBodyOrAnswer(answer);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -478,4 +383,212 @@ public class ExamQuestionOuterServiceProvider extends ControllerSupport implemen
|
|
|
|
|
|
return "text";
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取图片作答的文本部分
|
|
|
+ *
|
|
|
+ * @param studentAnswer
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getImgTxt(String studentAnswer) {
|
|
|
+ if (!StringUtils.isNullOrEmpty(studentAnswer)) {
|
|
|
+ return Jsoup.clean(studentAnswer, Whitelist.none());
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取图片作答图片路径
|
|
|
+ *
|
|
|
+ * @param studentAnswer
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getImgSrc(String studentAnswer) {
|
|
|
+ if (StringUtils.isNullOrEmpty(studentAnswer)) {
|
|
|
+ return studentAnswer;
|
|
|
+ }
|
|
|
+
|
|
|
+ //图片题特殊处理(因为图片作答题中有html标签,只需要取url即可)
|
|
|
+ Document doc = Jsoup.parse(studentAnswer);
|
|
|
+ Elements imgElements = doc.select("img[src]");
|
|
|
+
|
|
|
+ String imgSrc = "";
|
|
|
+
|
|
|
+ for (Element el : imgElements) {
|
|
|
+ String src = el.attr("src");
|
|
|
+ if (!StringUtils.isNullOrEmpty(src)) {
|
|
|
+ imgSrc += src + "|";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!StringUtils.isNullOrEmpty(imgSrc)) {
|
|
|
+ return imgSrc.substring(0, imgSrc.length() - 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ return imgSrc;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 单个答案再次格式化,去除地址中的多余后缀
|
|
|
+ *
|
|
|
+ * @param answerType
|
|
|
+ * @param studentAnswer
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getSimpleTransformedAnswer(String answerType, String studentAnswer) {
|
|
|
+ if ("image".equals(answerType)) {
|
|
|
+ String regExp = "(ftp|https?)\\:\\/\\/([\\w\\_\\-]+)\\.([\\w\\-]+[\\.]?)*[\\w]+\\.[a-zA-Z]{2,10}(.*)\\.(png|jpg|gif|jpeg)";
|
|
|
+ return RegExpUtil.find(studentAnswer, regExp);
|
|
|
+ }
|
|
|
+ return studentAnswer;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取格式化后后的题干或标准答案
|
|
|
+ *
|
|
|
+ * @param str
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private OuterSectionCollectionBean getBodyOrAnswer(String str) {
|
|
|
+ OuterSectionCollectionBean body = new OuterSectionCollectionBean();
|
|
|
+ List<OuterSectionBean> sections = new ArrayList<>();
|
|
|
+ // 得到小题题干或者答案行数
|
|
|
+ if (org.apache.commons.lang3.StringUtils.isBlank(str)) {
|
|
|
+ return body;
|
|
|
+ }
|
|
|
+ String[] questionRowStrings = str.split("</p>");
|
|
|
+ for (int i = 0; i < questionRowStrings.length; i++) {
|
|
|
+ List<OuterBlockBean> blocks = disposeQuestionBodyOrOption(questionRowStrings[i]);
|
|
|
+ if (blocks != null && blocks.size() > 0) {
|
|
|
+ OuterSectionBean section = new OuterSectionBean();
|
|
|
+ // 将小题题干拆分为Block集合
|
|
|
+ section.setBlocks(blocks);
|
|
|
+ sections.add(section);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ body.setSections(sections);
|
|
|
+ return body;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<OuterBlockBean> disposeQuestionBodyOrOption(String questionRow) {
|
|
|
+ List<OuterBlockBean> blocks = new ArrayList<>();
|
|
|
+ // 去掉每行里面的<p>,<span>,</span>标签
|
|
|
+ questionRow = questionRow.replaceAll("<p>", "").replaceAll("</p>", "").replaceAll("<span>", "")
|
|
|
+ .replaceAll("</span>", "").replaceAll("</a>", "");
|
|
|
+ String[] questionRowStrings = questionRow.split("<|/>|>");
|
|
|
+ for (int i = 0; i < questionRowStrings.length; i++) {
|
|
|
+ OuterBlockBean block = new OuterBlockBean();
|
|
|
+ String rowStr = questionRowStrings[i];
|
|
|
+ // 判断是否有图片
|
|
|
+ if (rowStr.startsWith("img")) {
|
|
|
+ rowStr = "<" + rowStr + ">";
|
|
|
+ Map<String, Object> param = new HashMap<>();
|
|
|
+ // 需要继续做截取,取到Parma
|
|
|
+ block.setType("image");
|
|
|
+ // 获取图片的路径
|
|
|
+ List<String> strSrcList = getImg(rowStr, "src");
|
|
|
+ if (strSrcList.size() > 0) {
|
|
|
+ String strSrc = strSrcList.get(0).replaceAll("src=\"", "").replaceAll("\"", "");
|
|
|
+ block.setValue(strSrc);
|
|
|
+ }
|
|
|
+ // 获取图片的高度
|
|
|
+ List<String> strHeightList = getImg(rowStr, "height");
|
|
|
+ if (strHeightList.size() > 0) {
|
|
|
+ String strHeight = strHeightList.get(0).replaceAll("height=\"", "").replaceAll("\"", "");
|
|
|
+ param.put("height", strHeight);
|
|
|
+ }
|
|
|
+ // 获取图片的宽度
|
|
|
+ List<String> strWidthList = getImg(rowStr, "width");
|
|
|
+ if (strHeightList.size() > 0) {
|
|
|
+ String strWidth = strWidthList.get(0).replaceAll("width=\"", "").replaceAll("\"", "");
|
|
|
+ param.put("width", strWidth);
|
|
|
+ }
|
|
|
+ block.setParam(param);
|
|
|
+ blocks.add(block);
|
|
|
+ } else if (rowStr.startsWith("a") && rowStr.contains("id") && rowStr.contains("name")) { // 处理音频
|
|
|
+ rowStr = "<" + rowStr + ">";
|
|
|
+ block.setPlayTime(1);
|
|
|
+ block.setType("audio");
|
|
|
+ block.setValue(this.getAttrValue(rowStr, "url"));
|
|
|
+ blocks.add(block);
|
|
|
+ } else {
|
|
|
+ block.setType("text");
|
|
|
+ rowStr = rowStr.replace(" ", "");// 消除空格
|
|
|
+ rowStr = rowStr.replace(""", "\"");// 将"转换成\"
|
|
|
+ rowStr = rowStr.replace("<", "<");// 将<转换成<
|
|
|
+ rowStr = rowStr.replace(">", ">");// 将>转换成>
|
|
|
+ rowStr = rowStr.replace("&", "&");// 将&转换成&
|
|
|
+ if (org.apache.commons.lang3.StringUtils.isNotBlank(rowStr)) {
|
|
|
+ block.setValue(rowStr);
|
|
|
+ blocks.add(block);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return blocks;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取图片里面的路径,长度,宽度
|
|
|
+ */
|
|
|
+ private List<String> getImg(String s, String str) {
|
|
|
+ String regex;
|
|
|
+ List<String> list = new ArrayList<>();
|
|
|
+ regex = str + "=\"(.*?)\"";
|
|
|
+ Pattern pa = Pattern.compile(regex, Pattern.DOTALL);
|
|
|
+ Matcher ma = pa.matcher(s);
|
|
|
+ while (ma.find()) {
|
|
|
+ list.add(ma.group());
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getAttrValue(String questionStr, String attrName) {
|
|
|
+ Pattern aPattern = Pattern.compile("a.*");
|
|
|
+ Matcher aMatcher = aPattern.matcher(questionStr);
|
|
|
+
|
|
|
+ if (aMatcher.find()) {
|
|
|
+ String idRegex = attrName + "=\".*?\"";
|
|
|
+ Pattern idPattern = Pattern.compile(idRegex);
|
|
|
+ Matcher idMatcher = idPattern.matcher(aMatcher.group());
|
|
|
+ if (idMatcher.find()) {
|
|
|
+ return idMatcher.group()
|
|
|
+ .replaceAll(attrName + "=\"", "")
|
|
|
+ .replaceAll("\"", "");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验图片答案格式是否正确
|
|
|
+ *
|
|
|
+ * @param studentAnswer
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private boolean validateImgAnswer(String studentAnswer) {
|
|
|
+ if (StringUtils.isNullOrEmpty(studentAnswer)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ String regExp = "[\\s\\S]*(ftp|https?)\\:\\/\\/([\\w\\_\\-]+)\\.([\\w\\-]+[\\.]?)*[\\w]+\\.[a-zA-Z]{2,10}(.*)\\.(png|jpg|gif|jpeg).*[\\s\\S]*";
|
|
|
+ return studentAnswer.matches(regExp);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验音频答案格式是否正确
|
|
|
+ *
|
|
|
+ * @param studentAnswer
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private boolean validateAudioAnswer(String studentAnswer) {
|
|
|
+ if (StringUtils.isNullOrEmpty(studentAnswer)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ String regExp = "^(ftp|https?)\\:\\/\\/([\\w\\_\\-]+)\\.([\\w\\-]+[\\.]?)*[\\w]+\\.[a-zA-Z]{2,10}(.*)\\.(mp3)";
|
|
|
+ return studentAnswer.matches(regExp);
|
|
|
+ }
|
|
|
+
|
|
|
}
|