xiatian пре 6 месеци
родитељ
комит
7267cf27d2

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

@@ -1,196 +1,223 @@
-package cn.com.qmth.dp.examcloud.oe.modules.debug;
-
-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;
-import org.jsoup.nodes.Node;
-import org.jsoup.nodes.TextNode;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.mongodb.core.MongoTemplate;
-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 java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-@Service
-public class DebugService {
-    
-
-
-    public static final String QUESOPS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
-    public static final String ELEMENT_TYPE_RID = "imageId";
-
-    public static final String ELEMENT_TYPE_TEXT = "text";
-
-    public static final String ELEMENT_TYPE_IMG = "image";
-    
-    public static final String ELEMENT_TYPE_DOCTAG = "doctag";
-    @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);
-//		Query query = new Query();
-//		query.addCriteria(Criteria.where("paper.$id").is(new ObjectId("64ddd05a391d2033f36b0a20")));
-//		List<PaperDetailUnit> ps = mongoTemplate.find(query, PaperDetailUnit.class, "paperDetailUnit");
-//		ExportPaperUtil.disposePaperDoc(ps);
-//		for(PaperDetailUnit p:ps) {
-//			disposeQuestion(p.getQuestion());
-//		}
-//		List<QuestionTypeCount> ret=countByType("WB7030", "17351");
-//		System.out.println();
-	}
-	
-	private List<QuestionTypeCount> countByType(String courseCode, String rootOrgId) {
-        Date day=DateUtil.parse("2023-08-21 00:00:00", "yyyy-MM-dd HH:mm:ss");
-		List<AggregationOperation> operations = new ArrayList<>();
-		operations.add(Aggregation.match(
-				Criteria.where("orgId").is(rootOrgId)
-				.and("course.code").is(courseCode)
-				.and("creationBy").is(646523L)
-				.and("creationDate").gt(day)
-					)
-				);
-		operations.add(Aggregation.group("questionType", "difficulty").count().as("count"));
-		operations.add(Aggregation.project("count").andInclude("questionType").andInclude("difficulty"));
-		Aggregation aggregation = Aggregation.newAggregation(operations);
-		AggregationResults<QuestionTypeCount> outputTypeCount = mongoTemplate.aggregate(aggregation, Question.class,
-				QuestionTypeCount.class);
-		return outputTypeCount.getMappedResults();
-	}
-	
-	private static void disposeQuestion(Question qes) {
-        if (qes != null) {
-
-            //处理选项
-            if (qes.getQuesOptions() != null && qes.getQuesOptions().size() > 0) {
-                int index = 0;
-                for (QuesOption qo : qes.getQuesOptions()) {
-                    List<JSection> slist2 = getSections(qo.getOptionBody());
-                    if (slist2 != null && slist2.size() > 0) {
-                        SectionElement se = new SectionElement();
-                        se.setType(ELEMENT_TYPE_TEXT);
-                        se.setValue(QUESOPS.charAt(index) + ".");
-                        index++;
-                        slist2.get(0).getElements().add(0, se);
-//                        qo.setOptionBodyWord(getQuestionDoc(slist2));
-                    }else {
-                    	System.out.println("******");
-                    }
-
-                }
-            }
-            
-            if (qes.getSubQuestions() != null && qes.getSubQuestions().size() > 0) {
-                for (Question sunqes : qes.getSubQuestions()) {
-                    disposeQuestion(sunqes);// 递归处理套题
-                }
-            }
-        }
-    }
-	private static List<JSection> getSections(String html) {
-        return getSections(html, false);
-    }
-
-    private static List<JSection> getSections(String html, boolean diposeFillBlank) {
-        if (StringUtils.isBlank(html)) {
-            return getEmptySections();
-        }
-        html = html.trim();
-        if (!html.startsWith("<p>")) {
-            html = "<p>" + html + "</p>";
-        }
-        List<JSection> ss = new ArrayList<JSection>();
-        Document doc = Jsoup.parse(html);
-        Element b = doc.body();
-        for (Node e : b.childNodes()) {
-            if ("p".equals(e.nodeName()) && e.childNodeSize() > 0) {
-                JSection s = new JSection();
-                List<SectionElement> ses = new ArrayList<SectionElement>();
-                s.setElements(ses);
-                for (Node ce : e.childNodes()) {
-                    getSectionElement(ce, ses, diposeFillBlank);
-                }
-                ss.add(s);
-            }
-        }
-        return ss;
-
-    }
-    
-    private static List<JSection> getEmptySections(){
-    	List<JSection> ss = new ArrayList<JSection>();
-    	JSection s = new JSection();
-        List<SectionElement> ses = new ArrayList<SectionElement>();
-        s.setElements(ses);
-        SectionElement se=new SectionElement();
-        se.setType(ELEMENT_TYPE_TEXT);
-        se.setValue("");
-        ses.add(se);
-        ss.add(s);
-        return ss;
-    }
-
-    private static void getSectionElement(Node ce, List<SectionElement> ses, boolean diposeFillBlank) {
-        if ("span".equals(ce.nodeName()) && ce.childNodeSize() > 0) {
-            for (Node e : ce.childNodes()) {
-                getSectionElement(e, ses, diposeFillBlank);
-            }
-        } else {
-            if (ce instanceof TextNode) {
-            	SectionElement se = new SectionElement();
-                TextNode tn = (TextNode) ce;
-                se.setType(ELEMENT_TYPE_TEXT);
-                String text = tn.text();
-                if (diposeFillBlank) {
-                    text = text.replaceAll("###", "______").replaceAll("##", "______");
-                }
-                text = text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\u0000", " ");
-                se.setValue(text);
-                ses.add(se);
-            } else if (ce instanceof Element) {
-            	SectionElement se = new SectionElement();
-                if ("img".equals(ce.nodeName())) {
-                    se.setType(ELEMENT_TYPE_IMG);
-                    se.setValue(ce.attr("src"));
-//                    setImageSize(se, ce);
-                } else if ("br".equals(ce.nodeName())) {
-                    se.setType(ELEMENT_TYPE_DOCTAG);
-                    se.setValue("<w:r w:rsidRPr=\"003A4B1C\"><w:br/></w:r>");
-                } else {
-                    Element el = (Element) ce;
-                    se.setType(ELEMENT_TYPE_TEXT);
-                    se.setValue(el.text());
-                }
-                ses.add(se);
-            }
-        }
-    }
-
-}
+package cn.com.qmth.dp.examcloud.oe.modules.debug;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+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;
+import org.jsoup.nodes.Node;
+import org.jsoup.nodes.TextNode;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoTemplate;
+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.PaperDetailUnit;
+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.ExportPaperService;
+import cn.com.qmth.examcloud.core.questions.service.bean.dto.GenPaperDto;
+import cn.com.qmth.examcloud.core.questions.service.impl.GenPaperService;
+
+@Service
+public class DebugService {
+
+    public static final String QUESOPS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+    public static final String ELEMENT_TYPE_RID = "imageId";
+
+    public static final String ELEMENT_TYPE_TEXT = "text";
+
+    public static final String ELEMENT_TYPE_IMG = "image";
+
+    public static final String ELEMENT_TYPE_DOCTAG = "doctag";
+
+    @Autowired
+    GenPaperService genPaperService;
+
+    @Autowired
+    MongoTemplate mongoTemplate;
+
+    @Autowired
+    ExportPaperService exportPaperService;
+
+    public void start() {
+        exportPaper();
+    }
+
+    private void exportPaper() {
+        System.out.println("start *********************");
+        // User u = new User();
+        // u.setRootOrgId(21954L);
+        // exportPaperService.exportPaperFile("6734199244444d06f3445b8b",
+        // "PAPER", null, PaperSeqMode.MODE1, "online",
+        // null, u);
+        Query query = new Query();
+        query.addCriteria(Criteria.where("paper.$id").is(new ObjectId("6734199244444d06f3445b8b")));
+        List<PaperDetailUnit> ps = mongoTemplate.find(query, PaperDetailUnit.class, "paperDetailUnit");
+        ExportPaperUtil.disposePaperDoc(ps);
+        for (PaperDetailUnit p : ps) {
+            disposeQuestion(p.getQuestion());
+        }
+        // List<QuestionTypeCount> ret = countByType("WB7030", "17351");
+        System.out.println();
+    }
+
+    private void genPaper() {
+        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);
+        // Query query = new Query();
+        // query.addCriteria(Criteria.where("paper.$id").is(new
+        // ObjectId("64ddd05a391d2033f36b0a20")));
+        // List<PaperDetailUnit> ps = mongoTemplate.find(query,
+        // PaperDetailUnit.class, "paperDetailUnit");
+        // ExportPaperUtil.disposePaperDoc(ps);
+        // for(PaperDetailUnit p:ps) {
+        // disposeQuestion(p.getQuestion());
+        // }
+        // List<QuestionTypeCount> ret=countByType("WB7030", "17351");
+        // System.out.println();
+    }
+
+    private List<QuestionTypeCount> countByType(String courseCode, String rootOrgId) {
+        Date day = DateUtil.parse("2023-08-21 00:00:00", "yyyy-MM-dd HH:mm:ss");
+        List<AggregationOperation> operations = new ArrayList<>();
+        operations.add(Aggregation.match(Criteria.where("orgId").is(rootOrgId).and("course.code").is(courseCode)
+                .and("creationBy").is(646523L).and("creationDate").gt(day)));
+        operations.add(Aggregation.group("questionType", "difficulty").count().as("count"));
+        operations.add(Aggregation.project("count").andInclude("questionType").andInclude("difficulty"));
+        Aggregation aggregation = Aggregation.newAggregation(operations);
+        AggregationResults<QuestionTypeCount> outputTypeCount = mongoTemplate.aggregate(aggregation, Question.class,
+                QuestionTypeCount.class);
+        return outputTypeCount.getMappedResults();
+    }
+
+    private static void disposeQuestion(Question qes) {
+        if (qes != null) {
+
+            // 处理选项
+            if (qes.getQuesOptions() != null && qes.getQuesOptions().size() > 0) {
+                int index = 0;
+                for (QuesOption qo : qes.getQuesOptions()) {
+                    List<JSection> slist2 = getSections(qo.getOptionBody());
+                    if (slist2 != null && slist2.size() > 0) {
+                        SectionElement se = new SectionElement();
+                        se.setType(ELEMENT_TYPE_TEXT);
+                        se.setValue(QUESOPS.charAt(index) + ".");
+                        index++;
+                        slist2.get(0).getElements().add(0, se);
+                        // qo.setOptionBodyWord(getQuestionDoc(slist2));
+                    } else {
+                        System.out.println("******");
+                    }
+
+                }
+            }
+
+            if (qes.getSubQuestions() != null && qes.getSubQuestions().size() > 0) {
+                for (Question sunqes : qes.getSubQuestions()) {
+                    disposeQuestion(sunqes);// 递归处理套题
+                }
+            }
+        }
+    }
+
+    private static List<JSection> getSections(String html) {
+        return getSections(html, false);
+    }
+
+    private static List<JSection> getSections(String html, boolean diposeFillBlank) {
+        if (StringUtils.isBlank(html)) {
+            return getEmptySections();
+        }
+        html = html.trim();
+        if (!html.startsWith("<p>")) {
+            html = "<p>" + html + "</p>";
+        }
+        List<JSection> ss = new ArrayList<JSection>();
+        Document doc = Jsoup.parse(html);
+        Element b = doc.body();
+        for (Node e : b.childNodes()) {
+            if ("p".equals(e.nodeName()) && e.childNodeSize() > 0) {
+                JSection s = new JSection();
+                List<SectionElement> ses = new ArrayList<SectionElement>();
+                s.setElements(ses);
+                for (Node ce : e.childNodes()) {
+                    getSectionElement(ce, ses, diposeFillBlank);
+                }
+                ss.add(s);
+            }
+        }
+        return ss;
+
+    }
+
+    private static List<JSection> getEmptySections() {
+        List<JSection> ss = new ArrayList<JSection>();
+        JSection s = new JSection();
+        List<SectionElement> ses = new ArrayList<SectionElement>();
+        s.setElements(ses);
+        SectionElement se = new SectionElement();
+        se.setType(ELEMENT_TYPE_TEXT);
+        se.setValue("");
+        ses.add(se);
+        ss.add(s);
+        return ss;
+    }
+
+    private static void getSectionElement(Node ce, List<SectionElement> ses, boolean diposeFillBlank) {
+        if ("span".equals(ce.nodeName()) && ce.childNodeSize() > 0) {
+            for (Node e : ce.childNodes()) {
+                getSectionElement(e, ses, diposeFillBlank);
+            }
+        } else {
+            if (ce instanceof TextNode) {
+                SectionElement se = new SectionElement();
+                TextNode tn = (TextNode) ce;
+                se.setType(ELEMENT_TYPE_TEXT);
+                String text = tn.text();
+                if (diposeFillBlank) {
+                    text = text.replaceAll("###", "______").replaceAll("##", "______");
+                }
+                text = text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;")
+                        .replaceAll("\u0000", " ");
+                se.setValue(text);
+                ses.add(se);
+            } else if (ce instanceof Element) {
+                SectionElement se = new SectionElement();
+                if ("img".equals(ce.nodeName())) {
+                    se.setType(ELEMENT_TYPE_IMG);
+                    se.setValue(ce.attr("src"));
+                    // setImageSize(se, ce);
+                } else if ("br".equals(ce.nodeName())) {
+                    se.setType(ELEMENT_TYPE_DOCTAG);
+                    se.setValue("<w:r w:rsidRPr=\"003A4B1C\"><w:br/></w:r>");
+                } else {
+                    Element el = (Element) ce;
+                    se.setType(ELEMENT_TYPE_TEXT);
+                    se.setValue(el.text());
+                }
+                ses.add(se);
+            }
+        }
+    }
+
+}

