Selaa lähdekoodia

主观题作答筛查

xiatian 1 vuosi sitten
vanhempi
commit
e57b7e3db0
19 muutettua tiedostoa jossa 886 lisäystä ja 56 poistoa
  1. 9 8
      pom.xml
  2. 35 0
      src/main/java/cn/com/qmth/dp/examcloud/oe/config/PrimaryMongoConfig.java
  3. 31 0
      src/main/java/cn/com/qmth/dp/examcloud/oe/config/SecondaryMongoConfig.java
  4. 217 0
      src/main/java/cn/com/qmth/dp/examcloud/oe/entity/question/ExamQuestionEntity.java
  5. 72 0
      src/main/java/cn/com/qmth/dp/examcloud/oe/entity/question/ExamRecordQuestionsEntity.java
  6. 24 21
      src/main/java/cn/com/qmth/dp/examcloud/oe/modules/debug/DebugService.java
  7. 8 6
      src/main/java/cn/com/qmth/dp/examcloud/oe/modules/export_questions_count/ExportQuestionsCountService.java
  8. 107 0
      src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findcheatanswer/FindCheatAnswerConsumer.java
  9. 43 0
      src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findcheatanswer/FindCheatAnswerProducer.java
  10. 47 0
      src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findcheatanswer/FindCheatAnswerRetDto.java
  11. 171 0
      src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findcheatanswer/FindCheatAnswerService.java
  12. 53 0
      src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findcheatanswer/QuestionDto.java
  13. 32 0
      src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findcheatanswer/QuestionTypeCount.java
  14. 6 1
      src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findreduplicatequestion/ExportQuesReduplicateConsumer.java
  15. 1 1
      src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findreduplicatequestion/ExportQuesReduplicateProducer.java
  16. 1 1
      src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findreduplicatequestion/ExportReduplicateQuestionService.java
  17. 14 14
      src/main/java/cn/com/qmth/dp/examcloud/oe/util/Calculator.java
  18. 6 0
      src/main/java/cn/com/qmth/dp/examcloud/oe/util/PaperUtil.java
  19. 9 4
      src/main/resources/application.properties

+ 9 - 8
pom.xml

@@ -5,25 +5,21 @@
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
     <modelVersion>4.0.0</modelVersion>
     <artifactId>examcloud-oe-tool</artifactId>
-    <version>v5.0.2-RELEASE</version>
     <packaging>jar</packaging>
 
     <parent>
         <groupId>cn.com.qmth.examcloud</groupId>
         <artifactId>examcloud-parent</artifactId>
-        <version>v5.0.2-RELEASE</version>
+        <version>${revision}</version>
+        <relativePath>../examcloud-parent/pom.xml</relativePath>
     </parent>
-
-    <properties>
-        <!-- 云平台版本 -->
-        <examcloud.version>v5.0.2-RELEASE</examcloud.version>
-    </properties>
+    
 
     <dependencies>
         <dependency>
             <groupId>cn.com.qmth.examcloud</groupId>
             <artifactId>examcloud-support</artifactId>
-            <version>${examcloud.version}</version>
+            <version>${revision}</version>
             <exclusions>
                 <exclusion>
                     <groupId>org.springframework.cloud</groupId>
@@ -31,6 +27,11 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud</groupId>
+            <artifactId>examcloud-core-questions-service</artifactId>
+            <version>${revision}</version>
+        </dependency>
         <dependency>
             <groupId>org.json</groupId>
             <artifactId>json</artifactId>

+ 35 - 0
src/main/java/cn/com/qmth/dp/examcloud/oe/config/PrimaryMongoConfig.java

@@ -0,0 +1,35 @@
+package cn.com.qmth.dp.examcloud.oe.config;
+
+import org.springframework.boot.autoconfigure.mongo.MongoProperties;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.data.mongodb.MongoDatabaseFactory;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
+
+@Configuration
+//@EnableMongoRepositories(basePackages = "com.。。。。",
+//        mongoTemplateRef = "primaryMongoTemplate")
+public class PrimaryMongoConfig {
+
+    @Bean
+    @Primary
+    @ConfigurationProperties(prefix="spring.data.mongodb.primary")
+    public MongoProperties primaryMongoProperties() {
+        return new MongoProperties();
+    }
+
+    @Primary
+    @Bean(name = "mongoTemplate")
+    public MongoTemplate primaryMongoTemplate() throws Exception {
+        return new MongoTemplate(primaryFactory(primaryMongoProperties()));
+    }
+
+    @Bean
+    @Primary
+    public MongoDatabaseFactory primaryFactory(MongoProperties mongoProperties) throws Exception {
+        return new SimpleMongoClientDatabaseFactory(primaryMongoProperties().getUri());
+    }
+}

+ 31 - 0
src/main/java/cn/com/qmth/dp/examcloud/oe/config/SecondaryMongoConfig.java

