|
@@ -0,0 +1,272 @@
|
|
|
+package cn.com.qmth.dp.examcloud.oe.modules.get_student_answer_detail;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
+
|
|
|
+import org.apache.commons.collections.CollectionUtils;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.bson.Document;
|
|
|
+import org.jsoup.Jsoup;
|
|
|
+import org.jsoup.safety.Whitelist;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.dao.DataAccessException;
|
|
|
+import org.springframework.data.mongodb.core.DocumentCallbackHandler;
|
|
|
+import org.springframework.data.mongodb.core.MongoTemplate;
|
|
|
+import org.springframework.data.mongodb.core.query.Criteria;
|
|
|
+import org.springframework.data.mongodb.core.query.Query;
|
|
|
+import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
+import org.springframework.scheduling.annotation.Async;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import com.google.common.collect.Lists;
|
|
|
+import com.google.common.collect.Maps;
|
|
|
+import com.google.common.collect.Sets;
|
|
|
+import com.mongodb.MongoException;
|
|
|
+
|
|
|
+import cn.com.qmth.examcloud.commons.helpers.ObjectHolder;
|
|
|
+import cn.com.qmth.examcloud.commons.helpers.poi.ExcelWriter;
|
|
|
+import cn.com.qmth.examcloud.commons.util.JsonUtil;
|
|
|
+import cn.com.qmth.examcloud.commons.util.ResourceLoader;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 获取考生作答明细
|
|
|
+ *
|
|
|
+ * @author WANGWEI
|
|
|
+ * @date 2019年7月11日
|
|
|
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class GetStduentAnswerDetailService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ JdbcTemplate jdbcTemplate;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ MongoTemplate mongoTemplate;
|
|
|
+
|
|
|
+ private int sqlIndex = 1;
|
|
|
+
|
|
|
+ private boolean mustHaveScore = true;
|
|
|
+
|
|
|
+ public void start(Long examId, String... courseCodeLIst) throws Exception {
|
|
|
+ for (String courseCode : courseCodeLIst) {
|
|
|
+ start(examId, courseCode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Async
|
|
|
+ public void start(Long examId, String courseCode) throws Exception {
|
|
|
+ String packageName = this.getClass().getPackage().getName();
|
|
|
+ String packagePath = packageName.replaceAll("\\.", "/");
|
|
|
+ String sql = ResourceLoader
|
|
|
+ .getResource(packagePath + "/query_exam_record_data_" + sqlIndex + ".sql");
|
|
|
+ Object[] args = new Object[]{examId, courseCode};
|
|
|
+ List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, args);
|
|
|
+
|
|
|
+ Map<String, Double> maxScoreOf = Maps.newHashMap();
|
|
|
+ Map<String, Long> examRecordDataIdOf = Maps.newHashMap();
|
|
|
+ Map<Long, String> identityNumberOf = Maps.newHashMap();
|
|
|
+
|
|
|
+ for (Map<String, Object> map : result) {
|
|
|
+ Long examRecordDataId = (Long) map.get("EXAM_RECORD_DATA_ID");
|
|
|
+ Double score = (Double) map.get("SCORE");
|
|
|
+ String identityNumber = (String) map.get("IDENTITY_NUMBER");
|
|
|
+ String curCourseCode = (String) map.get("CODE");
|
|
|
+
|
|
|
+ if (null == score) {
|
|
|
+ throw new RuntimeException("score is null. examRecordDataId=" + examRecordDataId);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!curCourseCode.equals(courseCode)) {
|
|
|
+ throw new RuntimeException("unexpected exception. courseCode=" + courseCode);
|
|
|
+ }
|
|
|
+
|
|
|
+ identityNumberOf.put(examRecordDataId, identityNumber);
|
|
|
+
|
|
|
+ Double maxScore = maxScoreOf.get(identityNumber);
|
|
|
+ if (null == maxScore || maxScore <= score) {
|
|
|
+ examRecordDataIdOf.put(identityNumber, examRecordDataId);
|
|
|
+ maxScoreOf.put(identityNumber, score);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Long> examRecordDataIdList = new ArrayList<>(examRecordDataIdOf.values());
|
|
|
+
|
|
|
+ List<Object[]> datas = Lists.newArrayList();
|
|
|
+
|
|
|
+ List<Object[]> noStudentScoreList = Lists.newArrayList();
|
|
|
+
|
|
|
+ int total = examRecordDataIdList.size();
|
|
|
+ int count = 0;
|
|
|
+ for (Long cur : examRecordDataIdList) {
|
|
|
+ count++;
|
|
|
+ System.out.println("total: " + total + "; count: " + count);
|
|
|
+
|
|
|
+ List<Document> answers = getAnswers(cur);
|
|
|
+
|
|
|
+ String identityNumber = identityNumberOf.get(cur);
|
|
|
+
|
|
|
+ for (Document doc : answers) {
|
|
|
+ Integer order = doc.getInteger("order");
|
|
|
+ Double studentScore = doc.getDouble("studentScore");
|
|
|
+ Double questionScore = doc.getDouble("questionScore");
|
|
|
+ String questionId = doc.getString("questionId");
|
|
|
+ String studentAnswer = doc.getString("studentAnswer");
|
|
|
+ String correctAnswer = doc.getString("correctAnswer");
|
|
|
+ String questionType = doc.getString("questionType");
|
|
|
+
|
|
|
+ if (null == order) {
|
|
|
+ throw new RuntimeException("order is null. examRecordDataId=" + cur);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (null == questionType) {
|
|
|
+ throw new RuntimeException(
|
|
|
+ "questionType is null. examRecordDataId=" + cur + "; order=" + order);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (null == studentScore) {
|
|
|
+ // 无作答时,0分
|
|
|
+ if (StringUtils.isBlank(studentAnswer)) {
|
|
|
+ studentScore = 0D;
|
|
|
+ }
|
|
|
+ // 计算分数
|
|
|
+ else {
|
|
|
+
|
|
|
+ if (null == questionScore) {
|
|
|
+ throw new RuntimeException("questionScore is null. examRecordDataId="
|
|
|
+ + cur + ";courseCode=" + courseCode + ";order=" + order);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 客观题
|
|
|
+ if (questionType.equals("SINGLE_CHOICE")
|
|
|
+ || questionType.equals("MULTIPLE_CHOICE")
|
|
|
+ || questionType.equals("TRUE_OR_FALSE")) {
|
|
|
+
|
|
|
+ // 无正确答案时
|
|
|
+ if (StringUtils.isBlank(correctAnswer)) {
|
|
|
+ noStudentScoreList.add(new Object[]{cur, courseCode, order});
|
|
|
+ studentScore = null;
|
|
|
+ }
|
|
|
+ // 有正确答案时
|
|
|
+ else {
|
|
|
+ if (correctAnswer.equals(studentAnswer)) {
|
|
|
+ studentScore = questionScore;
|
|
|
+ } else {
|
|
|
+ studentScore = 0D;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ // 主观题
|
|
|
+ else if (questionType.equals("FILL_UP") || questionType.equals("ESSAY")) {
|
|
|
+ noStudentScoreList.add(new Object[]{cur, courseCode, order});
|
|
|
+ studentScore = null;
|
|
|
+ } else {
|
|
|
+ throw new RuntimeException("unknow questionType. questionType="
|
|
|
+ + questionType + "; examRecordDataId=" + cur + ";courseCode="
|
|
|
+ + courseCode + ";order=" + order);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (null != studentAnswer && !studentAnswer.contains("<img")) {
|
|
|
+ studentAnswer = Jsoup.clean(studentAnswer, Whitelist.simpleText());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (null != studentAnswer) {
|
|
|
+ if (questionType.equals("SINGLE_CHOICE")
|
|
|
+ || questionType.equals("MULTIPLE_CHOICE")) {
|
|
|
+ studentAnswer = studentAnswer.replaceAll("0", "A");
|
|
|
+ studentAnswer = studentAnswer.replaceAll("1", "B");
|
|
|
+ studentAnswer = studentAnswer.replaceAll("2", "C");
|
|
|
+ studentAnswer = studentAnswer.replaceAll("3", "D");
|
|
|
+ studentAnswer = studentAnswer.replaceAll("4", "E");
|
|
|
+ studentAnswer = studentAnswer.replaceAll("5", "F");
|
|
|
+ studentAnswer = studentAnswer.replaceAll("6", "G");
|
|
|
+ studentAnswer = studentAnswer.replaceAll("7", "H");
|
|
|
+ studentAnswer = studentAnswer.replaceAll("8", "I");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Object[] row = new Object[]{identityNumber, courseCode, String.valueOf(order),
|
|
|
+ questionId, studentAnswer, String.valueOf(studentScore)};
|
|
|
+
|
|
|
+ datas.add(row);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if (CollectionUtils.isNotEmpty(noStudentScoreList)) {
|
|
|
+ System.out.println("无分数 ============>");
|
|
|
+ Set<Long> examRecordDataIdSet = Sets.newHashSet();
|
|
|
+ for (Object[] objects : noStudentScoreList) {
|
|
|
+ examRecordDataIdSet.add((Long) objects[0]);
|
|
|
+ System.out.println(JsonUtil.toJson(objects));
|
|
|
+ }
|
|
|
+
|
|
|
+ String sql4QueryExamStudentInfo = ResourceLoader
|
|
|
+ .getResource(packagePath + "/query_exam_student_info.sql");
|
|
|
+ String ids = StringUtils.join(examRecordDataIdSet, ",");
|
|
|
+ sql4QueryExamStudentInfo = sql4QueryExamStudentInfo.replace("$$", ids);
|
|
|
+
|
|
|
+ List<Map<String, Object>> studentInfoList = jdbcTemplate
|
|
|
+ .queryForList(sql4QueryExamStudentInfo);
|
|
|
+
|
|
|
+ for (Map<String, Object> curStudent : studentInfoList) {
|
|
|
+ System.out.println(JsonUtil.toJson(curStudent));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mustHaveScore) {
|
|
|
+ throw new RuntimeException("无分数");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ String filePath = "D:/Temp/answers-detail-" + examId + "-" + courseCode + ".xlsx";
|
|
|
+
|
|
|
+ final String[] EXCEL_HEADER = new String[]{"身份证号码", "课程代码", "题号(跟蓝图里面的题号或者题目ID是对应的)",
|
|
|
+ "题目ID", "答案", "分数"};
|
|
|
+
|
|
|
+ ExcelWriter.write(EXCEL_HEADER, new Class[]{String.class, String.class, String.class,
|
|
|
+ String.class, String.class, String.class}, datas, new File(filePath));
|
|
|
+
|
|
|
+ System.out.println("OVER ! courseCode=" + courseCode);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取作答
|
|
|
+ *
|
|
|
+ * @author WANGWEI
|
|
|
+ * @param examRecordDataId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private List<Document> getAnswers(Long examRecordDataId) {
|
|
|
+ Query query = Query.query(Criteria.where("examRecordDataId").is(examRecordDataId));
|
|
|
+ final ObjectHolder<List<Document>> answersHolder = new ObjectHolder<List<Document>>(null);
|
|
|
+ mongoTemplate.executeQuery(query, "examRecordQuestions", new DocumentCallbackHandler() {
|
|
|
+
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ @Override
|
|
|
+ public void processDocument(Document document)
|
|
|
+ throws MongoException, DataAccessException {
|
|
|
+ List<Document> answers = (List<Document>) document.get("examQuestionEntities");
|
|
|
+ answersHolder.set(answers);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ List<Document> answers = answersHolder.get();
|
|
|
+ return answers;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setSqlIndex(int sqlIndex) {
|
|
|
+ this.sqlIndex = sqlIndex;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setMustHaveScore(boolean mustHaveScore) {
|
|
|
+ this.mustHaveScore = mustHaveScore;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|