+ 345 - 343
src/main/java/cn/com/qmth/dp/examcloud/oe/modules/debug/ExportPaperUtil.java

@@ -1,343 +1,345 @@
-package cn.com.qmth.dp.examcloud.oe.modules.debug;
-
-import java.awt.image.BufferedImage;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.imageio.ImageIO;
-
-import org.apache.commons.lang3.StringUtils;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.nodes.Node;
-import org.jsoup.nodes.TextNode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import cn.com.qmth.dp.examcloud.oe.entity.question.PaperDetailUnit;
-import cn.com.qmth.dp.examcloud.oe.entity.question.QuesOption;
-import cn.com.qmth.dp.examcloud.oe.entity.question.Question;
-import cn.com.qmth.examcloud.commons.exception.StatusException;
-import sun.misc.BASE64Decoder;
-
-public class ExportPaperUtil {
-	private static final Logger log = LoggerFactory.getLogger(ExportPaperUtil.class);
-	private static final int docImageSzie = 12700;
-
-	private static final String DOCX_SUFFIX = ".docx";
-
-	private static final String ZIP_SUFFIX = ".zip";
-
-	public static final String QUESOPS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
-	public static final String ELEMENT_TYPE_RID = "imageId";
-
-	public static final String ELEMENT_TYPE_TEXT = "text";
-
-	public static final String ELEMENT_TYPE_IMG = "image";
-
-	public static final String ELEMENT_TYPE_DOCTAG = "doctag";
-
-	private static final String ENCODING = "UTF-8";
-
-	private static Pattern heightRex = Pattern.compile("height:([\\s\\S]*?)px");
-
-	private static Pattern widthRex = Pattern.compile("width:([\\s\\S]*?)px");
-
-	public static void disposePaperDoc(List<PaperDetailUnit> ps){
-		ExportTempDataDto dto = new ExportTempDataDto();
-		for (PaperDetailUnit pdue : ps) {
-			Question qes = pdue.getQuestion();
-			disposePaperQuestion(qes, dto);
-		}
-
-	}
-
-	private static void disposePaperQuestion(Question qes, ExportTempDataDto dto) {
-		if (qes != null) {
-			// 处理题干
-			List<JSection> slist1 = getSections(qes.getQuesBody(), true);
-			if (slist1 == null || slist1.size() == 0) {
-				slist1 = new ArrayList<JSection>();
-				JSection sec = new JSection();
-				List<SectionElement> ses = new ArrayList<SectionElement>();
-				sec.setElements(ses);
-				slist1.add(sec);
-			}
-			if (qes.getSubQuestions() == null || qes.getSubQuestions().size() == 0) {// 套题题干不加题号
-				SectionElement se = new SectionElement();
-				se.setType(ELEMENT_TYPE_TEXT);
-//                se.setValue(qes.getQuestionSeq() + ".");
-				slist1.get(0).getElements().add(0, se);
-			}
-
-			htmlToDoc(slist1, dto);
-//            qes.setQuesBodyWord(getQuestionDoc(slist1));
-
-			// 处理选项
-			if (qes.getQuesOptions() != null && qes.getQuesOptions().size() > 0) {
-				int index = 0;
-				JOptionDto joDto = new JOptionDto();
-				List<JOption> ops = new ArrayList<JOption>();
-				joDto.setOptions(ops);
-				for (QuesOption qo : qes.getQuesOptions()) {
-					List<JSection> slist2 = getSections(qo.getOptionBody());
-					if (slist2 != null && slist2.size() > 0) {
-						SectionElement se = new SectionElement();
-						se.setType(ELEMENT_TYPE_TEXT);
-						se.setValue(QUESOPS.charAt(index) + ".");
-						index++;
-						slist2.get(0).getElements().add(0, se);
-						htmlToDoc(slist2, dto);
-						JOption jo = new JOption();
-						jo.setJsections(slist2);
-						ops.add(jo);
-					}
-				}
-//                disposeQuesOptions(joDto);// 处理选项列数
-//                qes.setQuesOptionsWord(getPaperQuestionDoc(joDto.getOptions()));
-			}
-
-			// 处理答案
-			if (qes.getSubQuestions() == null || qes.getSubQuestions().size() == 0) {// 套题不加答案及序号
-				List<JSection> slist3 = getSections(qes.getQuesAnswer());
-				if (slist3 == null || slist3.size() == 0) {
-					slist3 = new ArrayList<JSection>();
-					JSection sec = new JSection();
-					List<SectionElement> ses = new ArrayList<SectionElement>();
-					sec.setElements(ses);
-					slist3.add(sec);
-				}
-				SectionElement se = new SectionElement();
-				se.setType(ELEMENT_TYPE_TEXT);
-//                se.setValue(qes.getQuestionSeq() + ".");
-				slist3.get(0).getElements().add(0, se);
-
-				htmlToDoc(slist3, dto);
-//                qes.setQuesAnswerWord(getQuestionDoc(slist3));
-			}
-
-			if (qes.getSubQuestions() != null && qes.getSubQuestions().size() > 0) {
-				for (Question sunqes : qes.getSubQuestions()) {
-					disposePaperQuestion(sunqes, dto);// 递归处理套题
-				}
-			}
-		}
-	}
-
-	private static void htmlToDoc(List<JSection> slist, ExportTempDataDto dto) {
-		for (JSection js : slist) {
-			for (SectionElement se : js.getElements()) {
-				if (ELEMENT_TYPE_IMG.equals(se.getType())) {
-					dto.setIndex(dto.getIndex() + 1);
-					se.getParam().setIndex(dto.getIndex());
-					se.getParam().setRid(ELEMENT_TYPE_RID + dto.getIndex());
-					se.getParam().setType(getImageType(se.getValue()));
-					dto.getTypes().add(se.getParam().getType());
-					dto.getImages().add(se);
-				}
-			}
-		}
-	}
-
-	private static String getImageType(String src) {
-		if (src.contains("data:image")) {
-			return src.substring(11, src.indexOf(";"));
-		} else {
-			try {
-				URL url = new URL(src);
-				return url.getPath().substring(url.getPath().lastIndexOf(".") + 1);
-			} catch (MalformedURLException e) {
-				throw new StatusException("1000", "图片链接格式错误:" + src);
-			}
-		}
-	}
-
-	private static List<JSection> getSections(String html) {
-		return getSections(html, false);
-	}
-
-	private static List<JSection> getSections(String html, boolean diposeFillBlank) {
-		if (StringUtils.isBlank(html)) {
-			return getEmptySections();
-		}
-		html = html.trim();
-		if (!html.startsWith("<p>")) {
-			html = "<p>" + html + "</p>";
-		}
-		List<JSection> ss = new ArrayList<JSection>();
-		Document doc = Jsoup.parse(html);
-		Element b = doc.body();
-		for (Node e : b.childNodes()) {
-			if ("p".equals(e.nodeName()) && e.childNodeSize() > 0) {
-				JSection s = new JSection();
-				List<SectionElement> ses = new ArrayList<SectionElement>();
-				s.setElements(ses);
-				for (Node ce : e.childNodes()) {
-					getSectionElement(ce, ses, diposeFillBlank);
-				}
-				ss.add(s);
-			}
-		}
-		return ss;
-
-	}
-
-	private static List<JSection> getEmptySections() {
-		List<JSection> ss = new ArrayList<JSection>();
-		JSection s = new JSection();
-		List<SectionElement> ses = new ArrayList<SectionElement>();
-		s.setElements(ses);
-		SectionElement se = new SectionElement();
-		se.setType(ELEMENT_TYPE_TEXT);
-		se.setValue("");
-		ses.add(se);
-		ss.add(s);
-		return ss;
-	}
-
-	private static void getSectionElement(Node ce, List<SectionElement> ses, boolean diposeFillBlank) {
-		if ("span".equals(ce.nodeName()) && ce.childNodeSize() > 0) {
-			for (Node e : ce.childNodes()) {
-				getSectionElement(e, ses, diposeFillBlank);
-			}
-		} else {
-			if (ce instanceof TextNode) {
-				SectionElement se = new SectionElement();
-				TextNode tn = (TextNode) ce;
-				se.setType(ELEMENT_TYPE_TEXT);
-				String text = tn.text();
-				if (diposeFillBlank) {
-					text = text.replaceAll("###", "______").replaceAll("##", "______");
-				}
-				text = text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;")
-						.replaceAll("\u0000", " ");
-				se.setValue(text);
-				ses.add(se);
-			} else if (ce instanceof Element) {
-				SectionElement se = new SectionElement();
-				if ("img".equals(ce.nodeName())) {
-					se.setType(ELEMENT_TYPE_IMG);
-					se.setValue(ce.attr("src"));
-					setImageSize(se, ce);
-				} else if ("br".equals(ce.nodeName())) {
-					se.setType(ELEMENT_TYPE_DOCTAG);
-					se.setValue("<w:r w:rsidRPr=\"003A4B1C\"><w:br/></w:r>");
-				} else {
-					Element el = (Element) ce;
-					se.setType(ELEMENT_TYPE_TEXT);
-					se.setValue(el.text());
-				}
-				ses.add(se);
-			}
-		}
-	}
-
-	private static void setImageSize(SectionElement imageEle, Node ce) {
-		int width = getWidth(ce);
-		int height = getHeight(ce);
-		if (width < 100 || height < 100) {
-			String base64 = imageEle.getValue();
-			if (base64.contains("data:image")) {
-				base64 = base64.substring(base64.indexOf(",") + 1);
-			}
-			BASE64Decoder decoder = new BASE64Decoder();
-
-			InputStream is = null;
-			try {
-				byte[] bytes = decoder.decodeBuffer(base64);
-				is = new ByteArrayInputStream(bytes);
-				BufferedImage image = ImageIO.read(is);
-				width = image.getWidth() * docImageSzie;
-				height = image.getHeight() * docImageSzie;
-			} catch (IOException e) {
-				log.error(e.getMessage(), e);
-			} finally {
-				if (is != null) {
-					try {
-						is.close();
-					} catch (IOException e) {
-						log.error(e.getMessage(), e);
-					}
-				}
-			}
-		}
-		imageEle.getParam().setHeight(height);
-		imageEle.getParam().setWidth(width);
-
-	}
-
-	private static int getWidth(Node ce) {
-		int n = 0;
-		String str = ce.attr("width");
-		if (StringUtils.isNotBlank(str)) {
-			String sizeStr = str.replace("px", "");
-			if (StringUtils.isNotBlank(sizeStr)) {
-				try {
-					return Integer.valueOf(sizeStr.trim()) * docImageSzie;
-				} catch (NumberFormatException e) {
-					log.warn("image width value is invalid");
-					return 0;
-				}
-			}
-		}
-		String style = ce.attr("style");
-		if (StringUtils.isNotBlank(style)) {
-			Matcher m = widthRex.matcher(style);
-			if (m.find()) {
-				String size = m.group(1).trim();
-				if (StringUtils.isNotBlank(size)) {
-					try {
-						return Integer.valueOf(size) * docImageSzie;
-					} catch (NumberFormatException e) {
-						log.warn("image style width value is invalid");
-						return 0;
-					}
-				}
-			}
-		}
-		return n;
-	}
-
-	private static int getHeight(Node ce) {
-		int n = 0;
-		String str = ce.attr("height");
-		if (StringUtils.isNotBlank(str)) {
-			String sizeStr = str.replace("px", "");
-			if (StringUtils.isNotBlank(sizeStr)) {
-				try {
-					return Integer.valueOf(sizeStr.trim()) * docImageSzie;
-				} catch (NumberFormatException e) {
-					log.error("image height value is invalid");
-					return 0;
-				}
-			}
-		}
-		String style = ce.attr("style");
-		if (StringUtils.isNotBlank(style)) {
-			Matcher m = heightRex.matcher(style);
-			if (m.find()) {
-				String size = m.group(1).trim();
-				if (StringUtils.isNotBlank(size)) {
-					try {
-						return Integer.valueOf(size) * docImageSzie;
-					} catch (NumberFormatException e) {
-						log.error("image style height value is invalid");
-						return 0;
-					}
-				}
-			}
-		}
-		return n;
-	}
-
-}
+package cn.com.qmth.dp.examcloud.oe.modules.debug;
+
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.imageio.ImageIO;
+
+import org.apache.commons.lang3.StringUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.nodes.Node;
+import org.jsoup.nodes.TextNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cn.com.qmth.dp.examcloud.oe.entity.question.PaperDetailUnit;
+import cn.com.qmth.dp.examcloud.oe.entity.question.QuesOption;
+import cn.com.qmth.dp.examcloud.oe.entity.question.Question;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import sun.misc.BASE64Decoder;
+
+public class ExportPaperUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(ExportPaperUtil.class);
+
+    private static final int docImageSzie = 12700;
+
+    private static final String DOCX_SUFFIX = ".docx";
+
+    private static final String ZIP_SUFFIX = ".zip";
+
+    public static final String QUESOPS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+    public static final String ELEMENT_TYPE_RID = "imageId";
+
+    public static final String ELEMENT_TYPE_TEXT = "text";
+
+    public static final String ELEMENT_TYPE_IMG = "image";
+
+    public static final String ELEMENT_TYPE_DOCTAG = "doctag";
+
+    private static final String ENCODING = "UTF-8";
+
+    private static Pattern heightRex = Pattern.compile("height:([\\s\\S]*?)px");
+
+    private static Pattern widthRex = Pattern.compile("width:([\\s\\S]*?)px");
+
+    public static void disposePaperDoc(List<PaperDetailUnit> ps) {
+        ExportTempDataDto dto = new ExportTempDataDto();
+        for (PaperDetailUnit pdue : ps) {
+            Question qes = pdue.getQuestion();
+            disposePaperQuestion(qes, dto);
+        }
+
+    }
+
+    private static void disposePaperQuestion(Question qes, ExportTempDataDto dto) {
+        if (qes != null) {
+            // 处理题干
+            List<JSection> slist1 = getSections(qes.getQuesBody(), true);
+            if (slist1 == null || slist1.size() == 0) {
+                slist1 = new ArrayList<JSection>();
+                JSection sec = new JSection();
+                List<SectionElement> ses = new ArrayList<SectionElement>();
+                sec.setElements(ses);
+                slist1.add(sec);
+            }
+            if (qes.getSubQuestions() == null || qes.getSubQuestions().size() == 0) {// 套题题干不加题号
+                SectionElement se = new SectionElement();
+                se.setType(ELEMENT_TYPE_TEXT);
+                // se.setValue(qes.getQuestionSeq() + ".");
+                slist1.get(0).getElements().add(0, se);
+            }
+
+            htmlToDoc(slist1, dto);
+            // qes.setQuesBodyWord(getQuestionDoc(slist1));
+
+            // 处理选项
+            if (qes.getQuesOptions() != null && qes.getQuesOptions().size() > 0) {
+                int index = 0;
+                JOptionDto joDto = new JOptionDto();
+                List<JOption> ops = new ArrayList<JOption>();
+                joDto.setOptions(ops);
+                for (QuesOption qo : qes.getQuesOptions()) {
+                    List<JSection> slist2 = getSections(qo.getOptionBody());
+                    if (slist2 != null && slist2.size() > 0) {
+                        SectionElement se = new SectionElement();
+                        se.setType(ELEMENT_TYPE_TEXT);
+                        se.setValue(QUESOPS.charAt(index) + ".");
+                        index++;
+                        slist2.get(0).getElements().add(0, se);
+                        htmlToDoc(slist2, dto);
+                        JOption jo = new JOption();
+                        jo.setJsections(slist2);
+                        ops.add(jo);
+                    }
+                }
+                // disposeQuesOptions(joDto);// 处理选项列数
+                // qes.setQuesOptionsWord(getPaperQuestionDoc(joDto.getOptions()));
+            }
+
+            // 处理答案
+            if (qes.getSubQuestions() == null || qes.getSubQuestions().size() == 0) {// 套题不加答案及序号
+                List<JSection> slist3 = getSections(qes.getQuesAnswer());
+                if (slist3 == null || slist3.size() == 0) {
+                    slist3 = new ArrayList<JSection>();
+                    JSection sec = new JSection();
+                    List<SectionElement> ses = new ArrayList<SectionElement>();
+                    sec.setElements(ses);
+                    slist3.add(sec);
+                }
+                SectionElement se = new SectionElement();
+                se.setType(ELEMENT_TYPE_TEXT);
+                // se.setValue(qes.getQuestionSeq() + ".");
+                slist3.get(0).getElements().add(0, se);
+
+                htmlToDoc(slist3, dto);
+                // qes.setQuesAnswerWord(getQuestionDoc(slist3));
+            }
+
+            if (qes.getSubQuestions() != null && qes.getSubQuestions().size() > 0) {
+                for (Question sunqes : qes.getSubQuestions()) {
+                    disposePaperQuestion(sunqes, dto);// 递归处理套题
+                }
+            }
+        }
+    }
+
+    private static void htmlToDoc(List<JSection> slist, ExportTempDataDto dto) {
+        for (JSection js : slist) {
+            for (SectionElement se : js.getElements()) {
+                if (ELEMENT_TYPE_IMG.equals(se.getType())) {
+                    dto.setIndex(dto.getIndex() + 1);
+                    se.getParam().setIndex(dto.getIndex());
+                    se.getParam().setRid(ELEMENT_TYPE_RID + dto.getIndex());
+                    se.getParam().setType(getImageType(se.getValue()));
+                    dto.getTypes().add(se.getParam().getType());
+                    dto.getImages().add(se);
+                }
+            }
+        }
+    }
+
+    private static String getImageType(String src) {
+        if (src.contains("data:image")) {
+            return src.substring(11, src.indexOf(";"));
+        } else {
+            try {
+                URL url = new URL(src);
+                return url.getPath().substring(url.getPath().lastIndexOf(".") + 1);
+            } catch (MalformedURLException e) {
+                throw new StatusException("1000", "图片链接格式错误:" + src);
+            }
+        }
+    }
+
+    private static List<JSection> getSections(String html) {
+        return getSections(html, false);
+    }
+
+    private static List<JSection> getSections(String html, boolean diposeFillBlank) {
+        if (StringUtils.isBlank(html)) {
+            return getEmptySections();
+        }
+        html = html.trim();
+        if (!html.startsWith("<p>")) {
+            html = "<p>" + html + "</p>";
+        }
+        List<JSection> ss = new ArrayList<JSection>();
+        Document doc = Jsoup.parse(html);
+        Element b = doc.body();
+        for (Node e : b.childNodes()) {
+            if ("p".equals(e.nodeName()) && e.childNodeSize() > 0) {
+                JSection s = new JSection();
+                List<SectionElement> ses = new ArrayList<SectionElement>();
+                s.setElements(ses);
+                for (Node ce : e.childNodes()) {
+                    getSectionElement(ce, ses, diposeFillBlank);
+                }
+                ss.add(s);
+            }
+        }
+        return ss;
+
+    }
+
+    private static List<JSection> getEmptySections() {
+        List<JSection> ss = new ArrayList<JSection>();
+        JSection s = new JSection();
+        List<SectionElement> ses = new ArrayList<SectionElement>();
+        s.setElements(ses);
+        SectionElement se = new SectionElement();
+        se.setType(ELEMENT_TYPE_TEXT);
+        se.setValue("");
+        ses.add(se);
+        ss.add(s);
+        return ss;
+    }
+
+    private static void getSectionElement(Node ce, List<SectionElement> ses, boolean diposeFillBlank) {
+        if ("span".equals(ce.nodeName()) && ce.childNodeSize() > 0) {
+            for (Node e : ce.childNodes()) {
+                getSectionElement(e, ses, diposeFillBlank);
+            }
+        } else {
+            if (ce instanceof TextNode) {
+                SectionElement se = new SectionElement();
+                TextNode tn = (TextNode) ce;
+                se.setType(ELEMENT_TYPE_TEXT);
+                String text = tn.text();
+                if (diposeFillBlank) {
+                    text = text.replaceAll("###", "______").replaceAll("##", "______");
+                }
+                text = text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;")
+                        .replaceAll("\u0000", " ");
+                se.setValue(text);
+                ses.add(se);
+            } else if (ce instanceof Element) {
+                SectionElement se = new SectionElement();
+                if ("img".equals(ce.nodeName())) {
+                    se.setType(ELEMENT_TYPE_IMG);
+                    se.setValue(ce.attr("src"));
+                    setImageSize(se, ce);
+                } else if ("br".equals(ce.nodeName())) {
+                    se.setType(ELEMENT_TYPE_DOCTAG);
+                    se.setValue("<w:r w:rsidRPr=\"003A4B1C\"><w:br/></w:r>");
+                } else {
+                    Element el = (Element) ce;
+                    se.setType(ELEMENT_TYPE_TEXT);
+                    se.setValue(el.text());
+                }
+                ses.add(se);
+            }
+        }
+    }
+
+    private static void setImageSize(SectionElement imageEle, Node ce) {
+        int width = getWidth(ce);
+        int height = getHeight(ce);
+        if (width < 100 || height < 100) {
+            String base64 = imageEle.getValue();
+            if (base64.contains("data:image")) {
+                base64 = base64.substring(base64.indexOf(",") + 1);
+            }
+            BASE64Decoder decoder = new BASE64Decoder();
+
+            InputStream is = null;
+            try {
+                byte[] bytes = decoder.decodeBuffer(base64);
+                is = new ByteArrayInputStream(bytes);
+                BufferedImage image = ImageIO.read(is);
+                width = image.getWidth() * docImageSzie;
+                height = image.getHeight() * docImageSzie;
+            } catch (Exception e) {
+                log.error(e.getMessage(), e);
+            } finally {
+                if (is != null) {
+                    try {
+                        is.close();
+                    } catch (IOException e) {
+                        log.error(e.getMessage(), e);
+                    }
+                }
+            }
+        }
+        imageEle.getParam().setHeight(height);
+        imageEle.getParam().setWidth(width);
+
+    }
+
+    private static int getWidth(Node ce) {
+        int n = 0;
+        String str = ce.attr("width");
+        if (StringUtils.isNotBlank(str)) {
+            String sizeStr = str.replace("px", "");
+            if (StringUtils.isNotBlank(sizeStr)) {
+                try {
+                    return Integer.valueOf(sizeStr.trim()) * docImageSzie;
+                } catch (NumberFormatException e) {
+                    log.warn("image width value is invalid");
+                    return 0;
+                }
+            }
+        }
+        String style = ce.attr("style");
+        if (StringUtils.isNotBlank(style)) {
+            Matcher m = widthRex.matcher(style);
+            if (m.find()) {
+                String size = m.group(1).trim();
+                if (StringUtils.isNotBlank(size)) {
+                    try {
+                        return Integer.valueOf(size) * docImageSzie;
+                    } catch (NumberFormatException e) {
+                        log.warn("image style width value is invalid");
+                        return 0;
+                    }
+                }
+            }
+        }
+        return n;
+    }
+
+    private static int getHeight(Node ce) {
+        int n = 0;
+        String str = ce.attr("height");
+        if (StringUtils.isNotBlank(str)) {
+            String sizeStr = str.replace("px", "");
+            if (StringUtils.isNotBlank(sizeStr)) {
+                try {
+                    return Integer.valueOf(sizeStr.trim()) * docImageSzie;
+                } catch (NumberFormatException e) {
+                    log.error("image height value is invalid");
+                    return 0;
+                }
+            }
+        }
+        String style = ce.attr("style");
+        if (StringUtils.isNotBlank(style)) {
+            Matcher m = heightRex.matcher(style);
+            if (m.find()) {
+                String size = m.group(1).trim();
+                if (StringUtils.isNotBlank(size)) {
+                    try {
+                        return Integer.valueOf(size) * docImageSzie;
+                    } catch (NumberFormatException e) {
+                        log.error("image style height value is invalid");
+                        return 0;
+                    }
+                }
+            }
+        }
+        return n;
+    }
+
+}