@@ -0,0 +1,31 @@
+package cn.com.qmth.dp.examcloud.oe.config;
+
+import org.springframework.boot.autoconfigure.mongo.MongoProperties;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.mongodb.MongoDatabaseFactory;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
+
+@Configuration
+//@EnableMongoRepositories(basePackages = "com.。。。。。",
+//        mongoTemplateRef = "secondaryMongoTemplate")
+public class SecondaryMongoConfig {
+
+    @Bean
+    @ConfigurationProperties(prefix="spring.data.mongodb.secondary")
+    public MongoProperties secondaryMongoProperties() {
+        return new MongoProperties();
+    }
+
+    @Bean(name = "secondaryMongoTemplate")
+    public MongoTemplate secondaryMongoTemplate() throws Exception {
+        return new MongoTemplate(secondaryFactory(secondaryMongoProperties()));
+    }
+
+    @Bean
+    public MongoDatabaseFactory secondaryFactory(MongoProperties mongoProperties) throws Exception {
+        return new SimpleMongoClientDatabaseFactory(secondaryMongoProperties().getUri());
+    }
+}

+ 217 - 0
src/main/java/cn/com/qmth/dp/examcloud/oe/entity/question/ExamQuestionEntity.java

@@ -0,0 +1,217 @@
+package cn.com.qmth.dp.examcloud.oe.entity.question;
+
+import java.io.Serializable;
+
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Id;
+
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import cn.com.qmth.examcloud.question.commons.core.question.AnswerType;
+import cn.com.qmth.examcloud.question.commons.core.question.QuestionType;
+
+/**
+ * @author chenken
+ * @date 2018/8/17 10:18
+ * @company QMTH
+ * @description 考生单题作答记录
+ */
+@Document(collection="examRecordQuestion")
+public class ExamQuestionEntity implements Serializable{
+
+    /**
+	 * 
+	 */
+	private static final long serialVersionUID = -6141069483774400912L;
+	
+	@Id
+	private String id;
+	/**
+	 * 考试记录Data Id
+	 */
+    private Long examRecordDataId;
+    /**
+     * 大题号
+     */
+    private Integer mainNumber;
+    /**
+     * 原题ID
+     */
+    private String questionId;
+    /**
+     * 顺序
+     */
+    private Integer order;
+    /**
+     * 小题分数
+     */
+    private Double questionScore;
+    /**
+     * 小题类型
+     */
+    private QuestionType questionType;
+    /**
+     * 标准答案
+     */
+    private String correctAnswer;
+    /**
+     * 考生作答
+     */
+    private String studentAnswer;
+    /**
+     * 学生小题得分
+     */
+    private Double studentScore;
+    /**
+     * 是否作答
+     */
+    private Boolean isAnswer;
+    /**
+     * 是否标记
+     */
+    private Boolean isSign;
+    
+    /**
+	 * 选项排序值
+	 */
+	private Integer[] optionPermutation;
+	
+	/**
+	 * 音频播放次数
+	 */
+	private String audioPlayTimes;
+	/**
+	 * 题目作答类型
+	 */
+	@Enumerated(EnumType.STRING)
+	private AnswerType answerType;	
+    
+	public ExamQuestionEntity() {}
+	
+	public String getId() {
+		return id;
+	}
+	public void setId(String id) {
+		this.id = id;
+	}
+	public Long getExamRecordDataId() {
+		return examRecordDataId;
+	}
+	public void setExamRecordDataId(Long examRecordDataId) {
+		this.examRecordDataId = examRecordDataId;
+	}
+	public Integer getMainNumber() {
+		return mainNumber;
+	}
+	/**
+	 * 设置 大题号
+	 * @param mainNumber
+	 */
+	public void setMainNumber(Integer mainNumber) {
+		this.mainNumber = mainNumber;
+	}
+	public String getQuestionId() {
+		return questionId;
+	}
+	/**
+	 * 设置题库试题ID
+	 * @param questionId
+	 */
+	public void setQuestionId(String questionId) {
+		this.questionId = questionId;
+	}
+	public Integer getOrder() {
+		return order;
+	}
+	/**
+	 * 设置小题号
+	 * @param order
+	 */
+	public void setOrder(Integer order) {
+		this.order = order;
+	}
+	public String getStudentAnswer() {
+		return studentAnswer;
+	}
+	public void setStudentAnswer(String studentAnswer) {
+		this.studentAnswer = studentAnswer;
+	}
+	public Double getStudentScore() {
+		return studentScore;
+	}
+	/**
+	 * 设置考生得分
+	 * @param studentScore
+	 */
+	public void setStudentScore(Double studentScore) {
+		this.studentScore = studentScore;
+	}
+	public Double getQuestionScore() {
+		return questionScore;
+	}
+	/**
+	 * 设置试题分数
+	 * @param questionScore
+	 */
+	public void setQuestionScore(Double questionScore) {
+		this.questionScore = questionScore;
+	}
+	public QuestionType getQuestionType() {
+		return questionType;
+	}
+	/**
+	 * 设置题型
+	 * @param questionType
+	 */
+	public void setQuestionType(QuestionType questionType) {
+		this.questionType = questionType;
+	}
+	public Boolean getIsAnswer() {
+		return isAnswer;
+	}
+	public void setIsAnswer(Boolean isAnswer) {
+		this.isAnswer = isAnswer;
+	}
+	public Boolean getIsSign() {
+		return isSign;
+	}
+	public void setIsSign(Boolean isSign) {
+		this.isSign = isSign;
+	}
+
+	public String getCorrectAnswer() {
+		return correctAnswer;
+	}
+
+	public void setCorrectAnswer(String correctAnswer) {
+		this.correctAnswer = correctAnswer;
+	}
+
+	public Integer[] getOptionPermutation() {
+		return optionPermutation;
+	}
+
+	public void setOptionPermutation(Integer[] optionPermutation) {
+		this.optionPermutation = optionPermutation;
+	}
+
+	public String getAudioPlayTimes() {
+		return audioPlayTimes;
+	}
+
+	public void setAudioPlayTimes(String audioPlayTimes) {
+		this.audioPlayTimes = audioPlayTimes;
+	}
+
+	public AnswerType getAnswerType() {
+		return answerType;
+	}
+
+	public void setAnswerType(AnswerType answerType) {
+		this.answerType = answerType;
+	}
+
+	
+	
+}

+ 72 - 0
src/main/java/cn/com/qmth/dp/examcloud/oe/entity/question/ExamRecordQuestionsEntity.java

@@ -0,0 +1,72 @@
+package cn.com.qmth.dp.examcloud.oe.entity.question;
+
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import cn.com.qmth.examcloud.question.commons.core.question.AnswerType;
+
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Id;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author chenken
+ * @date 2018年9月3日 上午10:46:06
+ * @company QMTH
+ * @description 考试作答试题集合
+ */
+@Document(collection = "examRecordQuestions")
+public class ExamRecordQuestionsEntity implements Serializable {
+    private static final long serialVersionUID = -1688201571728312142L;
+
+    @Id
+    private String id;
+
+    private Long examRecordDataId;
+
+    private Date creationTime;
+
+    private List<ExamQuestionEntity> examQuestionEntities;
+    
+    /**
+	 * 题目作答类型
+	 */
+	@Enumerated(EnumType.STRING)
+	private AnswerType answerType;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public Long getExamRecordDataId() {
+        return examRecordDataId;
+    }
+
+    public Date getCreationTime() {
+        return creationTime;
+    }
+
+    public void setCreationTime(Date creationTime) {
+        this.creationTime = creationTime;
+    }
+
+    public void setExamRecordDataId(Long examRecordDataId) {
+        this.examRecordDataId = examRecordDataId;
+    }
+
+    public List<ExamQuestionEntity> getExamQuestionEntities() {
+        return examQuestionEntities;
+    }
+
+    public void setExamQuestionEntities(
+            List<ExamQuestionEntity> examQuestionEntities) {
+        this.examQuestionEntities = examQuestionEntities;
+    }
+
+}

+ 24 - 21
src/main/java/cn/com/qmth/dp/examcloud/oe/modules/debug/DebugService.java

@@ -1,10 +1,13 @@
 package cn.com.qmth.dp.examcloud.oe.modules.debug;
 
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
+import cn.com.qmth.dp.examcloud.oe.entity.question.QuesOption;
+import cn.com.qmth.dp.examcloud.oe.entity.question.Question;
+import cn.com.qmth.dp.examcloud.oe.modules.export_course_questions_diff_count.QuestionTypeCount;
+import cn.com.qmth.examcloud.commons.util.DateUtil;
+import cn.com.qmth.examcloud.core.questions.service.bean.dto.GenPaperDto;
+import cn.com.qmth.examcloud.core.questions.service.impl.GenPaperService;
 import org.apache.commons.lang3.StringUtils;
+import org.bson.types.ObjectId;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
@@ -16,12 +19,12 @@ import org.springframework.data.mongodb.core.aggregation.Aggregation;
 import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
 import org.springframework.data.mongodb.core.aggregation.AggregationResults;
 import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
 import org.springframework.stereotype.Service;
 