+ 135 - 134
src/main/java/cn/com/qmth/dp/examcloud/oe/modules/export_course_questions_count/ExportQuesConsumer.java

@@ -1,134 +1,135 @@
-package cn.com.qmth.dp.examcloud.oe.modules.export_course_questions_count;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import org.apache.commons.collections4.CollectionUtils;
-import org.bson.types.ObjectId;
-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.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.Course;
-import cn.com.qmth.dp.examcloud.oe.entity.question.Question;
-import cn.com.qmth.dp.examcloud.oe.enums.question.QuesStructType;
-import cn.com.qmth.dp.examcloud.oe.multithread.Consumer;
-import cn.com.qmth.examcloud.commons.util.DateUtil;
-
-@Service
-@Scope("prototype")
-public class ExportQuesConsumer extends Consumer<Course> {
-
-    @Autowired
-    private MongoTemplate mongoTemplate;
-
-    @Override
-    public void consume(Map<String, Object> param, Course c) {
-        CourseQuestionsCountRetDto rd = new CourseQuestionsCountRetDto();
-        String rootOrgId = (String) param.get("rootOrgId");
-        rd.setCourseCode(c.getCode());
-        rd.setCourseName(c.getName());
-        List<QuestionTypeCount> tc = countByType(c.getCode(), rootOrgId);
-        if (CollectionUtils.isNotEmpty(tc)) {
-            setCount(rd, tc);
-            // setExtCount(rd, rootOrgId);
-        }
-        if (rd.getSingleAnswerQuestion() != 0 || rd.getMultipleAnswerQuestion() != 0 || rd.getBoolAnswerQuestion() != 0
-                || rd.getFillBlankQuestion() != 0 || rd.getTextAnswerQuestion() != 0
-                || rd.getNestedAnswerQuestion() != 0 || rd.getExt() != 0) {
-            addRet(rd);
-        }
-
-    }
-
-    private List<ObjectId> getPaperIds(String courseCode, String rootOrgId) {
-        Query query = new Query();
-        query.addCriteria(
-                Criteria.where("orgId").is(rootOrgId).and("paperType").is("IMPORT").and("course.code").is(courseCode));
-        List<IdBean> ps = mongoTemplate.find(query, IdBean.class, "paper");
-        if (CollectionUtils.isEmpty(ps)) {
-            return null;
-        }
-        List<ObjectId> ids = ps.stream().map(p -> new ObjectId(p.getId())).collect(Collectors.toList());
-        return ids;
-    }
-
-    private List<ObjectId> getDetailIds(List<ObjectId> ps) {
-        Query query = new Query();
-        query.addCriteria(Criteria.where("paper.$id").in(ps));
-        List<Detail> ds = mongoTemplate.find(query, Detail.class, "paperDetail");
-        if (CollectionUtils.isEmpty(ps)) {
-            return null;
-        }
-        List<ObjectId> ids = new ArrayList<>();
-        // for(Detail d:ds) {
-        // if(d.getName().contains("案例分析")) {
-        // ids.add(new ObjectId(d.getId()));
-        // }
-        // }
-        return ids;
-    }
-
-    private long getExtCount(List<ObjectId> ds) {
-        Query query = new Query();
-        query.addCriteria(Criteria.where("paperDetail.$id").in(ds).and("questionType")
-                .is(QuesStructType.TEXT_ANSWER_QUESTION.name()));
-        long count = mongoTemplate.count(query, "paperDetailUnit");
-        return count;
-    }
-
-    private void setExtCount(CourseQuestionsCountRetDto rd, String rootOrgId) {
-        List<ObjectId> paperIds = getPaperIds(rd.getCourseCode(), rootOrgId);
-        if (CollectionUtils.isEmpty(paperIds)) {
-            return;
-        }
-
-        List<ObjectId> detailIds = getDetailIds(paperIds);
-        if (CollectionUtils.isEmpty(detailIds)) {
-            return;
-        }
-        rd.setExt(getExtCount(detailIds));
-    }
-
-    private void setCount(CourseQuestionsCountRetDto rd, List<QuestionTypeCount> tc) {
-        for (QuestionTypeCount t : tc) {
-            if (t.getQuestionType().equals(QuesStructType.SINGLE_ANSWER_QUESTION.name())) {
-                rd.setSingleAnswerQuestion(t.getCount());
-            } else if (t.getQuestionType().equals(QuesStructType.MULTIPLE_ANSWER_QUESTION.name())) {
-                rd.setMultipleAnswerQuestion(t.getCount());
-            } else if (t.getQuestionType().equals(QuesStructType.BOOL_ANSWER_QUESTION.name())) {
-                rd.setBoolAnswerQuestion(t.getCount());
-            } else if (t.getQuestionType().equals(QuesStructType.FILL_BLANK_QUESTION.name())) {
-                rd.setFillBlankQuestion(t.getCount());
-            } else if (t.getQuestionType().equals(QuesStructType.TEXT_ANSWER_QUESTION.name())) {
-                rd.setTextAnswerQuestion(t.getCount());
-            } else if (t.getQuestionType().equals(QuesStructType.NESTED_ANSWER_QUESTION.name())) {
-                rd.setNestedAnswerQuestion(t.getCount());
-            }
-        }
-    }
-
-    private List<QuestionTypeCount> countByType(String courseCode, String rootOrgId) {
-        List<AggregationOperation> operations = new ArrayList<>();
-        Date day = DateUtil.parse("2023-05-18 00:00:00", "yyyy-MM-dd HH:mm:ss");
-        operations.add(Aggregation.match(Criteria.where("orgId").is(rootOrgId).and("course.code").is(courseCode)
-                .and("creationBy").is(646523L).and("creationDate").gt(day)));
-        // operations.add(Aggregation.match(Criteria.where("orgId").is(rootOrgId).and("course.code").is(courseCode)));
-        operations.add(Aggregation.group("questionType").count().as("count"));
-        operations.add(Aggregation.project("count").and("questionType").previousOperation());
-        Aggregation aggregation = Aggregation.newAggregation(operations);
-        AggregationResults<QuestionTypeCount> outputTypeCount = mongoTemplate.aggregate(aggregation, Question.class,
-                QuestionTypeCount.class);
-        return outputTypeCount.getMappedResults();
-    }
-
-}
+package cn.com.qmth.dp.examcloud.oe.modules.export_course_questions_count;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.bson.types.ObjectId;
+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.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.Course;
+import cn.com.qmth.dp.examcloud.oe.entity.question.Question;
+import cn.com.qmth.dp.examcloud.oe.enums.question.QuesStructType;
+import cn.com.qmth.dp.examcloud.oe.multithread.Consumer;
+import cn.com.qmth.examcloud.commons.util.DateUtil;
+
+@Service
+@Scope("prototype")
+public class ExportQuesConsumer extends Consumer<Course> {
+
+    @Autowired
+    private MongoTemplate mongoTemplate;
+
+    @Override
+    public void consume(Map<String, Object> param, Course c) {
+        CourseQuestionsCountRetDto rd = new CourseQuestionsCountRetDto();
+        String rootOrgId = (String) param.get("rootOrgId");
+        rd.setCourseCode(c.getCode());
+        rd.setCourseName(c.getName());
+        List<QuestionTypeCount> tc = countByType(c.getCode(), rootOrgId);
+        if (CollectionUtils.isNotEmpty(tc)) {
+            setCount(rd, tc);
+            // setExtCount(rd, rootOrgId);
+        }
+        if (rd.getSingleAnswerQuestion() != 0 || rd.getMultipleAnswerQuestion() != 0 || rd.getBoolAnswerQuestion() != 0
+                || rd.getFillBlankQuestion() != 0 || rd.getTextAnswerQuestion() != 0
+                || rd.getNestedAnswerQuestion() != 0 || rd.getExt() != 0) {
+            addRet(rd);
+        }
+
+    }
+
+    private List<ObjectId> getPaperIds(String courseCode, String rootOrgId) {
+        Query query = new Query();
+        query.addCriteria(
+                Criteria.where("orgId").is(rootOrgId).and("paperType").is("IMPORT").and("course.code").is(courseCode));
+        List<IdBean> ps = mongoTemplate.find(query, IdBean.class, "paper");
+        if (CollectionUtils.isEmpty(ps)) {
+            return null;
+        }
+        List<ObjectId> ids = ps.stream().map(p -> new ObjectId(p.getId())).collect(Collectors.toList());
+        return ids;
+    }
+
+    private List<ObjectId> getDetailIds(List<ObjectId> ps) {
+        Query query = new Query();
+        query.addCriteria(Criteria.where("paper.$id").in(ps));
+        List<Detail> ds = mongoTemplate.find(query, Detail.class, "paperDetail");
+        if (CollectionUtils.isEmpty(ps)) {
+            return null;
+        }
+        List<ObjectId> ids = new ArrayList<>();
+        // for(Detail d:ds) {
+        // if(d.getName().contains("案例分析")) {
+        // ids.add(new ObjectId(d.getId()));
+        // }
+        // }
+        return ids;
+    }
+
+    private long getExtCount(List<ObjectId> ds) {
+        Query query = new Query();
+        query.addCriteria(Criteria.where("paperDetail.$id").in(ds).and("questionType")
+                .is(QuesStructType.TEXT_ANSWER_QUESTION.name()));
+        long count = mongoTemplate.count(query, "paperDetailUnit");
+        return count;
+    }
+
+    private void setExtCount(CourseQuestionsCountRetDto rd, String rootOrgId) {
+        List<ObjectId> paperIds = getPaperIds(rd.getCourseCode(), rootOrgId);
+        if (CollectionUtils.isEmpty(paperIds)) {
+            return;
+        }
+
+        List<ObjectId> detailIds = getDetailIds(paperIds);
+        if (CollectionUtils.isEmpty(detailIds)) {
+            return;
+        }
+        rd.setExt(getExtCount(detailIds));
+    }
+
+    private void setCount(CourseQuestionsCountRetDto rd, List<QuestionTypeCount> tc) {
+        for (QuestionTypeCount t : tc) {
+            if (t.getQuestionType().equals(QuesStructType.SINGLE_ANSWER_QUESTION.name())) {
+                rd.setSingleAnswerQuestion(t.getCount());
+            } else if (t.getQuestionType().equals(QuesStructType.MULTIPLE_ANSWER_QUESTION.name())) {
+                rd.setMultipleAnswerQuestion(t.getCount());
+            } else if (t.getQuestionType().equals(QuesStructType.BOOL_ANSWER_QUESTION.name())) {
+                rd.setBoolAnswerQuestion(t.getCount());
+            } else if (t.getQuestionType().equals(QuesStructType.FILL_BLANK_QUESTION.name())) {
+                rd.setFillBlankQuestion(t.getCount());
+            } else if (t.getQuestionType().equals(QuesStructType.TEXT_ANSWER_QUESTION.name())) {
+                rd.setTextAnswerQuestion(t.getCount());
+            } else if (t.getQuestionType().equals(QuesStructType.NESTED_ANSWER_QUESTION.name())) {
+                rd.setNestedAnswerQuestion(t.getCount());
+            }
+        }
+    }
+
+    private List<QuestionTypeCount> countByType(String courseCode, String rootOrgId) {
+        List<AggregationOperation> operations = new ArrayList<>();
+        // Date day = DateUtil.parse("2023-05-18 00:00:00", "yyyy-MM-dd
+        // HH:mm:ss");
+        operations.add(Aggregation.match(Criteria.where("orgId").is(rootOrgId).and("course.code").is(courseCode)));
+        // .and("creationBy").is(646523L).and("creationDate").gt(day)));
+        // operations.add(Aggregation.match(Criteria.where("orgId").is(rootOrgId).and("course.code").is(courseCode)));
+        operations.add(Aggregation.group("questionType").count().as("count"));
+        operations.add(Aggregation.project("count").and("questionType").previousOperation());
+        Aggregation aggregation = Aggregation.newAggregation(operations);
+        AggregationResults<QuestionTypeCount> outputTypeCount = mongoTemplate.aggregate(aggregation, Question.class,
+                QuestionTypeCount.class);
+        return outputTypeCount.getMappedResults();
+    }
+
+}