-import cn.com.qmth.dp.examcloud.oe.entity.question.QuesOption;
-import cn.com.qmth.dp.examcloud.oe.entity.question.Question;
-import cn.com.qmth.dp.examcloud.oe.modules.export_course_questions_diff_count.QuestionTypeCount;
-import cn.com.qmth.examcloud.commons.util.DateUtil;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
 
 @Service
 public class DebugService {
@@ -37,22 +40,22 @@ public class DebugService {
     public static final String ELEMENT_TYPE_IMG = "image";
     
     public static final String ELEMENT_TYPE_DOCTAG = "doctag";
-//    @Autowired
-//    GenPaperService genPaperService;
+    @Autowired
+    GenPaperService genPaperService;
 	@Autowired
 	MongoTemplate mongoTemplate;
 
 	public void start() {
 		System.out.println("start *********************");
-//		GenPaperDto d=new GenPaperDto();
-//		d.setCourseNo("061001");
-//		d.setGenNumber(1);
-//		List<String> pids=new ArrayList<>();
-//		pids.add("62b965233c66227eeadbdd68");
-//		d.setPaperIds(pids);
-//		d.setPaperName("test1");
-//		d.setPaperStructId("656f2be8267c7c21db09b990");
-//		genPaperService.genPaper(d);
+		GenPaperDto d=new GenPaperDto();
+		d.setCourseNo("061001");
+		d.setGenNumber(1);
+		List<String> pids=new ArrayList<>();
+		pids.add("62b965233c66227eeadbdd68");
+		d.setPaperIds(pids);
+		d.setPaperName("test1");
+		d.setPaperStructId("656f2be8267c7c21db09b990");
+		genPaperService.genPaper(d);
 //		Query query = new Query();
 //		query.addCriteria(Criteria.where("paper.$id").is(new ObjectId("64ddd05a391d2033f36b0a20")));
 //		List<PaperDetailUnit> ps = mongoTemplate.find(query, PaperDetailUnit.class, "paperDetailUnit");
@@ -60,8 +63,8 @@ public class DebugService {
 //		for(PaperDetailUnit p:ps) {
 //			disposeQuestion(p.getQuestion());
 //		}
-		List<QuestionTypeCount> ret=countByType("WB7030", "17351");
-		System.out.println();
+//		List<QuestionTypeCount> ret=countByType("WB7030", "17351");
+//		System.out.println();
 	}
 	
 	private List<QuestionTypeCount> countByType(String courseCode, String rootOrgId) {

+ 8 - 6
src/main/java/cn/com/qmth/dp/examcloud/oe/modules/export_questions_count/ExportQuestionsCountService.java

@@ -12,6 +12,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
+import javax.annotation.Resource;
+
 import org.apache.poi.xssf.usermodel.XSSFRow;
 import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
@@ -33,22 +35,22 @@ import cn.com.qmth.dp.examcloud.oe.excel.ExportUtils;
 @Service
 public class ExportQuestionsCountService {
 
-	@Autowired
+	@Resource(name = "secondaryMongoTemplate")
 	MongoTemplate mongoTemplate;
 
 	public void start() {
 		Date start=new Date();
 		Query query = new Query();
-		query.addCriteria(Criteria.where("orgId").is("4").and("paperType").is("IMPORT"));
+		query.addCriteria(Criteria.where("orgId").is("18108").and("paperType").is("IMPORT"));
 		List<Paper> ps = mongoTemplate.find(query, Paper.class, "paper");
 		if (ps != null&&ps.size()>0) {
-			List<String> course= readCourseCode();
-			Map<String, String> courseMap = course.stream().collect(Collectors.toMap(a -> a, a -> a,(k1,k2)->k1));
+//			List<String> course= readCourseCode();
+//			Map<String, String> courseMap = course.stream().collect(Collectors.toMap(a -> a, a -> a,(k1,k2)->k1));
 			List<Paper> psRet=new ArrayList<>();
 			for (Paper paper : ps) {
-				if(paper.getName().indexOf("(211)")!=-1) {
+//				if(paper.getName().indexOf("(211)")!=-1) {
 					psRet.add(paper);
-				}
+//				}
 			}
 			if (psRet != null&&psRet.size()>0) {
 				Map<String,RetDto> map=new HashMap<>();

+ 107 - 0
src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findcheatanswer/FindCheatAnswerConsumer.java

@@ -0,0 +1,107 @@
+package cn.com.qmth.dp.examcloud.oe.modules.findcheatanswer;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Resource;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+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.stereotype.Service;
+
+import cn.com.qmth.dp.examcloud.oe.entity.question.ExamQuestionEntity;
+import cn.com.qmth.dp.examcloud.oe.entity.question.ExamRecordQuestionsEntity;
+import cn.com.qmth.dp.examcloud.oe.multithread.Consumer;
+import cn.com.qmth.dp.examcloud.oe.util.PaperUtil;
+import cn.com.qmth.dp.examcloud.oe.util.StringSimilarityUtils;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.question.commons.core.question.QuestionType;
+
+@Service
+@Scope("prototype")
+public class FindCheatAnswerConsumer extends Consumer<Long> {
+	@Autowired
+	private FindCheatAnswerService findCheatAnswerService;
+
+	@Resource(name = "secondaryMongoTemplate")
+	private MongoTemplate oeTemplate;
+
+	@Override
+	public void consume(Map<String, Object> param, Long recordId) {
+		ExamRecordQuestionsEntity qs = getStudentAnswer(recordId);
+		if (qs == null) {
+			throw new StatusException("未找到考生作答:"+recordId);
+		}
+		Map<String, Integer> subIndex = new HashMap<>();
+		for (ExamQuestionEntity q : qs.getExamQuestionEntities()) {
+			Integer curIndex = subIndex.get(q.getQuestionId());
+			if (curIndex == null) {
+				subIndex.put(q.getQuestionId(), 0);
+			} else {
+				subIndex.put(q.getQuestionId(), curIndex + 1);
+			}
+			if (QuestionType.SINGLE_CHOICE.equals(q.getQuestionType())
+					|| QuestionType.TRUE_OR_FALSE.equals(q.getQuestionType())) {
+//				if (!StringUtils.equals(q.getCorrectAnswer(), q.getStudentAnswer())) {
+//					return;
+//				}
+			} else if (QuestionType.MULTIPLE_CHOICE.equals(q.getQuestionType())) {
+//				if (!StringUtils.equals(sort(q.getCorrectAnswer()), sort(q.getStudentAnswer()))) {
+//					return;
+//				}
+			} else if (QuestionType.FILL_UP.equals(q.getQuestionType())) {
+				String correctAnswer = findCheatAnswerService.getQuestionAnswerText(q.getQuestionId(),
+						subIndex.get(q.getQuestionId()));
+				if (!StringUtils.equals(dis(q.getStudentAnswer()), correctAnswer)) {
+					return;
+				}
+			} else if (QuestionType.ESSAY.equals(q.getQuestionType())) {
+				String correctAnswer = findCheatAnswerService.getQuestionAnswerText(q.getQuestionId(),
+						subIndex.get(q.getQuestionId()));
+				String studentAnswer=PaperUtil.getExtractText(q.getStudentAnswer());
+				double similarity = StringSimilarityUtils.getSimilarityWithCosinesBySeg(correctAnswer, studentAnswer);
+				if (similarity < 0.85) {
+					return;
+				}
+			}else {
+				throw new StatusException("试题类型错误:"+recordId+" "+q.getOrder());
+			}
+		}
+		addRet(qs.getExamRecordDataId());
+	}
+
+	private String dis(String s) {
+		if (StringUtils.isBlank(s)) {
+			return "";
+		}
+		return s.replaceAll("##", "");
+	}
+
+	private ExamRecordQuestionsEntity getStudentAnswer(Long recordId) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("examRecordDataId").is(recordId));
+		List<ExamRecordQuestionsEntity> ret = oeTemplate.find(query, ExamRecordQuestionsEntity.class,
+				"examRecordQuestions");
+		if(CollectionUtils.isEmpty(ret)) {
+			return null;
+		}
+		return ret.get(0);
+	}
+
+	private String sort(String s) {
+		if (StringUtils.isBlank(s)) {
+			return "";
+		}
+		char[] stringtoChar = s.toCharArray();
+		Arrays.sort(stringtoChar);
+		String sortedString = new String(stringtoChar);
+		return sortedString;
+	}
+}

+ 43 - 0
src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findcheatanswer/FindCheatAnswerProducer.java

@@ -0,0 +1,43 @@
+package cn.com.qmth.dp.examcloud.oe.modules.findcheatanswer;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Service;
+
+import cn.com.qmth.dp.examcloud.oe.multithread.Producer;
+
+@Service
+public class FindCheatAnswerProducer extends Producer {
+	@Autowired
+	private JdbcTemplate jdbcTemplate;
+	
+	@Override
+	protected void produce(Map<String, Object> param) throws Exception {
+		Long examId = (Long) param.get("examId");
+		List<Long> cs = findAllRecordIds(examId);
+		System.out.println("recordCount:" + cs.size());
+		if (CollectionUtils.isNotEmpty(cs)) {
+			for (Long c : cs) {
+				offer(c);
+			}
+		}
+	}
+	
+	
+	private List<Long> findAllRecordIds(Long examId) {
+		StringBuilder sqlBuilder = new StringBuilder();
+		sqlBuilder.append(" select t.id from ec_oe_exam_record_data t ");
+		sqlBuilder.append(" where t.exam_id =" + examId);
+		sqlBuilder.append(" and t.id=52780182");
+
+//		RowMapper<Long> rowMapper = new BeanPropertyRowMapper<Long>(Long.class);
+		List<Long> ret = jdbcTemplate.queryForList(sqlBuilder.toString(),Long.class);
+		return ret;
+	}
+	
+
+}

+ 47 - 0
src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findcheatanswer/FindCheatAnswerRetDto.java

@@ -0,0 +1,47 @@
+package cn.com.qmth.dp.examcloud.oe.modules.findcheatanswer;
+
+import cn.com.qmth.dp.examcloud.oe.excel.ExcelProperty;
+
+public class FindCheatAnswerRetDto {
+	@ExcelProperty(name = "课程代码", width = 25, index =1)
+	private String courseCode;
+	@ExcelProperty(name = "学生名称", width = 25, index = 2)
+	private String studentName;
+	@ExcelProperty(name = "身份证号", width = 25, index = 3)
+	private String identityNumber;
+	@ExcelProperty(name = "学号", width = 25, index = 4)
+	private String studentCode;
+	@ExcelProperty(name = "考试记录id", width = 25, index = 5)
+	private Long examRecordDataId;
+	public String getCourseCode() {
+		return courseCode;
+	}
+	public void setCourseCode(String courseCode) {
+		this.courseCode = courseCode;
+	}
+	public String getIdentityNumber() {
+		return identityNumber;
+	}
+	public void setIdentityNumber(String identityNumber) {
+		this.identityNumber = identityNumber;
+	}
+	public String getStudentCode() {
+		return studentCode;
+	}
+	public void setStudentCode(String studentCode) {
+		this.studentCode = studentCode;
+	}
+	public Long getExamRecordDataId() {
+		return examRecordDataId;
+	}
+	public void setExamRecordDataId(Long examRecordDataId) {
+		this.examRecordDataId = examRecordDataId;
+	}
+	public String getStudentName() {
+		return studentName;
+	}
+	public void setStudentName(String studentName) {
+		this.studentName = studentName;
+	}
+
+}

+ 171 - 0
src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findcheatanswer/FindCheatAnswerService.java

@@ -0,0 +1,171 @@
+package cn.com.qmth.dp.examcloud.oe.modules.findcheatanswer;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.annotation.Resource;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.bson.types.ObjectId;
+import org.springframework.beans.factory.annotation.Autowired;
+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.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Service;
+
+import cn.com.qmth.dp.examcloud.oe.enums.question.QuesStructType;
+import cn.com.qmth.dp.examcloud.oe.excel.ExportUtils;
+import cn.com.qmth.dp.examcloud.oe.multithread.Consumer;
+import cn.com.qmth.dp.examcloud.oe.util.PaperUtil;
+
+/**
+ * 主观题作答筛查
+ * 
+ * @author chenken
+ *
+ */
+@Service
+public class FindCheatAnswerService {
+	private Long examId = 5860L;
+	private int threadCount = 40;
+	private static Lock lock = new ReentrantLock();
+	private static Map<String, String> questionTexts = new ConcurrentHashMap<>();
+	@Autowired
+	private JdbcTemplate jdbcTemplate;
+	@Resource(name = "mongoTemplate")
+	private MongoTemplate mongoTemplate;
+	@Autowired
+	private FindCheatAnswerProducer pr;
+
+	public void start() {
+		File file = new File("d:/ret.xlsx");
+		if (file.exists()) {
+			file.delete();
+		}
+		Date s = new Date();
+		try {
+			Map<String, Object> param = new HashMap<>();
+			param.put("examId", examId);
+			pr.startDispose(FindCheatAnswerConsumer.class, threadCount, param);
+			List<Long> ret = new ArrayList<>();
+			for (Consumer c : pr.getConsumers()) {
+				ret.addAll(c.getRet());
+			}
+			System.out.println("ret count:" + ret.size());
+			if (ret.size() == 0) {
+				return;
+			}
+			List<FindCheatAnswerRetDto> dtos = findRet(ret);
+			FileOutputStream fos = null;
+			try {
+				file.createNewFile();
+				fos = new FileOutputStream(file);
+				ExportUtils.makeExcel(FindCheatAnswerRetDto.class, dtos, fos);
+			} catch (Exception e) {
+				throw new RuntimeException(e);
+			} finally {
+				if (fos != null) {
+					try {
+						fos.close();
+					} catch (IOException e) {
+						e.printStackTrace();
+					}
+				}
+			}
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+
+		}
+		Date e = new Date();
+		System.out.println("time:" + (e.getTime() - s.getTime()));
+	}
+
+	private List<FindCheatAnswerRetDto> findRet(List<Long> ids) {
+		StringBuilder sqlBuilder = new StringBuilder();
+		sqlBuilder.append(" select t.id examRecordDataId,f.course_code courseCode,f.student_name studentName "
+				+ " ,f.identity_number identityNumber,f.student_code studentCode " + " from ec_oe_exam_record_data t ");
+		sqlBuilder.append(" left join ec_oe_exam_student f on t.exam_student_id=f.exam_student_id ");
+		sqlBuilder.append(" where t.id in(" + StringUtils.join(ids, ",") + ") ");
+
+		RowMapper<FindCheatAnswerRetDto> rowMapper = new BeanPropertyRowMapper<>(FindCheatAnswerRetDto.class);
+		List<FindCheatAnswerRetDto> ret = jdbcTemplate.query(sqlBuilder.toString(), rowMapper);
+		return ret;
+	}
+
+	public String getQuestionAnswerText(String questionId, Integer subIndex) {
+		if (StringUtils.isBlank(questionId)) {
+			throw new RuntimeException("题ID不能为空");
+		}
+		if (subIndex == null) {
+			throw new RuntimeException("subIndex不能为空");
+		}
+		String key = questionId + "-" + subIndex;
+
+		String text = questionTexts.get(key);
+		if (text != null) {
+			return text;
+		}
+		lock.lock();
+		try {
+			text = questionTexts.get(key);
+			if (text != null) {
+				return text;
+			}
+			text = getQuestionAnswer(questionId, subIndex);
+			questionTexts.put(text, text);
+			return text;
+		} finally {
+			lock.unlock();
+		}
+	}
+
+	private String getQuestionAnswer(String questionId, Integer subIndex) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(new ObjectId(questionId)));
+		List<QuestionDto> ret = mongoTemplate.find(query, QuestionDto.class, "question");
+		if (CollectionUtils.isEmpty(ret)) {
+			throw new RuntimeException("未找到试题:"+questionId);
+		}
+		QuestionDto que=ret.get(0);
+		String an = "";
+		if (QuesStructType.NESTED_ANSWER_QUESTION.equals(que.getQuestionType())) {
+			an = que.getSubQuestions().get(subIndex).getQuesAnswer();
+			if (StringUtils.isBlank(an)) {
+				an = "";
+				return an;
+			}
+			if (QuesStructType.FILL_BLANK_QUESTION.equals(que.getQuestionType())) {
+				an = an.replaceAll("##", "");
+			}
+		} else {
+			an = que.getQuesAnswer();
+			if (StringUtils.isBlank(an)) {
+				an = "";
+				return an;
+			}
+			if (QuesStructType.FILL_BLANK_QUESTION.equals(que.getQuestionType())) {
+				an = an.replaceAll("##", "");
+			}
+		}
+		if (StringUtils.isBlank(an)) {
+			an = "";
+		} else {
+			an = PaperUtil.getExtractText(an);
+		}
+		return an;
+	}
+
+}

+ 53 - 0
src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findcheatanswer/QuestionDto.java

@@ -0,0 +1,53 @@
+package cn.com.qmth.dp.examcloud.oe.modules.findcheatanswer;
+
+import java.util.List;
+
+import javax.persistence.Id;
+
+import cn.com.qmth.dp.examcloud.oe.enums.question.QuesStructType;
+
+public class QuestionDto {
+
+	@Id
+	protected String id;
+
+	private QuesStructType questionType;// 试题结构类型
+
+	private String quesAnswer;
+
+	private List<QuestionDto> subQuestions;// 子题目,用于套题
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public QuesStructType getQuestionType() {
+		return questionType;
+	}
+
+	public void setQuestionType(QuesStructType questionType) {
+		this.questionType = questionType;
+	}
+
+	public String getQuesAnswer() {
+		return quesAnswer;
+	}
+
+	public void setQuesAnswer(String quesAnswer) {
+		this.quesAnswer = quesAnswer;
+	}
+
+	public List<QuestionDto> getSubQuestions() {
+		return subQuestions;
+	}
+
+	public void setSubQuestions(List<QuestionDto> subQuestions) {
+		this.subQuestions = subQuestions;
+	}
+
+
+}

+ 32 - 0
src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findcheatanswer/QuestionTypeCount.java

@@ -0,0 +1,32 @@
+package cn.com.qmth.dp.examcloud.oe.modules.findcheatanswer;
+
+public class QuestionTypeCount {
+	private String questionType;
+	private String difficulty;
+	private long count;
+
+	public long getCount() {
+		return count;
+	}
+
+	public void setCount(long count) {
+		this.count = count;
+	}
+
+	public String getQuestionType() {
+		return questionType;
+	}
+
+	public void setQuestionType(String questionType) {
+		this.questionType = questionType;
+	}
+
+	public String getDifficulty() {
+		return difficulty;
+	}
+
+	public void setDifficulty(String difficulty) {
+		this.difficulty = difficulty;
+	}
+
+}

+ 6 - 1
src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findreduplicatequestion/ExportQuesReduplicateConsumer.java

@@ -1,6 +1,7 @@
 package cn.com.qmth.dp.examcloud.oe.modules.findreduplicatequestion;
 
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -22,6 +23,7 @@ import cn.com.qmth.dp.examcloud.oe.enums.question.QuesStructType;
 import cn.com.qmth.dp.examcloud.oe.multithread.Consumer;
 import cn.com.qmth.dp.examcloud.oe.util.PaperUtil;
 import cn.com.qmth.dp.examcloud.oe.util.StringSimilarityUtils;
+import cn.com.qmth.examcloud.commons.util.DateUtil;
 
 @Service
 @Scope("prototype")
@@ -106,10 +108,12 @@ public class ExportQuesReduplicateConsumer extends Consumer<Course> {
 //	}
 
 	private List<QuestionDto> findQuestion(String rootOrgId, String courseCode) {
+		Date day=DateUtil.parse("2024-01-01 00:00:00", "yyyy-MM-dd HH:mm:ss");
 		Query query = new Query();
 		query.addCriteria(Criteria.where("orgId").is(rootOrgId));
 		query.addCriteria(Criteria.where("course.code").is(courseCode));
-		query.addCriteria(Criteria.where("creationBy").is(646523L));
+//		query.addCriteria(Criteria.where("creationBy").is(646523L));
+		query.addCriteria(Criteria.where("creationDate").gt(day));
 		List<QuestionDto> ret = this.mongoTemplate.find(query, QuestionDto.class, "question");
 		return ret;
 	}
@@ -189,6 +193,7 @@ public class ExportQuesReduplicateConsumer extends Consumer<Course> {
 				String quesText2 = subdto.getExtractText();
 				double similarity = StringSimilarityUtils.getSimilarityWithCosinesBySeg(quesText1, quesText2);
 				if (similarity > 0.94) {
+//				if (StringUtils.equals(quesText1, quesText2)) {
 					checkIds.add(dto.getId());
 					checkIds.add(subdto.getId());
 					if (!hasGroup) {

+ 1 - 1
src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findreduplicatequestion/ExportQuesReduplicateProducer.java

@@ -38,7 +38,7 @@ public class ExportQuesReduplicateProducer extends Producer {
 			wb = new XSSFWorkbook(ResouceUtil.getStream("subject_info.xlsx"));
 			XSSFSheet sheet = wb.getSheetAt(0);
 			int rows = sheet.getLastRowNum();
-			for (int i = 2; i <= rows; i++) {
+			for (int i = 1; i <= rows; i++) {
 				Course c = new Course();
 				XSSFRow row = sheet.getRow(i);
 				String ecCode = row.getCell(0).getStringCellValue().trim();

+ 1 - 1
src/main/java/cn/com/qmth/dp/examcloud/oe/modules/findreduplicatequestion/ExportReduplicateQuestionService.java

@@ -17,7 +17,7 @@ import cn.com.qmth.examcloud.web.support.SpringContextHolder;
 
 @Service
 public class ExportReduplicateQuestionService {
-	private String rootOrgId = "17351";
+	private String rootOrgId = "17068";
 //	private String paperName = "230517";
 	private int threadCount=4;
 

+ 14 - 14
src/main/java/cn/com/qmth/dp/examcloud/oe/util/Calculator.java

@@ -37,8 +37,8 @@ public class Calculator {
      * @return
      */
     public static double add(double v1, double v2, int len) {
-        BigDecimal b1 = new BigDecimal(v1);
-        BigDecimal b2 = new BigDecimal(v2);
+        BigDecimal b1 = BigDecimal.valueOf(v1);
+        BigDecimal b2 = BigDecimal.valueOf(v2);
         return b1.add(b2).setScale(len, BigDecimal.ROUND_HALF_UP).doubleValue();
 
     }
@@ -52,12 +52,12 @@ public class Calculator {
         if(CollectionUtils.isEmpty(ds)) {
             throw new StatusException("数组为空");
         }
-        BigDecimal ret = new BigDecimal(0.0);
+        BigDecimal ret = BigDecimal.valueOf(0.0);
         for(Double d:ds) {
             if(d==null) {
                 throw new StatusException("数组元素为空");
             }
-            ret=ret.add(new BigDecimal(d));
+            ret=ret.add(BigDecimal.valueOf(d));
         }
         return ret.setScale(len, BigDecimal.ROUND_HALF_UP).doubleValue();
 
@@ -84,8 +84,8 @@ public class Calculator {
      * @return
      */
     public static double subtract(double v1, double v2, int len) {
-        BigDecimal b1 = new BigDecimal(v1);
-        BigDecimal b2 = new BigDecimal(v2);
+        BigDecimal b1 = BigDecimal.valueOf(v1);
+        BigDecimal b2 = BigDecimal.valueOf(v2);
         return b1.subtract(b2).setScale(len, BigDecimal.ROUND_HALF_UP).doubleValue();
 
     }
@@ -96,8 +96,8 @@ public class Calculator {
      * @return
      */
     public static double absoluteDiff(double v1, double v2, int len) {
-        BigDecimal b1 = new BigDecimal(v1);
-        BigDecimal b2 = new BigDecimal(v2);
+        BigDecimal b1 = BigDecimal.valueOf(v1);
+        BigDecimal b2 = BigDecimal.valueOf(v2);
         if(v1>v2) {
             return b1.subtract(b2).setScale(len, BigDecimal.ROUND_HALF_UP).doubleValue();
         }else {
@@ -126,8 +126,8 @@ public class Calculator {
      * @return
      */
     public static double multiply(double v1, double v2, int len) {
-        BigDecimal b1 = new BigDecimal(v1);
-        BigDecimal b2 = new BigDecimal(v2);
+        BigDecimal b1 = BigDecimal.valueOf(v1);
+        BigDecimal b2 = BigDecimal.valueOf(v2);
         return b1.multiply(b2).setScale(len, BigDecimal.ROUND_HALF_UP).doubleValue();
 
     }
@@ -154,8 +154,8 @@ public class Calculator {
      * @return
      */
     public static double divide(double v1, double v2, int len) {
-        BigDecimal b1 = new BigDecimal(v1);
-        BigDecimal b2 = new BigDecimal(v2);
+        BigDecimal b1 = BigDecimal.valueOf(v1);
+        BigDecimal b2 = BigDecimal.valueOf(v2);
         return b1.divide(b2, len, BigDecimal.ROUND_HALF_UP).doubleValue();
     }
 
@@ -163,8 +163,8 @@ public class Calculator {
         if(v1==null||v2==null||v2==0) {
             return "-";
         }
-        BigDecimal b1 = new BigDecimal(v1);
-        BigDecimal b2 = new BigDecimal(v2);
+        BigDecimal b1 = BigDecimal.valueOf(v1);
+        BigDecimal b2 = BigDecimal.valueOf(v2);
         return String.valueOf(b1.divide(b2, len, BigDecimal.ROUND_HALF_UP).doubleValue());
     }
 }

+ 6 - 0
src/main/java/cn/com/qmth/dp/examcloud/oe/util/PaperUtil.java

@@ -11,6 +11,12 @@ import cn.com.qmth.dp.examcloud.oe.modules.findreduplicatequestion.QuesOptionDto
 import cn.com.qmth.dp.examcloud.oe.modules.findreduplicatequestion.QuestionDto;
 
 public class PaperUtil {
+    public static String getExtractText(String html) {
+        if (StringUtils.isBlank(html)) {
+            return "";
+        }
+        return getTextInHtml(html);
+    }
     public static String getExtractText(QuestionDto question) {
         StringBuilder quesText = new StringBuilder();
         if (question == null) {

+ 9 - 4
src/main/resources/application.properties

@@ -16,14 +16,19 @@ spring.redis.database=0
 #
 # ********** mongodb config **********
 #
-spring.data.mongodb.uri=mongodb://${mguri.username}:${mguri.password}@${mguri.hostAndPortGroup}/${mguri.database}
+spring.data.mongodb.primary.uri=mongodb://${mguri.username}:${mguri.password}@${mguri.hostAndPortGroup}/${mguri.primary.database}?authSource=admin
+spring.data.mongodb.secondary.uri=mongodb://${mguri.username}:${mguri.password}@${mguri.hostAndPortGroup}/${mguri.secondary.database}?authSource=admin
+
+#spring.data.mongodb.uri=mongodb://${mguri.username}:${mguri.password}@${mguri.hostAndPortGroup}/${mguri.database}
 # ********** dev-39 oe
 mguri.hostAndPortGroup=192.168.10.130:27017
 mguri.username=examcloud_oe_dev
 mguri.password=examcloud_oe_dev
-mguri.database=examcloud_oe_dev
-spring.data.mongodb.database=examcloud_oe_dev
-spring.data.mongodb.grid-fs-database=examcloud_oe_dev
+mguri.primary.database=examcloud_oe_dev
+mguri.secondary.database=examcloud_question_dev
+#mguri.database=examcloud_oe_dev
+#spring.data.mongodb.database=examcloud_oe_dev
+#spring.data.mongodb.grid-fs-database=examcloud_oe_dev
 # ********** dev-39 question
 #mguri.hostAndPortGroup=192.168.10.130:27017
 #mguri.username=examcloud_question_dev