+ 113 - 122
src/main/java/cn/com/qmth/dp/examcloud/oe/modules/export_course_questions_count/ExportQuestionsCountBySuffService.java

@@ -1,122 +1,113 @@
-package cn.com.qmth.dp.examcloud.oe.modules.export_course_questions_count;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-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.stereotype.Service;
-
-import cn.com.qmth.dp.examcloud.oe.entity.question.Question;
-import cn.com.qmth.dp.examcloud.oe.excel.ExportUtils;
-import cn.com.qmth.dp.examcloud.oe.multithread.Consumer;
-import cn.com.qmth.examcloud.web.support.SpringContextHolder;
-
-/**
- * 按试卷后缀名导出小题各题型数.多线程处理
- * 
- * @author chenken
- *
- */
-@Service
-public class ExportQuestionsCountBySuffService {
-
-    private String rootOrgId = "17351";
-
-    private String[] paperSuffs = new String[] { "231205" };
-
-    private int threadCount = 20;
-
-    private int fileIndex = 0;
-
-    @Autowired
-    private MongoTemplate mongoTemplate;
-
-    public void start() {
-        Date s = new Date();
-        for (String paperSuff : paperSuffs) {
-            oneBatch(paperSuff);
-        }
-        System.out.println("finish all! ");
-        Date e = new Date();
-        System.out.println("time:" + (e.getTime() - s.getTime()));
-    }
-
-    public void oneBatch(String suff) {
-        Date s = new Date();
-        ExportQuesBySuffProducer pr = SpringContextHolder.getBean(ExportQuesBySuffProducer.class);
-        try {
-            Map<String, Object> param = new HashMap<>();
-            param.put("rootOrgId", rootOrgId);
-            param.put("paperSuff", suff);
-            pr.startDispose(ExportQuesBySuffConsumer.class, threadCount, param);
-            List<CourseQuestionsCountRetDto> ret = new ArrayList<CourseQuestionsCountRetDto>();
-            for (Consumer c : pr.getConsumers()) {
-                ret.addAll(c.getRet());
-            }
-            Collections.sort(ret, new Comparator<CourseQuestionsCountRetDto>() {
-
-                @Override
-                public int compare(CourseQuestionsCountRetDto o1, CourseQuestionsCountRetDto o2) {
-                    String c1 = o1.getCourseCode();
-                    String c2 = o2.getCourseCode();
-                    return c1.compareTo(c2);
-                }
-
-            });
-            FileOutputStream fos = null;
-            File file = createFile(suff);
-            try {
-                file.createNewFile();
-                fos = new FileOutputStream(file);
-                ExportUtils.makeExcel(CourseQuestionsCountRetDto.class, ret, fos);
-            } catch (Exception e) {
-                e.printStackTrace();
-            } finally {
-                if (fos != null) {
-                    try {
-                        fos.close();
-                    } catch (IOException e) {
-                        e.printStackTrace();
-                    }
-                }
-            }
-            System.out.println("finish! TotalQuestionCount:" + getTotalQuestionCount(rootOrgId.toString()) + " | file: "
-                    + file.getAbsolutePath());
-            Date e = new Date();
-            System.out.println("time:" + (e.getTime() - s.getTime()));
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-
-        }
-    }
-
-    private long getTotalQuestionCount(String rootOrgId) {
-        Query query = new Query();
-        query.addCriteria(Criteria.where("orgId").is(rootOrgId));
-        long count = mongoTemplate.count(query, Question.class, "question");
-        return count;
-    }
-
-    private File createFile(String name) {
-        String suff = fileIndex == 0 ? "" : (fileIndex + "");
-        File file = new File("d:/examcloud-data-export/" + name + suff + ".xlsx");
-        if (file.exists()) {
-            if (!file.delete()) {
-                fileIndex++;
-                return createFile(name);
-            }
-        }
-        return file;
-    }
-}
+package cn.com.qmth.dp.examcloud.oe.modules.export_course_questions_count;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+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.stereotype.Service;
+
+import cn.com.qmth.dp.examcloud.oe.entity.question.Question;
+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.FileUtil;
+import cn.com.qmth.examcloud.web.support.SpringContextHolder;
+
+/**
+ * 按试卷后缀名导出小题各题型数.多线程处理
+ * 
+ * @author chenken
+ *
+ */
+@Service
+public class ExportQuestionsCountBySuffService {
+
+    private String rootOrgId = "17351";
+
+    private String[] paperSuffs = new String[] { "231205" };
+
+    private int threadCount = 20;
+
+    private String dir = "e:/files/gunakai/241128/";
+
+    @Autowired
+    private MongoTemplate mongoTemplate;
+
+    public void start() {
+        Date s = new Date();
+        for (String paperSuff : paperSuffs) {
+            oneBatch(paperSuff);
+        }
+        System.out.println("finish all! ");
+        Date e = new Date();
+        System.out.println("time:" + (e.getTime() - s.getTime()));
+    }
+
+    public void oneBatch(String suff) {
+        Date s = new Date();
+        ExportQuesBySuffProducer pr = SpringContextHolder.getBean(ExportQuesBySuffProducer.class);
+        try {
+            Map<String, Object> param = new HashMap<>();
+            param.put("rootOrgId", rootOrgId);
+            param.put("paperSuff", suff);
+            pr.startDispose(ExportQuesBySuffConsumer.class, threadCount, param);
+            List<CourseQuestionsCountRetDto> ret = new ArrayList<CourseQuestionsCountRetDto>();
+            for (Consumer c : pr.getConsumers()) {
+                ret.addAll(c.getRet());
+            }
+            Collections.sort(ret, new Comparator<CourseQuestionsCountRetDto>() {
+
+                @Override
+                public int compare(CourseQuestionsCountRetDto o1, CourseQuestionsCountRetDto o2) {
+                    String c1 = o1.getCourseCode();
+                    String c2 = o2.getCourseCode();
+                    return c1.compareTo(c2);
+                }
+
+            });
+            FileOutputStream fos = null;
+            File file = FileUtil.createFile(dir, suff + ".xlsx");
+            try {
+                file.createNewFile();
+                fos = new FileOutputStream(file);
+                ExportUtils.makeExcel(CourseQuestionsCountRetDto.class, ret, fos);
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                if (fos != null) {
+                    try {
+                        fos.close();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+            System.out.println("finish! TotalQuestionCount:" + getTotalQuestionCount(rootOrgId.toString()) + " | file: "
+                    + file.getAbsolutePath());
+            Date e = new Date();
+            System.out.println("time:" + (e.getTime() - s.getTime()));
+            System.out.println("finish | filePath:  " + file.getAbsolutePath());
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+
+        }
+    }
+
+    private long getTotalQuestionCount(String rootOrgId) {
+        Query query = new Query();
+        query.addCriteria(Criteria.where("orgId").is(rootOrgId));
+        long count = mongoTemplate.count(query, Question.class, "question");
+        return count;
+    }
+
+}

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

@@ -35,7 +35,7 @@ public class ExportQuesReduplicateConsumer extends Consumer<Course> {
 
     @Override
     public void consume(Map<String, Object> param, Course c) {
-        String rootOrgId = (String) param.get("rootOrgId");
+        Long rootOrgId = (Long) param.get("rootOrgId");
         // String paperName = (String) param.get("paperName");
         // List<PaperDto> papers = findPaper(rootOrgId, c.getCode(), paperName);
         // if (CollectionUtils.isEmpty(papers)) {
@@ -111,11 +111,11 @@ public class ExportQuesReduplicateConsumer extends Consumer<Course> {
     // return ret;
     // }
 
-    private List<QuestionDto> findQuestion(String rootOrgId, String courseCode) {
+    private List<QuestionDto> findQuestion(Long rootOrgId, String courseCode) {
         // Date day=DateUtil.parse("2024-06-13 00:00:00", "yyyy-MM-dd
         // HH:mm:ss");
         Query query = new Query();
-        query.addCriteria(Criteria.where("orgId").is(rootOrgId));
+        query.addCriteria(Criteria.where("orgId").is(rootOrgId.toString()));
         query.addCriteria(Criteria.where("course.code").is(courseCode));
         // query.addCriteria(Criteria.where("creationBy").is(646523L));
         // query.addCriteria(Criteria.where("creationDate").gt(day));

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

@@ -1,65 +1,101 @@
-package cn.com.qmth.dp.examcloud.oe.modules.findreduplicatequestion;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.poi.xssf.usermodel.XSSFRow;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.springframework.stereotype.Service;
-
-import cn.com.qmth.dp.examcloud.oe.entity.question.Course;
-import cn.com.qmth.dp.examcloud.oe.multithread.Producer;
-import cn.com.qmth.dp.examcloud.oe.util.ResouceUtil;
-
-@Service
-public class ExportQuesReduplicateProducer extends Producer {
-
-	
-	@Override
-	protected void produce(Map<String, Object> param) throws Exception {
-		List<Course> cs = getCourse();
-		if (CollectionUtils.isNotEmpty(cs)) {
-			for (Course c : cs) {
-				offer(c);
-			}
-		}
-		System.out.println("courseCount:" + cs.size());
-	}
-	
-	
-	private List<Course> getCourse() {
-		List<Course> list=new ArrayList<>();
-		XSSFWorkbook wb = null;
-		try {
-			wb = new XSSFWorkbook(ResouceUtil.getStream("subject_info.xlsx"));
-			XSSFSheet sheet = wb.getSheetAt(0);
-			int rows = sheet.getLastRowNum();
-			for (int i = 1; i <= rows; i++) {
-				Course c = new Course();
-				XSSFRow row = sheet.getRow(i);
-				String ecCode = row.getCell(0).getStringCellValue().trim();
-				String name = row.getCell(2).getStringCellValue().trim();
-				c.setCode(ecCode);
-				c.setName(name);
-				list.add(c);
-				
-			}
-		} catch (IOException e) {
-			throw new RuntimeException(e);
-		} finally {
-			if (wb != null) {
-				try {
-					wb.close();
-				} catch (IOException e) {
-				}
-			}
-		}
-		return list;
-	}
-	
-
-}
+package cn.com.qmth.dp.examcloud.oe.modules.findreduplicatequestion;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.beans.factory.annotation.Autowired;
+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.entity.question.Course;
+import cn.com.qmth.dp.examcloud.oe.multithread.Producer;
+
+@Service
+public class ExportQuesReduplicateProducer extends Producer {
+
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+
+    @Override
+    protected void produce(Map<String, Object> param) throws Exception {
+        String dir = (String) param.get("dir");
+        String mode = (String) param.get("mode");
+        Long rootOrgId = (Long) param.get("rootOrgId");
+
+        List<Course> cs = null;
+        if ("db".equals(mode)) {
+            cs = getCourseByDb(rootOrgId);
+        } else if ("file".equals(mode)) {
+            cs = getCourseByFile(dir);
+        }
+        if (CollectionUtils.isEmpty(cs)) {
+            System.out.println("*******没有科目");
+            return;
+        }
+        System.out.println("***********courseCount:" + cs.size());
+        if (CollectionUtils.isNotEmpty(cs)) {
+            for (Course c : cs) {
+                offer(c);
+            }
+        }
+        System.out.println("***********courseCount:" + cs.size());
+    }
+
+    private List<Course> getCourseByDb(Long rootOrgId) {
+        String sql = "select t.* from ec_b_course t where t.root_org_id=" + rootOrgId;
+        RowMapper<Course> rowMapper = new BeanPropertyRowMapper<Course>(Course.class);
+        List<Course> ret = jdbcTemplate.query(sql, rowMapper);
+        return ret;
+    }
+
+    private List<Course> getCourseByFile(String dir) {
+        List<Course> list = new ArrayList<>();
+        XSSFWorkbook wb = null;
+        FileInputStream in = null;
+        try {
+            File file = new File(dir + "subject_info.xlsx");
+            in = new FileInputStream(file);
+            wb = new XSSFWorkbook(in);
+            XSSFSheet sheet = wb.getSheetAt(0);
+            int rows = sheet.getLastRowNum();
+            for (int i = 1; i <= rows; i++) {
+                Course c = new Course();
+                XSSFRow row = sheet.getRow(i);
+                String ecCode = row.getCell(0).getStringCellValue().trim();
+                String name = row.getCell(2).getStringCellValue().trim();
+                c.setCode(ecCode);
+                c.setName(name);
+                list.add(c);
+
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } finally {
+
+            if (wb != null) {
+                try {
+                    wb.close();
+                } catch (IOException e) {
+                }
+            }
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+        return list;
+    }
+
+}

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

@@ -1,67 +1,73 @@
-package cn.com.qmth.dp.examcloud.oe.modules.findreduplicatequestion;
-
-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 org.springframework.stereotype.Service;
-
-import cn.com.qmth.dp.examcloud.oe.excel.ExportUtils;
-import cn.com.qmth.dp.examcloud.oe.multithread.Consumer;
-import cn.com.qmth.examcloud.web.support.SpringContextHolder;
-
-@Service
-public class ExportReduplicateQuestionService {
-//	private String rootOrgId = "17068";
-	private String rootOrgId = "17351";
-//	private String paperName = "230517";
-	private int threadCount=8;
-
-	public void start() {
-		Date s=new Date();
-		ExportQuesReduplicateProducer pr = SpringContextHolder.getBean(ExportQuesReduplicateProducer.class);
-		try {
-			Map<String, Object> param=new HashMap<>();
-			param.put("rootOrgId", rootOrgId);
-//			param.put("paperName", paperName);
-			pr.startDispose(ExportQuesReduplicateConsumer.class, threadCount, param);
-			List<RetDto> ret = new ArrayList<>();
-			int index=0;
-			for(Consumer c:pr.getConsumers()) {
-				ret.addAll(c.getRet());
-				index++;
-			}
-			FileOutputStream fos = null;
-			try {
-				File file = new File("d:/ret.xlsx");
-				if (file.exists()) {
-					file.delete();
-				}
-				file.createNewFile();
-				fos = new FileOutputStream(file);
-				ExportUtils.makeExcel(RetDto.class, ret, 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()));
-	}
-
-}
+package cn.com.qmth.dp.examcloud.oe.modules.findreduplicatequestion;
+
+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 org.springframework.stereotype.Service;
+
+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.FileUtil;
+import cn.com.qmth.examcloud.web.support.SpringContextHolder;
+
+@Service
+public class ExportReduplicateQuestionService {
+
+    // private String rootOrgId = "17068";
+    private Long rootOrgId = 17351L;
+
+    private String mode = "file";
+
+    // private String dir = "e:/files/dianke/241205/";
+    private String dir = "e:/files/yunkai/241204/";
+
+    // private String paperName = "230517";
+    private int threadCount = 8;
+
+    public void start() {
+        Date s = new Date();
+        ExportQuesReduplicateProducer pr = SpringContextHolder.getBean(ExportQuesReduplicateProducer.class);
+        File file;
+        try {
+            Map<String, Object> param = new HashMap<>();
+            param.put("rootOrgId", rootOrgId);
+            param.put("mode", mode);
+            param.put("dir", dir);
+            // param.put("paperName", paperName);
+            pr.startDispose(ExportQuesReduplicateConsumer.class, threadCount, param);
+            List<RetDto> ret = new ArrayList<>();
+            for (Consumer c : pr.getConsumers()) {
+                ret.addAll(c.getRet());
+            }
+            FileOutputStream fos = null;
+            try {
+                file = FileUtil.createFile(dir, "duplicatequestion.xlsx");
+                fos = new FileOutputStream(file);
+                ExportUtils.makeExcel(RetDto.class, ret, 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("finish | time:" + (e.getTime() - s.getTime()));
+        System.out.println("finish | filePath:  " + file.getAbsolutePath());
+    }
+
+}

+ 107 - 107
src/main/java/cn/com/qmth/dp/examcloud/oe/multithread/Consumer.java

@@ -1,107 +1,107 @@
-package cn.com.qmth.dp.examcloud.oe.multithread;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.logging.log4j.ThreadContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public abstract class Consumer<T> extends Thread {
-
-    private static final Logger logger = LoggerFactory.getLogger(Consumer.class);
-
-    private Basket basket;
-
-    private List<Object> ret = new ArrayList<>();
-
-    private Set<Object> set = new HashSet<>();
-
-    private String traceId;
-
-    /**
-     * 业务参数
-     */
-    private Map<String, Object> param;
-
-    public Consumer() {
-    }
-
-    @Override
-    public void run() {
-        logger.info("*******************Consumer:" + Thread.currentThread().getId() + " start");
-        try {
-            while (true) {
-                // 先判断是否有异常结束
-                if (basket.isExcuteError()) {
-                    break;
-                }
-                // 取消费数据
-                Object o = basket.consume();
-                // 判断消费数据是否是结束
-                if (o instanceof EndObject) {
-                    break;
-                }
-                @SuppressWarnings("unchecked")
-                T t = (T) o;
-                // logger.info("*******************Consumer:"+Thread.currentThread().getId()+"
-                // consume");
-                // 消费数据实现
-                consume(this.param, t);
-                logger.info("已处理:" + basket.updateProcess(1));
-            }
-        } catch (Exception e) {
-            basket.setExcuteError(true);
-            logger.error("消费线程处理出错", e);
-        } finally {
-            basket.countDown();
-            logger.info("*******************Consumer:" + Thread.currentThread().getId() + " stop");
-            ThreadContext.clearAll();
-        }
-    }
-
-    public abstract void consume(Map<String, Object> param, T t);
-
-    public Basket getBasket() {
-        return basket;
-    }
-
-    public void setBasket(Basket basket) {
-        this.basket = basket;
-    }
-
-    public String getTraceId() {
-        return traceId;
-    }
-
-    public void setTraceId(String traceId) {
-        this.traceId = traceId;
-    }
-
-    public List<Object> getRet() {
-        return ret;
-    }
-
-    public void addRet(Object r) {
-        ret.add(r);
-    }
-
-    protected Map<String, Object> getParam() {
-        return param;
-    }
-
-    protected void setParam(Map<String, Object> param) {
-        this.param = param;
-    }
-
-    public Set<Object> getSet() {
-        return set;
-    }
-
-    public void addSet(Object r) {
-        set.add(r);
-    }
-}
+package cn.com.qmth.dp.examcloud.oe.multithread;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.logging.log4j.ThreadContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class Consumer<T> extends Thread {
+
+    private static final Logger logger = LoggerFactory.getLogger(Consumer.class);
+
+    private Basket basket;
+
+    private List<Object> ret = new ArrayList<>();
+
+    private Set<Object> set = new HashSet<>();
+
+    private String traceId;
+
+    /**
+     * 业务参数
+     */
+    private Map<String, Object> param;
+
+    public Consumer() {
+    }
+
+    @Override
+    public void run() {
+        logger.info("*******************Consumer:" + Thread.currentThread().getId() + " start");
+        try {
+            while (true) {
+                // 先判断是否有异常结束
+                if (basket.isExcuteError()) {
+                    break;
+                }
+                // 取消费数据
+                Object o = basket.consume();
+                // 判断消费数据是否是结束
+                if (o instanceof EndObject) {
+                    break;
+                }
+                @SuppressWarnings("unchecked")
+                T t = (T) o;
+                // logger.info("*******************Consumer:"+Thread.currentThread().getId()+"
+                // consume");
+                // 消费数据实现
+                consume(this.param, t);
+                logger.info("已处理:" + basket.updateProcess(1));
+            }
+        } catch (Exception e) {
+            basket.setExcuteError(true);
+            logger.error("消费线程处理出错", e);
+        } finally {
+            basket.countDown();
+            logger.info("*******************Consumer:" + Thread.currentThread().getId() + " stop");
+            ThreadContext.clearAll();
+        }
+    }
+
+    public abstract void consume(Map<String, Object> param, T t);
+
+    public Basket getBasket() {
+        return basket;
+    }
+
+    public void setBasket(Basket basket) {
+        this.basket = basket;
+    }
+
+    public String getTraceId() {
+        return traceId;
+    }
+
+    public void setTraceId(String traceId) {
+        this.traceId = traceId;
+    }
+
+    public List<Object> getRet() {
+        return ret;
+    }
+
+    public void addRet(Object r) {
+        ret.add(r);
+    }
+
+    protected Map<String, Object> getParam() {
+        return param;
+    }
+
+    protected void setParam(Map<String, Object> param) {
+        this.param = param;
+    }
+
+    public Set<Object> getSet() {
+        return set;
+    }
+
+    public void addSet(Object r) {
+        set.add(r);
+    }
+}

+ 508 - 472
src/main/java/cn/com/qmth/dp/examcloud/oe/util/FileUtil.java

@@ -1,473 +1,509 @@
-/*
- * *************************************************
- * Copyright (c) 2018 QMTH. All Rights Reserved.
- * Created by Deason on 2018-07-12 15:31:10.
- * *************************************************
- */
-
-package cn.com.qmth.dp.examcloud.oe.util;
-
-import org.apache.commons.io.IOUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.*;
-import java.nio.charset.Charset;
-import java.text.SimpleDateFormat;
-import java.util.*;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import java.util.zip.ZipOutputStream;
-
-public class FileUtil {
-
-    private static Logger log = LoggerFactory.getLogger(FileUtil.class);
-
-    /**
-     * 分隔文件
-     *
-     * @param sourcePath 原文件
-     * @param targetPath 目标文件
-     * @param n          跳过的字节数
-     * @return
-     */
-    public static File cutFile(String sourcePath, String targetPath, int n) {
-        File file = new File(sourcePath);
-        File newFile = new File(targetPath);
-
-        try (
-                FileInputStream fis = new FileInputStream(file);
-                InputStream is = new BufferedInputStream(fis);
-                OutputStream os = new FileOutputStream(newFile);
-        ) {
-
-            //从n个字节开始读,注意中文是两个字节
-            fis.skip(n);
-
-            //指定文件位置读取的文件流,存入新文件
-            byte buffer[] = new byte[4 * 1024];
-            int len;
-            while ((len = is.read(buffer)) != -1) {
-                os.write(buffer, 0, len);
-            }
-
-            os.flush();
-            return newFile;
-        } catch (FileNotFoundException e) {
-            log.error(e.getMessage(), e);
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-        }
-        return null;
-    }
-
-    /**
-     * 读取文件前面部分N个字节
-     *
-     * @param path       文件路径
-     * @param headerSize 头信息字节数(必须2的倍数)
-     * @param signSize   签名信息字节数
-     * @return
-     */
-    public static String[] readFileHeader(String path, int headerSize, int signSize) {
-        int n = headerSize / 2;
-        String[] codes = new String[n + 1];
-
-        File file = new File(path);
-        try (
-                FileInputStream fis = new FileInputStream(file);
-                DataInputStream ois = new DataInputStream(fis);
-        ) {
-            //分n次读取文件(n * 2)个字节
-            for (int i = 0; i < n; i++) {
-                codes[i] = String.valueOf(ois.readShort());
-            }
-
-            if (signSize > 0) {
-                StringBuilder ss = new StringBuilder();
-                for (int i = 0; i < signSize; i++) {
-                    ss.append((char) ois.readByte());
-                }
-                codes[2] = ss.toString();
-            }
-        } catch (FileNotFoundException e) {
-            log.error(e.getMessage(), e);
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-        }
-
-        return codes;
-    }
-
-    /**
-     * 读取文件内容
-     *
-     * @param file
-     * @return
-     */
-    public static String readFileContent(File file) {
-        StringBuilder content = new StringBuilder();
-        InputStreamReader streamReader = null;
-        BufferedReader bufferedReader = null;
-        try {
-            String encoding = "UTF-8";
-            if (file.exists() && file.isFile()) {
-                streamReader = new InputStreamReader(new FileInputStream(file), encoding);
-                bufferedReader = new BufferedReader(streamReader);
-                String line;
-                while ((line = bufferedReader.readLine()) != null) {
-                    content.append(line);
-                }
-            }
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-        } finally {
-            IOUtils.closeQuietly(streamReader);
-            IOUtils.closeQuietly(bufferedReader);
-        }
-        return content.toString();
-    }
-
-    /**
-     * 在文件流前面追加头信息和签名信息,并生成新的“.tk”文件
-     */
-    public static boolean appendHeader(File file, short[] headers, String sign) {
-        if (file == null || !file.exists()) {
-            return false;
-        }
-
-        if (!file.isFile()) {
-            return false;
-        }
-
-        FileInputStream fis = null;
-        InputStream is = null;
-        FileOutputStream fos = null;
-        DataOutputStream dos = null;
-        try {
-            //创建临时文件
-            String baseFilePath = file.getAbsolutePath();
-            String targetFilePath = getFilePathName(baseFilePath) + ".tk";
-            File newFile = new File(targetFilePath);
-            fos = new FileOutputStream(newFile);
-            dos = new DataOutputStream(fos);
-
-            //写入头信息
-            for (short s : headers) {
-                dos.writeShort(s);
-            }
-            if (sign != null && !"".equals(sign)) {
-                //写入签名信息
-                dos.write(sign.getBytes("ISO-8859-1"));
-            }
-
-            //在临时文件中追加原始文件内容
-            fis = new FileInputStream(file);
-            is = new BufferedInputStream(fis);
-
-            byte buffer[] = new byte[4 * 1024];
-            int len;
-            while ((len = is.read(buffer)) != -1) {
-                dos.write(buffer, 0, len);
-            }
-            dos.flush();
-            return true;
-        } catch (FileNotFoundException e) {
-            log.error(e.getMessage(), e);
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-        } finally {
-            IOUtils.closeQuietly(is);
-            IOUtils.closeQuietly(fis);
-            IOUtils.closeQuietly(dos);
-            IOUtils.closeQuietly(fos);
-        }
-        return false;
-    }
-
-    /**
-     * 生成日期目录路径
-     */
-    public static String generateDateDir() {
-        return "/" + new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + "/";
-    }
-
-    public static String generateFileName() {
-        return UUID.randomUUID().toString().replaceAll("-", "");
-    }
-
-    public static String generateDateName() {
-        return new SimpleDateFormat("yyMMddHHmmss").format(new Date());
-    }
-
-    /**
-     * 获取文件后缀名(包含".")
-     */
-    public static String getFileSuffix(String fileName) {
-        if (fileName == null) {
-            return "";
-        }
-        int index = fileName.lastIndexOf(".");
-        if (index > -1) {
-            return fileName.substring(index).toLowerCase();
-        }
-        return "";
-    }
-
-    /**
-     * 获取无后缀的文件名
-     *
-     * @param fileName 示例:../xxx/abc.xx
-     * @return 示例:../xxx/abc
-     */
-    public static String getFilePathName(String fileName) {
-        if (fileName != null && fileName.length() > 0) {
-            int index = fileName.lastIndexOf(".");
-            if (index != -1) {
-                return fileName.substring(0, index);
-            }
-        }
-        return "";
-    }
-
-    /**
-     * 创建文件目录
-     */
-    public static boolean makeDirs(String path) {
-        if (path == null || "".equals(path)) {
-            return false;
-        }
-        File folder = new File(path);
-        if (!folder.exists()) {
-            return folder.mkdirs();
-        }
-        return true;
-    }
-
-    /**
-     * 写入内容到文件(覆盖)
-     */
-    public static void writeFile(String filePath, String content) {
-        File file = new File(filePath);
-        makeDirs(file.getParent());
-
-        try {
-            if (!file.exists()) {
-                file.createNewFile();
-            }
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-            return;
-        }
-
-        if (content == null) {
-            content = "";
-        }
-
-        try (FileOutputStream fos = new FileOutputStream(file);
-             OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
-             BufferedWriter bw = new BufferedWriter(osw);) {
-
-            bw.write(content);
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-        }
-    }
-
-    /**
-     * 解压文件
-     *
-     * @param targetDir 解压目录
-     * @param zipFile   待解压的ZIP文件
-     */
-    public static List<File> unZip(File targetDir, File zipFile) {
-        if (targetDir == null) {
-            log.error("解压目录不能为空!");
-            return null;
-        }
-
-        if (zipFile == null) {
-            log.error("待解压的文件不能为空!");
-            return null;
-        }
-
-        if (!zipFile.exists()) {
-            log.error("待解压的文件不存在!" + zipFile.getAbsolutePath());
-            return null;
-        }
-
-        String zipName = zipFile.getName().toLowerCase();
-        if (zipFile.isDirectory() || zipName.indexOf(".zip") < 0) {
-            log.error("待解压的文件格式错误!");
-            return null;
-        }
-
-        if (!targetDir.exists()) {
-            targetDir.mkdir();
-        }
-
-        List<File> result = new LinkedList<>();
-
-        try (ZipFile zip = new ZipFile(zipFile, Charset.forName("UTF-8"));) {
-
-            Enumeration entries = zip.entries();
-            while (entries.hasMoreElements()) {
-                ZipEntry entry = (ZipEntry) entries.nextElement();
-
-                //Linux中需要替换掉路径的反斜杠
-                String entryName = (File.separator + entry.getName()).replaceAll("\\\\", "/");
-
-                String filePath = targetDir.getAbsolutePath() + entryName;
-                File target = new File(filePath);
-                if (entry.isDirectory()) {
-                    target.mkdirs();
-                } else {
-                    File dir = target.getParentFile();
-                    if (!dir.exists()) {
-                        dir.mkdirs();
-                    }
-
-                    try (OutputStream os = new FileOutputStream(target);
-                         InputStream is = zip.getInputStream(entry);) {
-                        IOUtils.copy(is, os);
-                        os.flush();
-                    } catch (IOException e) {
-                        log.error(e.getMessage(), e);
-                    }
-                    result.add(target);
-                }
-            }
-
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-        }
-
-        return result;
-    }
-
-    /**
-     * 文件压缩
-     *
-     * @param target  目录或文件
-     * @param zipFile 压缩后的ZIP文件
-     */
-    public static boolean doZip(File target, File zipFile) {
-        if (target == null || !target.exists()) {
-            log.error("目录或文件不能为空!");
-            return false;
-        }
-
-        if (zipFile == null) {
-            log.error("待压缩的文件不能为空!");
-            return false;
-        }
-
-        try (
-                OutputStream outStream = new FileOutputStream(zipFile);
-                ZipOutputStream zipOutStream = new ZipOutputStream(outStream, Charset.forName("UTF-8"));
-        ) {
-            if (!zipFile.exists()) {
-                boolean ok = zipFile.createNewFile();
-                if (!ok) {
-                    log.error("压缩的文件创建失败!");
-                    return false;
-                }
-            }
-
-            if (target.isDirectory()) {
-                File[] files = target.listFiles();
-                if (files.length == 0) {
-                    log.error("文件夹内未找到任何文件!");
-                    return false;
-                }
-
-                for (File file : files) {
-                    doZip(zipOutStream, file, null);
-                }
-            } else {
-                doZip(zipOutStream, target, null);
-            }
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-        }
-
-        return true;
-    }
-
-    private static void doZip(ZipOutputStream zipOutStream, File target, String parentDir) throws IOException {
-        //log.info("Zip:" + parentDir);
-        if (parentDir == null) {
-            parentDir = "";
-        }
-
-        if (!"".equals(parentDir) && !parentDir.endsWith(File.separator)) {
-            parentDir += File.separator;
-        }
-
-        if (target.isDirectory()) {
-            File[] files = target.listFiles();
-            if (files.length > 0) {
-                for (File file : files) {
-                    doZip(zipOutStream, file, parentDir + target.getName());
-                }
-            } else {
-                zipOutStream.putNextEntry(new ZipEntry(parentDir + target.getName()));
-                zipOutStream.closeEntry();
-            }
-        } else {
-            try (InputStream is = new FileInputStream(target);) {
-                zipOutStream.putNextEntry(new ZipEntry(parentDir + target.getName()));
-                int len;
-                byte[] bytes = new byte[1024];
-                while ((len = is.read(bytes)) > 0) {
-                    zipOutStream.write(bytes, 0, len);
-                }
-            } catch (IOException e) {
-                log.error(e.getMessage(), e);
-            }
-            zipOutStream.closeEntry();
-        }
-    }
-
-    public static void deleteFolder(String path) {
-
-        File file = new File(path);
-        if (file.exists()) {
-            if (file.isFile()) {
-                deleteFile(path);
-            } else {
-                deleteDirectory(path);
-            }
-        }
-    }
-
-    public static void deleteFile(String path) {
-        File file = new File(path);
-        if (file.isFile() && file.exists()) {
-            file.delete();
-        }
-    }
-
-    public static void deleteDirectory(String path) {
-        if (!path.endsWith(File.separator)) {
-            path = path + File.separator;
-        }
-        File dirFile = new File(path);
-        if (!dirFile.exists() || !dirFile.isDirectory()) {
-            return;
-        }
-        File[] files = dirFile.listFiles();
-        if (files != null) {
-            for (int i = 0; i < files.length; i++) {
-                if (files[i].isFile()) {
-                    deleteFile(files[i].getAbsolutePath());
-                } else {
-                    deleteDirectory(files[i].getAbsolutePath());
-                }
-            }
-        }
-
-        dirFile.delete();
-    }
-
+/*
+ * ************************************************* Copyright (c) 2018 QMTH.
+ * All Rights Reserved. Created by Deason on 2018-07-12 15:31:10.
+ * *************************************************
+ */
+
+package cn.com.qmth.dp.examcloud.oe.util;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FileUtil {
+
+    private static Logger log = LoggerFactory.getLogger(FileUtil.class);
+
+    /**
+     * 分隔文件
+     *
+     * @param sourcePath
+     *            原文件
+     * @param targetPath
+     *            目标文件
+     * @param n
+     *            跳过的字节数
+     * @return
+     */
+    public static File cutFile(String sourcePath, String targetPath, int n) {
+        File file = new File(sourcePath);
+        File newFile = new File(targetPath);
+
+        try (FileInputStream fis = new FileInputStream(file);
+                InputStream is = new BufferedInputStream(fis);
+                OutputStream os = new FileOutputStream(newFile);) {
+
+            // 从n个字节开始读,注意中文是两个字节
+            fis.skip(n);
+
+            // 指定文件位置读取的文件流,存入新文件
+            byte buffer[] = new byte[4 * 1024];
+            int len;
+            while ((len = is.read(buffer)) != -1) {
+                os.write(buffer, 0, len);
+            }
+
+            os.flush();
+            return newFile;
+        } catch (FileNotFoundException e) {
+            log.error(e.getMessage(), e);
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+        }
+        return null;
+    }
+
+    /**
+     * 读取文件前面部分N个字节
+     *
+     * @param path
+     *            文件路径
+     * @param headerSize
+     *            头信息字节数(必须2的倍数)
+     * @param signSize
+     *            签名信息字节数
+     * @return
+     */
+    public static String[] readFileHeader(String path, int headerSize, int signSize) {
+        int n = headerSize / 2;
+        String[] codes = new String[n + 1];
+
+        File file = new File(path);
+        try (FileInputStream fis = new FileInputStream(file); DataInputStream ois = new DataInputStream(fis);) {
+            // 分n次读取文件(n * 2)个字节
+            for (int i = 0; i < n; i++) {
+                codes[i] = String.valueOf(ois.readShort());
+            }
+
+            if (signSize > 0) {
+                StringBuilder ss = new StringBuilder();
+                for (int i = 0; i < signSize; i++) {
+                    ss.append((char) ois.readByte());
+                }
+                codes[2] = ss.toString();
+            }
+        } catch (FileNotFoundException e) {
+            log.error(e.getMessage(), e);
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+        }
+
+        return codes;
+    }
+
+    /**
+     * 读取文件内容
+     *
+     * @param file
+     * @return
+     */
+    public static String readFileContent(File file) {
+        StringBuilder content = new StringBuilder();
+        InputStreamReader streamReader = null;
+        BufferedReader bufferedReader = null;
+        try {
+            String encoding = "UTF-8";
+            if (file.exists() && file.isFile()) {
+                streamReader = new InputStreamReader(new FileInputStream(file), encoding);
+                bufferedReader = new BufferedReader(streamReader);
+                String line;
+                while ((line = bufferedReader.readLine()) != null) {
+                    content.append(line);
+                }
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        } finally {
+            IOUtils.closeQuietly(streamReader);
+            IOUtils.closeQuietly(bufferedReader);
+        }
+        return content.toString();
+    }
+
+    /**
+     * 在文件流前面追加头信息和签名信息,并生成新的“.tk”文件
+     */
+    public static boolean appendHeader(File file, short[] headers, String sign) {
+        if (file == null || !file.exists()) {
+            return false;
+        }
+
+        if (!file.isFile()) {
+            return false;
+        }
+
+        FileInputStream fis = null;
+        InputStream is = null;
+        FileOutputStream fos = null;
+        DataOutputStream dos = null;
+        try {
+            // 创建临时文件
+            String baseFilePath = file.getAbsolutePath();
+            String targetFilePath = getFilePathName(baseFilePath) + ".tk";
+            File newFile = new File(targetFilePath);
+            fos = new FileOutputStream(newFile);
+            dos = new DataOutputStream(fos);
+
+            // 写入头信息
+            for (short s : headers) {
+                dos.writeShort(s);
+            }
+            if (sign != null && !"".equals(sign)) {
+                // 写入签名信息
+                dos.write(sign.getBytes("ISO-8859-1"));
+            }
+
+            // 在临时文件中追加原始文件内容
+            fis = new FileInputStream(file);
+            is = new BufferedInputStream(fis);
+
+            byte buffer[] = new byte[4 * 1024];
+            int len;
+            while ((len = is.read(buffer)) != -1) {
+                dos.write(buffer, 0, len);
+            }
+            dos.flush();
+            return true;
+        } catch (FileNotFoundException e) {
+            log.error(e.getMessage(), e);
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+        } finally {
+            IOUtils.closeQuietly(is);
+            IOUtils.closeQuietly(fis);
+            IOUtils.closeQuietly(dos);
+            IOUtils.closeQuietly(fos);
+        }
+        return false;
+    }
+
+    /**
+     * 生成日期目录路径
+     */
+    public static String generateDateDir() {
+        return "/" + new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + "/";
+    }
+
+    public static String generateFileName() {
+        return UUID.randomUUID().toString().replaceAll("-", "");
+    }
+
+    public static String generateDateName() {
+        return new SimpleDateFormat("yyMMddHHmmss").format(new Date());
+    }
+
+    /**
+     * 获取文件后缀名(包含".")
+     */
+    public static String getFileSuffix(String fileName) {
+        if (fileName == null) {
+            return "";
+        }
+        int index = fileName.lastIndexOf(".");
+        if (index > -1) {
+            return fileName.substring(index).toLowerCase();
+        }
+        return "";
+    }
+
+    /**
+     * 获取无后缀的文件名
+     *
+     * @param fileName
+     *            示例:../xxx/abc.xx
+     * @return 示例:../xxx/abc
+     */
+    public static String getFilePathName(String fileName) {
+        if (fileName != null && fileName.length() > 0) {
+            int index = fileName.lastIndexOf(".");
+            if (index != -1) {
+                return fileName.substring(0, index);
+            }
+        }
+        return "";
+    }
+
+    /**
+     * 创建文件目录
+     */
+    public static boolean makeDirs(String path) {
+        if (path == null || "".equals(path)) {
+            return false;
+        }
+        File folder = new File(path);
+        if (!folder.exists()) {
+            return folder.mkdirs();
+        }
+        return true;
+    }
+
+    /**
+     * 写入内容到文件(覆盖)
+     */
+    public static void writeFile(String filePath, String content) {
+        File file = new File(filePath);
+        makeDirs(file.getParent());
+
+        try {
+            if (!file.exists()) {
+                file.createNewFile();
+            }
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+            return;
+        }
+
+        if (content == null) {
+            content = "";
+        }
+
+        try (FileOutputStream fos = new FileOutputStream(file);
+                OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
+                BufferedWriter bw = new BufferedWriter(osw);) {
+
+            bw.write(content);
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 解压文件
+     *
+     * @param targetDir
+     *            解压目录
+     * @param zipFile
+     *            待解压的ZIP文件
+     */
+    public static List<File> unZip(File targetDir, File zipFile) {
+        if (targetDir == null) {
+            log.error("解压目录不能为空!");
+            return null;
+        }
+
+        if (zipFile == null) {
+            log.error("待解压的文件不能为空!");
+            return null;
+        }
+
+        if (!zipFile.exists()) {
+            log.error("待解压的文件不存在!" + zipFile.getAbsolutePath());
+            return null;
+        }
+
+        String zipName = zipFile.getName().toLowerCase();
+        if (zipFile.isDirectory() || zipName.indexOf(".zip") < 0) {
+            log.error("待解压的文件格式错误!");
+            return null;
+        }
+
+        if (!targetDir.exists()) {
+            targetDir.mkdir();
+        }
+
+        List<File> result = new LinkedList<>();
+
+        try (ZipFile zip = new ZipFile(zipFile, Charset.forName("UTF-8"));) {
+
+            Enumeration entries = zip.entries();
+            while (entries.hasMoreElements()) {
+                ZipEntry entry = (ZipEntry) entries.nextElement();
+
+                // Linux中需要替换掉路径的反斜杠
+                String entryName = (File.separator + entry.getName()).replaceAll("\\\\", "/");
+
+                String filePath = targetDir.getAbsolutePath() + entryName;
+                File target = new File(filePath);
+                if (entry.isDirectory()) {
+                    target.mkdirs();
+                } else {
+                    File dir = target.getParentFile();
+                    if (!dir.exists()) {
+                        dir.mkdirs();
+                    }
+
+                    try (OutputStream os = new FileOutputStream(target); InputStream is = zip.getInputStream(entry);) {
+                        IOUtils.copy(is, os);
+                        os.flush();
+                    } catch (IOException e) {
+                        log.error(e.getMessage(), e);
+                    }
+                    result.add(target);
+                }
+            }
+
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+        }
+
+        return result;
+    }
+
+    /**
+     * 文件压缩
+     *
+     * @param target
+     *            目录或文件
+     * @param zipFile
+     *            压缩后的ZIP文件
+     */
+    public static boolean doZip(File target, File zipFile) {
+        if (target == null || !target.exists()) {
+            log.error("目录或文件不能为空!");
+            return false;
+        }
+
+        if (zipFile == null) {
+            log.error("待压缩的文件不能为空!");
+            return false;
+        }
+
+        try (OutputStream outStream = new FileOutputStream(zipFile);
+                ZipOutputStream zipOutStream = new ZipOutputStream(outStream, Charset.forName("UTF-8"));) {
+            if (!zipFile.exists()) {
+                boolean ok = zipFile.createNewFile();
+                if (!ok) {
+                    log.error("压缩的文件创建失败!");
+                    return false;
+                }
+            }
+
+            if (target.isDirectory()) {
+                File[] files = target.listFiles();
+                if (files.length == 0) {
+                    log.error("文件夹内未找到任何文件!");
+                    return false;
+                }
+
+                for (File file : files) {
+                    doZip(zipOutStream, file, null);
+                }
+            } else {
+                doZip(zipOutStream, target, null);
+            }
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+        }
+
+        return true;
+    }
+
+    private static void doZip(ZipOutputStream zipOutStream, File target, String parentDir) throws IOException {
+        // log.info("Zip:" + parentDir);
+        if (parentDir == null) {
+            parentDir = "";
+        }
+
+        if (!"".equals(parentDir) && !parentDir.endsWith(File.separator)) {
+            parentDir += File.separator;
+        }
+
+        if (target.isDirectory()) {
+            File[] files = target.listFiles();
+            if (files.length > 0) {
+                for (File file : files) {
+                    doZip(zipOutStream, file, parentDir + target.getName());
+                }
+            } else {
+                zipOutStream.putNextEntry(new ZipEntry(parentDir + target.getName()));
+                zipOutStream.closeEntry();
+            }
+        } else {
+            try (InputStream is = new FileInputStream(target);) {
+                zipOutStream.putNextEntry(new ZipEntry(parentDir + target.getName()));
+                int len;
+                byte[] bytes = new byte[1024];
+                while ((len = is.read(bytes)) > 0) {
+                    zipOutStream.write(bytes, 0, len);
+                }
+            } catch (IOException e) {
+                log.error(e.getMessage(), e);
+            }
+            zipOutStream.closeEntry();
+        }
+    }
+
+    public static void deleteFolder(String path) {
+
+        File file = new File(path);
+        if (file.exists()) {
+            if (file.isFile()) {
+                deleteFile(path);
+            } else {
+                deleteDirectory(path);
+            }
+        }
+    }
+
+    public static void deleteFile(String path) {
+        File file = new File(path);
+        if (file.isFile() && file.exists()) {
+            file.delete();
+        }
+    }
+
+    public static void deleteDirectory(String path) {
+        if (!path.endsWith(File.separator)) {
+            path = path + File.separator;
+        }
+        File dirFile = new File(path);
+        if (!dirFile.exists() || !dirFile.isDirectory()) {
+            return;
+        }
+        File[] files = dirFile.listFiles();
+        if (files != null) {
+            for (int i = 0; i < files.length; i++) {
+                if (files[i].isFile()) {
+                    deleteFile(files[i].getAbsolutePath());
+                } else {
+                    deleteDirectory(files[i].getAbsolutePath());
+                }
+            }
+        }
+
+        dirFile.delete();
+    }
+
+    public static File createFile(String dir, String name) {
+        return createFile(dir, name, 0);
+    }
+
+    private static File createFile(String dir, String filename, int fileIndex) {
+        String fileType = filename.substring(filename.lastIndexOf("."));
+        String fileNameText = filename.substring(0, filename.lastIndexOf("."));
+        String suff = fileIndex == 0 ? "" : (fileIndex + "");
+        File file = new File(dir + fileNameText + suff + fileType);
+        if (file.exists()) {
+            if (!file.delete()) {
+                fileIndex++;
+                return createFile(dir, filename, fileIndex);
+            }
+        }
+        return file;
+    }
 }

BIN
src/main/resources/subject_info.xlsx