Преглед изворни кода

Merge branch 'dev0410' of https://git.oschina.net/songyue123456/comm-ques-bank into dev0410

chenken пре 8 година
родитељ
комит
e6c7020078
19 измењених фајлова са 1080 додато и 772 уклоњено
  1. 7 19
      cqb-base/src/main/java/com/qmth/cqb/base/service/SettingService.java
  2. 271 252
      cqb-comm-utils/src/main/java/com/qmth/cqb/utils/StringSimilarityUtils.java
  3. 14 0
      cqb-comm-utils/src/main/java/com/qmth/cqb/utils/exception/PaperException.java
  4. 15 0
      cqb-comm-utils/src/main/java/com/qmth/cqb/utils/exception/QuesException.java
  5. 247 170
      cqb-comm-utils/src/main/java/com/qmth/cqb/utils/word/DocxProcessUtil.java
  6. 3 2
      cqb-paper/src/main/java/com/qmth/cqb/paper/dao/PaperRepo.java
  7. 30 27
      cqb-paper/src/main/java/com/qmth/cqb/paper/model/PaperDetailUnit.java
  8. 135 46
      cqb-paper/src/main/java/com/qmth/cqb/paper/service/ExportPaperService.java
  9. 149 160
      cqb-paper/src/main/java/com/qmth/cqb/paper/service/ImportPaperService.java
  10. 55 42
      cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperDetailService.java
  11. 24 10
      cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperService.java
  12. 11 1
      cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperStructService.java
  13. 13 1
      cqb-paper/src/main/java/com/qmth/cqb/paper/web/ExportPaperController.java
  14. 31 17
      cqb-paper/src/main/java/com/qmth/cqb/paper/web/ImportPaperController.java
  15. 40 6
      cqb-paper/src/main/java/com/qmth/cqb/paper/web/PaperController.java
  16. 12 6
      cqb-paper/src/main/java/com/qmth/cqb/paper/web/PaperDetailController.java
  17. 6 1
      cqb-paper/src/main/java/com/qmth/cqb/paper/web/PaperStructController.java
  18. 16 11
      cqb-question-resource/src/main/java/com/qmth/cqb/question/service/QuesService.java
  19. 1 1
      cqb-starter/src/main/resources/log4j2.xml

+ 7 - 19
cqb-base/src/main/java/com/qmth/cqb/base/service/SettingService.java

@@ -1,35 +1,23 @@
 package com.qmth.cqb.base.service;
 
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
 
-import com.qmth.cqb.base.dao.CourseRepo;
 import com.qmth.cqb.base.dao.SettingRepo;
-import com.qmth.cqb.base.model.Course;
 import com.qmth.cqb.base.model.Setting;
 import com.qmth.cqb.utils.enums.Switch;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Example;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-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 java.util.ArrayList;
-import java.util.List;
 
 /**
  * Created by songyue on 16/12/28.
  */
 @Service
 public class SettingService {
-	
-	@Autowired
+
+    @Autowired
     SettingRepo settingRepo;
-	
-    public void initData(){
-        if(settingRepo.count() == 0){
+
+    public void initData() {
+        if (settingRepo.count() == 0) {
             Setting importSetting = new Setting();
             Setting genSetting = new Setting();
             importSetting.setCode("import");

+ 271 - 252
cqb-comm-utils/src/main/java/com/qmth/cqb/utils/StringSimilarityUtils.java

@@ -1,276 +1,295 @@
 package com.qmth.cqb.utils;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import org.ansj.domain.Result;
 import org.ansj.domain.Term;
 import org.ansj.splitWord.analysis.ToAnalysis;
 
-import java.util.*;
-
 /**
  * 计算相似度工具包:
+ * 
  * @author songyue
  * @date 2016-05-11
  */
 public class StringSimilarityUtils {
 
-	/**
-	 * 对输入字符串分词
-	 * @param str
-	 * @return ArrayList
-	 * @author songyue
-	 */
-	public static List<String> segmentText(String str) {
-		List<String> segResult = new ArrayList<String>();// 分词结果
-		Result result = ToAnalysis.parse(str);
-		List<Term> terms = result.getTerms();
-		for(Term term:terms){
-			segResult.add(term.getName());
-		}
-		return segResult;
-	}
+    /**
+     * 对输入字符串分词
+     * 
+     * @param str
+     * @return ArrayList
+     * @author songyue
+     */
+    public static List<String> segmentText(String str) {
+        List<String> segResult = new ArrayList<String>();// 分词结果
+        Result result = ToAnalysis.parse(str);
+        List<Term> terms = result.getTerms();
+        for (Term term : terms) {
+            segResult.add(term.getName());
+        }
+        return segResult;
+    }
+
+    /**
+     * 计算相似度(两个分词集合,分词匹配,算法为余弦定理)
+     * 
+     * @param seg1
+     * @param seg2
+     * @return
+     */
+    public static double getSimilarityWithCosinesBySeg(String seg1, String seg2) {
+        double similarity = 0;
+        int size1 = 0;
+        int size2 = 0;
+        seg1 = stringFilter(seg1);
+        seg2 = stringFilter(seg2);
+        List<String> w1 = segmentText(seg1);
+        List<String> w2 = segmentText(seg2);
+        if (w1 != null && (size1 = w1.size()) != 0 && w2 != null && (size2 = w2.size()) != 0) {
+            Map<String, int[]> countMap = new HashMap<String, int[]>();
+            String index = null;
+            // 将w1与w2分词出现频次统计入coutMap中
+            for (int i = 0; i < size1; i++) {
+                index = w1.get(i);
+                if (index != null) {
+                    int[] c = countMap.get(index);
+                    if (c != null && c.length == 2) {
+                        c[0]++;
+                    } else {
+                        c = new int[2];
+                        c[0] = 1;
+                        c[1] = 0;
+                        countMap.put(index, c);
+                    }
+                }
+            }
+            for (int i = 0; i < size2; i++) {
+                index = w2.get(i);
+                if (index != null) {
+                    int[] c = countMap.get(index);
+                    if (c != null && c.length == 2) {
+                        c[1]++;
+                    } else {
+                        c = new int[2];
+                        c[0] = 0;
+                        c[1] = 1;
+                        countMap.put(index, c);
+                    }
+                }
+            }
+            // 根据余弦定理计算相似度
+            Iterator<String> it = countMap.keySet().iterator();
+            double sum = 0;
+            double s1 = 0;
+            double s2 = 0;
+            while (it.hasNext()) {
+                int[] c = countMap.get(it.next());
+                sum += c[0] * c[1];
+                s1 += c[0] * c[0];
+                s2 += c[1] * c[1];
+            }
+            similarity = sum / Math.sqrt(s1 * s2);
+        } else {
+            return 0;
+        }
+        return similarity;
+    }
 
-	/**
-	 * 计算相似度(两个分词集合,分词匹配,算法为余弦定理)
-	 * @param seg1
-	 * @param seg2
-	 * @return
-	 */
-	public static double getSimilarityWithCosinesBySeg(String seg1, String seg2) {
-		double similarity = 0;
-		int size1 = 0;
-		int size2 = 0;
-		seg1 = stringFilter(seg1);
-		seg2 = stringFilter(seg2);
-		List<String> w1 = segmentText(seg1);
-		List<String> w2 = segmentText(seg2);
-		if (w1 != null && (size1 = w1.size()) != 0 && w2 != null && (size2 = w2.size()) != 0) {
-			Map<String, int[]> countMap = new HashMap<String, int[]>();
-			String index = null;
-			// 将w1与w2分词出现频次统计入coutMap中
-			for (int i = 0; i < size1; i++) {
-				index = w1.get(i);
-				if (index != null) {
-					int[] c = countMap.get(index);
-					if (c != null && c.length == 2) {
-						c[0]++;
-					} else {
-						c = new int[2];
-						c[0] = 1;
-						c[1] = 0;
-						countMap.put(index, c);
-					}
-				}
-			}
-			for (int i = 0; i < size2; i++) {
-				index = w2.get(i);
-				if (index != null) {
-					int[] c = countMap.get(index);
-					if (c != null && c.length == 2) {
-						c[1]++;
-					} else {
-						c = new int[2];
-						c[0] = 0;
-						c[1] = 1;
-						countMap.put(index, c);
-					}
-				}
-			}
-			// 根据余弦定理计算相似度
-			Iterator<String> it = countMap.keySet().iterator();
-			double sum = 0;
-			double s1 = 0;
-			double s2 = 0;
-			while (it.hasNext()) {
-				int[] c = countMap.get(it.next());
-				sum += c[0] * c[1];
-				s1 += c[0] * c[0];
-				s2 += c[1] * c[1];
-			}
-			similarity = sum / Math.sqrt(s1 * s2);
-		} else {
-			throw new NullPointerException("传入的参数为空");
-		}
-		return similarity;
-	}
+    /**
+     * 计算相似度(两个字符串,全字匹配,算法为余弦定理)
+     * 
+     * @param w1
+     * @param w2
+     * @return
+     */
+    public static double getSimilarityWithCosinesByWords(String w1, String w2) {
+        double similarity = 0;
+        int size1 = 0;
+        int size2 = 0;
+        w1 = stringFilter(w1);
+        w2 = stringFilter(w2);
+        if (w1 != null && (size1 = w1.length()) != 0 && w2 != null && (size2 = w2.length()) != 0) {
+            Map<Character, int[]> countMap = new HashMap<Character, int[]>();
+            char index;
+            // 将w1与w2所有字符出现频次统计入countMap中
+            for (int i = 0; i < size1; i++) {
+                index = w1.charAt(i);
+                int[] c = countMap.get(index);
+                if (c != null && c.length == 2) {
+                    c[0]++;
+                } else {
+                    c = new int[2];
+                    c[0] = 1;
+                    c[1] = 0;
+                    countMap.put(index, c);
+                }
+            }
+            for (int i = 0; i < size2; i++) {
+                index = w2.charAt(i);
+                int[] c = countMap.get(index);
+                if (c != null && c.length == 2) {
+                    c[1]++;
+                } else {
+                    c = new int[2];
+                    c[0] = 0;
+                    c[1] = 1;
+                    countMap.put(index, c);
+                }
+            }
+            // 根据余弦定理计算相似度
+            Iterator<Character> it = countMap.keySet().iterator();
+            double sum = 0;
+            double s1 = 0;
+            double s2 = 0;
+            while (it.hasNext()) {
+                int[] c = countMap.get(it.next());
+                sum += c[0] * c[1];
+                s1 += c[0] * c[0];
+                s2 += c[1] * c[1];
+            }
+            similarity = sum / Math.sqrt(s1 * s2);
+        } else {
+            throw new NullPointerException("传入的参数为空");
+        }
+        return similarity;
+    }
 
-	/**
-	 * 计算相似度(两个字符串,全字匹配,算法为余弦定理)
-	 * @param w1
-	 * @param w2
-	 * @return
-	 */
-	public static double getSimilarityWithCosinesByWords(String w1, String w2) {
-		double similarity = 0;
-		int size1 = 0;
-		int size2 = 0;
-		w1 = stringFilter(w1);
-		w2 = stringFilter(w2);
-		if (w1 != null && (size1 = w1.length()) != 0 && w2 != null && (size2 = w2.length()) != 0) {
-			Map<Character, int[]> countMap = new HashMap<Character, int[]>();
-			char index;
-			// 将w1与w2所有字符出现频次统计入countMap中
-			for (int i = 0; i < size1; i++) {
-				index = w1.charAt(i);
-				int[] c = countMap.get(index);
-				if (c != null && c.length == 2) {
-					c[0]++;
-				} else {
-					c = new int[2];
-					c[0] = 1;
-					c[1] = 0;
-					countMap.put(index, c);
-				}
-			}
-			for (int i = 0; i < size2; i++) {
-				index = w2.charAt(i);
-				int[] c = countMap.get(index);
-				if (c != null && c.length == 2) {
-					c[1]++;
-				} else {
-					c = new int[2];
-					c[0] = 0;
-					c[1] = 1;
-					countMap.put(index, c);
-				}
-			}
-			// 根据余弦定理计算相似度
-			Iterator<Character> it = countMap.keySet().iterator();
-			double sum = 0;
-			double s1 = 0;
-			double s2 = 0;
-			while (it.hasNext()) {
-				int[] c = countMap.get(it.next());
-				sum += c[0] * c[1];
-				s1 += c[0] * c[0];
-				s2 += c[1] * c[1];
-			}
-			similarity = sum / Math.sqrt(s1 * s2);
-		} else {
-			throw new NullPointerException("传入的参数为空");
-		}
-		return similarity;
-	}
+    /**
+     * 计算相似度(两个字符串,采用优化Dice算法)
+     * 
+     * @param w1
+     * @param w2
+     * @return
+     */
+    public static double getSimilarityWithDiceOptByWords(String w1, String w2) {
+        if (w1 == null || w2 == null || w1.length() == 0 || w2.length() == 0)
+            return 0;
+        if (w1 == w2)
+            return 1;
+        if (w1.length() == 1 || w2.length() == 1) {
+            if (w1.equals(w2)) {
+                return 1;
+            } else {
+                return 0;
+            }
+        }
+        w1 = stringFilter(w1);
+        w2 = stringFilter(w2);
+        final int n = w1.length() - 1;
+        final int[] sPairs = new int[n];
+        for (int i = 0; i <= n; i++)
+            if (i == 0)
+                sPairs[i] = w1.charAt(i) << 16;
+            else if (i == n)
+                sPairs[i - 1] |= w1.charAt(i);
+            else
+                sPairs[i] = (sPairs[i - 1] |= w1.charAt(i)) << 16;
 
-	/**
-	 * 计算相似度(两个字符串,采用优化Dice算法)
-	 * @param w1
-	 * @param w2
-	 * @return
-	 */
-	public static double getSimilarityWithDiceOptByWords(String w1, String w2) {
-		if (w1 == null || w2 == null || w1.length() == 0 || w2.length() == 0)
-			return 0;
-		if (w1 == w2)
-			return 1;
-		if (w1.length() == 1 || w2.length() == 1){
-			if (w1.equals(w2)) {
-				return 1;
-			} else {
-				return 0;
-			}
-		}
-		w1 = stringFilter(w1);
-		w2 = stringFilter(w2);
-		final int n = w1.length() - 1;
-		final int[] sPairs = new int[n];
-		for (int i = 0; i <= n; i++)
-			if (i == 0)
-				sPairs[i] = w1.charAt(i) << 16;
-			else if (i == n)
-				sPairs[i - 1] |= w1.charAt(i);
-			else
-				sPairs[i] = (sPairs[i - 1] |= w1.charAt(i)) << 16;
+        final int m = w2.length() - 1;
+        final int[] tPairs = new int[m];
+        for (int i = 0; i <= m; i++)
+            if (i == 0)
+                tPairs[i] = w2.charAt(i) << 16;
+            else if (i == m)
+                tPairs[i - 1] |= w2.charAt(i);
+            else
+                tPairs[i] = (tPairs[i - 1] |= w2.charAt(i)) << 16;
 
-		final int m = w2.length() - 1;
-		final int[] tPairs = new int[m];
-		for (int i = 0; i <= m; i++)
-			if (i == 0)
-				tPairs[i] = w2.charAt(i) << 16;
-			else if (i == m)
-				tPairs[i - 1] |= w2.charAt(i);
-			else
-				tPairs[i] = (tPairs[i - 1] |= w2.charAt(i)) << 16;
+        Arrays.sort(sPairs);
+        Arrays.sort(tPairs);
 
-		Arrays.sort(sPairs);
-		Arrays.sort(tPairs);
+        int matches = 0, i = 0, j = 0;
+        while (i < n && j < m) {
+            if (sPairs[i] == tPairs[j]) {
+                matches += 2;
+                i++;
+                j++;
+            } else if (sPairs[i] < tPairs[j])
+                i++;
+            else
+                j++;
+        }
+        return (double) matches / (n + m);
+    }
 
-		int matches = 0, i = 0, j = 0;
-		while (i < n && j < m) {
-			if (sPairs[i] == tPairs[j]) {
-				matches += 2;
-				i++;
-				j++;
-			} else if (sPairs[i] < tPairs[j])
-				i++;
-			else
-				j++;
-		}
-		return (double) matches / (n + m);
-	}
+    /**
+     * 计算相似度(两个字符串,采用一般Dice算法)
+     * 
+     * @param w1
+     * @param w2
+     * @return
+     */
+    public static double getSimilarityWithDiceByWords(String w1, String w2) {
+        double similarity = 0;
+        if (w1 != null && w1.length() != 0 && w2 != null && w2.length() != 0) {
+            if (w1.length() == 1 || w2.length() == 1) {
+                if (w1.equals(w2)) {
+                    return 1;
+                } else {
+                    return 0;
+                }
+            }
+            w1 = stringFilter(w1);
+            w2 = stringFilter(w2);
+            Set<String> nx = new HashSet<String>();
+            Set<String> ny = new HashSet<String>();
 
-	/**
-	 * 计算相似度(两个字符串,采用一般Dice算法)
-	 * @param w1
-	 * @param w2
-	 * @return
-	 */
-	public static double getSimilarityWithDiceByWords(String w1, String w2) {
-		double similarity = 0;
-		if (w1 != null && w1.length() != 0 && w2 != null && w2.length() != 0) {
-			if (w1.length() == 1 || w2.length() == 1){
-				if (w1.equals(w2)) {
-					return 1;
-				} else {
-					return 0;
-				}
-			}
-			w1 = stringFilter(w1);
-			w2 = stringFilter(w2);
-			Set<String> nx = new HashSet<String>();
-			Set<String> ny = new HashSet<String>();
+            for (int i = 0; i < w1.length() - 1; i++) {
+                char x1 = w1.charAt(i);
+                char x2 = w1.charAt(i + 1);
+                String tmp = "" + x1 + x2;
+                nx.add(tmp);
+            }
+            for (int j = 0; j < w2.length() - 1; j++) {
+                char y1 = w2.charAt(j);
+                char y2 = w2.charAt(j + 1);
+                String tmp = "" + y1 + y2;
+                ny.add(tmp);
+            }
+            Set<String> intersection = new HashSet<String>(nx);
+            intersection.retainAll(ny);
+            double totcombigrams = intersection.size();
+            similarity = (2 * totcombigrams) / (nx.size() + ny.size());
+        }
+        return similarity;
+    }
 
-			for (int i = 0; i < w1.length() - 1; i++) {
-				char x1 = w1.charAt(i);
-				char x2 = w1.charAt(i + 1);
-				String tmp = "" + x1 + x2;
-				nx.add(tmp);
-			}
-			for (int j = 0; j < w2.length() - 1; j++) {
-				char y1 = w2.charAt(j);
-				char y2 = w2.charAt(j + 1);
-				String tmp = "" + y1 + y2;
-				ny.add(tmp);
-			}
-			Set<String> intersection = new HashSet<String>(nx);
-			intersection.retainAll(ny);
-			double totcombigrams = intersection.size();
-			similarity = (2 * totcombigrams) / (nx.size() + ny.size());
-		}
-		return similarity;
-	}
+    /**
+     * 过滤特殊字符
+     * 
+     * @param str
+     * @return
+     */
+    public static String stringFilter(String str) {
+        String regEx = "[_`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]";
+        return str.replaceAll("\\s*", "").replaceAll(regEx, "");
 
-	/**
-	 * 过滤特殊字符
-	 * @param str
-	 * @return
-	 */
-	public static String stringFilter(String str) {
-		String regEx = "[_`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]";
-		return str.replaceAll("\\s*", "").replaceAll(regEx, "");
-	}
+    }
 
-	public static void main(String[] args) {
-		String str1 = "秦汉以    来的公文程式构   成有  :::::\n    <><>_________________ !!!!!";
-		String str2 = "明清以来的公文程式构成有";
-//		System.out.println(StringSimilarityUtils.stringFilter(str1));
-//		System.out.println(StringSimilarityUtils.stringFilter(str2));
-//		//double similarity1 = StringSimilarityUtils.getSimilarityWithCosinesBySeg(str1, str2);
-//		double similarity_cos = StringSimilarityUtils.getSimilarityWithCosinesByWords(str1, str2);
-//		double similarity_dice = StringSimilarityUtils.getSimilarityWithDiceByWords(str1, str2);
-//		double similarity_diceopt = StringSimilarityUtils.getSimilarityWithDiceOptByWords(str1, str2);
-//		System.out.println(similarity_cos);
-//		System.out.println(similarity_dice);
-//		System.out.println(similarity_diceopt);
-		System.out.println(segmentText(str2));
-	}
+    public static void main(String[] args) {
+        String str1 = "秦汉以    来的公文程式构   成有  :::::\n    <><>_________________ !!!!!";
+        String str2 = "明清以来的公文程式构成有";
+        // System.out.println(StringSimilarityUtils.stringFilter(str1));
+        // System.out.println(StringSimilarityUtils.stringFilter(str2));
+        // //double similarity1 =
+        // StringSimilarityUtils.getSimilarityWithCosinesBySeg(str1, str2);
+        // double similarity_cos =
+        // StringSimilarityUtils.getSimilarityWithCosinesByWords(str1, str2);
+        // double similarity_dice =
+        // StringSimilarityUtils.getSimilarityWithDiceByWords(str1, str2);
+        // double similarity_diceopt =
+        // StringSimilarityUtils.getSimilarityWithDiceOptByWords(str1, str2);
+        // System.out.println(similarity_cos);
+        // System.out.println(similarity_dice);
+        // System.out.println(similarity_diceopt);
+        System.out.println(segmentText(str2));
+    }
 }

+ 14 - 0
cqb-comm-utils/src/main/java/com/qmth/cqb/utils/exception/PaperException.java

@@ -0,0 +1,14 @@
+package com.qmth.cqb.utils.exception;
+
+/**
+ * Created by songyue on 17/5/2.
+ */
+public class PaperException extends Exception{
+    private static final long serialVersionUID = 8857929143713319678L;
+
+    public PaperException(){super();}
+
+    public PaperException(String message) {
+        super(message);
+    }
+}

+ 15 - 0
cqb-comm-utils/src/main/java/com/qmth/cqb/utils/exception/QuesException.java

@@ -0,0 +1,15 @@
+package com.qmth.cqb.utils.exception;
+
+/**
+ * Created by songyue on 17/5/2.
+ */
+public class QuesException extends Exception{
+
+    private static final long serialVersionUID = -2651610766615418315L;
+
+    public QuesException(){super();}
+
+    public QuesException(String message) {
+        super(message);
+    }
+}

+ 247 - 170
cqb-comm-utils/src/main/java/com/qmth/cqb/utils/word/DocxProcessUtil.java

@@ -25,12 +25,15 @@ import org.docx4j.dml.wordprocessingDrawing.Inline;
 import org.docx4j.finders.ClassFinder;
 import org.docx4j.jaxb.Context;
 import org.docx4j.math.CTOMath;
+import org.docx4j.math.CTOMathPara;
 import org.docx4j.openpackaging.exceptions.Docx4JException;
 import org.docx4j.openpackaging.io3.stores.PartStore;
+import org.docx4j.openpackaging.io3.stores.ZipPartStore;
 import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
 import org.docx4j.openpackaging.parts.Part;
 import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
 import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
+import org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart;
 import org.docx4j.openpackaging.parts.relationships.Namespaces;
 import org.docx4j.openpackaging.parts.relationships.RelationshipsPart;
 import org.docx4j.relationships.Relationship;
@@ -53,6 +56,8 @@ import javax.xml.transform.stream.StreamResult;
 import javax.xml.transform.stream.StreamSource;
 import java.io.*;
 import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * docx处理工具类 Created by songyue on 17/3/10.
@@ -127,13 +132,14 @@ public final class DocxProcessUtil {
      * @param p
      * @return
      */
-    public static boolean isNotText(P p) {
+    public static boolean isText(P p) {
         List<Object> mathList = getAllElementFromObject(p, CTOMath.class);
+        List<Object> mathParaList = getAllElementFromObject(p, CTOMathPara.class);
         List<Object> drawList = getAllElementFromObject(p, Drawing.class);
-        if (mathList.size() > 0 || drawList.size() > 0) {
-            return true;
-        } else {
+        if (mathParaList.size() > 0 || mathList.size() > 0 || drawList.size() > 0) {
             return false;
+        } else {
+            return true;
         }
     }
 
@@ -271,6 +277,11 @@ public final class DocxProcessUtil {
                         "http://schemas.openxmlformats.org/officeDocument/2006/math", "oMath", CTOMath.class);
                 byte[] imgByte = convertMathml2Img(omml2mml(omml));
                 pContent.set(index, newImage(wordMLPackage, imgByte, "math" + (index), "math" + (index)));
+            }else if(child.getClass().equals(CTOMathPara.class)){
+                String omml = XmlUtils.marshaltoString(child, true, true, Context.jc,
+                        "http://schemas.openxmlformats.org/officeDocument/2006/math", "oMathPara", CTOMathPara.class);
+                byte[] imgByte = convertMathml2Img(omml2mml(omml));
+                pContent.set(index, newImage(wordMLPackage, imgByte, "math" + (index), "math" + (index)));
             }
             index++;
         }
@@ -335,30 +346,25 @@ public final class DocxProcessUtil {
      * @param omml
      * @return
      */
-    public static String omml2mml(String omml) {
+    public static String omml2mml(String omml)throws Exception {
         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-        InputStream stylesheet = ClassLoader.getSystemResourceAsStream(OMML2MML_XSL);
+        InputStream stylesheet = DocxProcessUtil.class.getClassLoader().getResourceAsStream(OMML2MML_XSL);
         StringReader sr = new StringReader(omml);
         InputSource ommldata = new InputSource(sr);
         StringWriter writer = new StringWriter();
         org.w3c.dom.Document document = null;
         DocumentBuilder builder = null;
         Transformer transformer = null;
-        try {
-            builder = factory.newDocumentBuilder();
-            document = builder.parse(ommldata);
-            TransformerFactory tFactory = new TransformerFactoryImpl();
-            StreamSource stylesource = new StreamSource(stylesheet);
-            transformer = tFactory.newTransformer(stylesource);
-            DOMSource source = new DOMSource(document);
-            StreamResult result = new StreamResult(writer);
-            transformer.transform(source, result);
-        } catch (Exception e) {
-            e.printStackTrace();
-        } finally {
-            IOUtils.closeQuietly(sr);
-            IOUtils.closeQuietly(writer);
-        }
+        builder = factory.newDocumentBuilder();
+        document = builder.parse(ommldata);
+        TransformerFactory tFactory = new TransformerFactoryImpl();
+        StreamSource stylesource = new StreamSource(stylesheet);
+        transformer = tFactory.newTransformer(stylesource);
+        DOMSource source = new DOMSource(document);
+        StreamResult result = new StreamResult(writer);
+        transformer.transform(source, result);
+        IOUtils.closeQuietly(sr);
+        IOUtils.closeQuietly(writer);
         String mml = writer.toString();
         mml = ("<mml:math" + StringUtils.substringAfter(mml, "<mml:math")).replace("mml:", "");
         return mml;
@@ -370,25 +376,20 @@ public final class DocxProcessUtil {
      * @param htmlStr
      * @return
      */
-    public static String formatHtml(String htmlStr) {
-        try {
-            org.jsoup.nodes.Document doc = Jsoup.parse(htmlStr);
-            Elements divs = doc.select("div[class='document");
-            doc.select("p").removeAttr("class").removeAttr("style");
-            doc.select("div").removeAttr("class").removeAttr("style");
-            doc.select("span").removeAttr("class").removeAttr("style");
-            doc.select("span").stream().forEach(element -> {
-                if (!element.hasText())
-                    element.remove();
-            });
-            if (divs.size() > 0) {
-                htmlStr = divs.html();
-            } else {
-                htmlStr = doc.html();
-            }
-            return htmlStr;
-        } catch (Exception e) {
-            e.printStackTrace();
+    public static String formatHtml(String htmlStr) throws Exception {
+        org.jsoup.nodes.Document doc = Jsoup.parse(htmlStr);
+        Elements divs = doc.select("div[class='document");
+        doc.select("p").removeAttr("class").removeAttr("style");
+        doc.select("div").removeAttr("class").removeAttr("style");
+        doc.select("span").removeAttr("class").removeAttr("style");
+        doc.select("span").stream().forEach(element -> {
+            if (!element.hasText())
+                element.remove();
+        });
+        if (divs.size() > 0) {
+            htmlStr = divs.html();
+        } else {
+            htmlStr = doc.html();
         }
         return htmlStr;
     }
@@ -399,7 +400,7 @@ public final class DocxProcessUtil {
      * @param htmlStr
      * @return
      */
-    public static String getTextInHtml(String htmlStr) {
+    public static String getTextInHtml(String htmlStr){
         try {
             org.jsoup.nodes.Document doc = Jsoup.parse(htmlStr);
             String textStr = "";
@@ -420,37 +421,31 @@ public final class DocxProcessUtil {
      * @param htmlPath
      * @return
      */
-    public static String formatHtmlByPath(String htmlPath) {
+    public static String formatHtmlByPath(String htmlPath) throws Exception {
         String htmlStr = "";
-        File htmlFile;
-        try {
-            htmlFile = new File(htmlPath);
-            org.jsoup.nodes.Document doc = Jsoup.parse(htmlFile, ENCODING);
-            Elements divs = doc.select("div[class='document']");
-            doc.select("p").removeAttr("class").removeAttr("style");
-            doc.select("div").removeAttr("class").removeAttr("style");
-            doc.select("span").removeAttr("class").removeAttr("style");
-            doc.select("span").stream().forEach(element -> {
-                if (!element.hasText() && element.childNodeSize() == 0) {
-                    element.remove();
-                }
-            });
-            Elements imgs = doc.select("img");
-            for (org.jsoup.nodes.Element img : imgs) {
-                String imgSrc = img.attr("src");
-                if (!StringUtils.isEmpty(imgSrc)) {
-                    String imgBase64 = new String(getBase64ByPath(htmlFile.getParent() + "/" + imgSrc));
-                    img.attr("src", BASE64_HEADER + imgBase64);
-                }
+        File htmlFile = new File(htmlPath);
+        org.jsoup.nodes.Document doc = Jsoup.parse(htmlFile, ENCODING);
+        Elements divs = doc.select("div[class='document']");
+        doc.select("p").removeAttr("class").removeAttr("style");
+        doc.select("div").removeAttr("class").removeAttr("style");
+        doc.select("span").removeAttr("class").removeAttr("style");
+        doc.select("span").stream().forEach(element -> {
+            if (!element.hasText() && element.childNodeSize() == 0) {
+                element.remove();
             }
-            if (divs.size() > 0) {
-                htmlStr = divs.html();
-            } else {
-                htmlStr = doc.html();
+        });
+        Elements imgs = doc.select("img");
+        for (org.jsoup.nodes.Element img : imgs) {
+            String imgSrc = img.attr("src");
+            if (!StringUtils.isEmpty(imgSrc)) {
+                String imgBase64 = new String(getBase64ByPath(htmlFile.getParent() + "/" + imgSrc));
+                img.attr("src", BASE64_HEADER + imgBase64);
             }
-            return htmlStr;
-        } catch (Exception e) {
-            e.printStackTrace();
+        }
+        if (divs.size() > 0) {
+            htmlStr = divs.html();
+        } else {
+            htmlStr = doc.html();
         }
         return htmlStr;
     }
@@ -461,26 +456,21 @@ public final class DocxProcessUtil {
      * @param mathMlStr
      * @return
      */
-    public static byte[] convertMathml2Img(String mathMlStr) {
+    public static byte[] convertMathml2Img(String mathMlStr) throws Exception {
         File xmlFile = null;
         File imgFile = null;
         FileOutputStream xmlFos = null;
         byte[] base64Byte = new byte[0];
-        try {
-            xmlFile = new File(TEMP_FILE_IMP, UUID.randomUUID().toString());
-            imgFile = new File(TEMP_FILE_IMP, UUID.randomUUID().toString());
-            xmlFos = new FileOutputStream(xmlFile);
-            IOUtils.write(mathMlStr, xmlFos, ENCODING);
-            xmlFos.flush();
-            Converter.getInstance().convert(xmlFile, imgFile, IMG_OUT_TYPE, IMG_LAYOUT);
-            base64Byte = IOUtils.toByteArray(new FileInputStream(imgFile));
-        } catch (Exception e) {
-            e.printStackTrace();
-        } finally {
-            IOUtils.closeQuietly(xmlFos);
-            FileUtils.deleteQuietly(xmlFile);
-            FileUtils.deleteQuietly(imgFile);
-        }
+        xmlFile = new File(TEMP_FILE_IMP, UUID.randomUUID().toString());
+        imgFile = new File(TEMP_FILE_IMP, UUID.randomUUID().toString());
+        xmlFos = new FileOutputStream(xmlFile);
+        IOUtils.write(mathMlStr, xmlFos, ENCODING);
+        xmlFos.flush();
+        Converter.getInstance().convert(xmlFile, imgFile, IMG_OUT_TYPE, IMG_LAYOUT);
+        base64Byte = IOUtils.toByteArray(new FileInputStream(imgFile));
+        IOUtils.closeQuietly(xmlFos);
+        FileUtils.deleteQuietly(xmlFile);
+        FileUtils.deleteQuietly(imgFile);
         return base64Byte;
     }
 
@@ -490,21 +480,16 @@ public final class DocxProcessUtil {
      * @param imgFilePath
      * @return
      */
-    public static byte[] getBase64ByPath(String imgFilePath) {
+    public static byte[] getBase64ByPath(String imgFilePath) throws Exception {
         InputStream is = null;
         byte[] base64Byte = new byte[0];
         byte[] imgByte;
         File imgFile = new File(imgFilePath);
-        try {
-            is = new FileInputStream(imgFile);
-            imgByte = IOUtils.toByteArray(is);
-            base64Byte = Base64.encodeBase64(imgByte);
-        } catch (Exception e) {
-            e.printStackTrace();
-        } finally {
-            IOUtils.closeQuietly(is);
-            FileUtils.deleteQuietly(imgFile);
-        }
+        is = new FileInputStream(imgFile);
+        imgByte = IOUtils.toByteArray(is);
+        base64Byte = Base64.encodeBase64(imgByte);
+        IOUtils.closeQuietly(is);
+        FileUtils.deleteQuietly(imgFile);
         return base64Byte;
     }
 
@@ -514,19 +499,14 @@ public final class DocxProcessUtil {
      * @param imgFile
      * @return
      */
-    public static byte[] getBase64ByFile(File imgFile) {
+    public static byte[] getBase64ByFile(File imgFile) throws Exception {
         InputStream is = null;
         byte[] base64Byte = new byte[0];
         byte[] imgByte;
-        try {
-            is = new FileInputStream(imgFile);
-            imgByte = IOUtils.toByteArray(is);
-            base64Byte = Base64.encodeBase64(imgByte);
-        } catch (Exception e) {
-            e.printStackTrace();
-        } finally {
-            IOUtils.closeQuietly(is);
-        }
+        is = new FileInputStream(imgFile);
+        imgByte = IOUtils.toByteArray(is);
+        base64Byte = Base64.encodeBase64(imgByte);
+        IOUtils.closeQuietly(is);
         return base64Byte;
     }
 
@@ -560,7 +540,6 @@ public final class DocxProcessUtil {
     public static P formatP(P p, QuesUnit quesUnit) {
         List<Object> pContent = p.getContent();
         int index = 0;
-
         for (Object child : pContent) {
             if (child.getClass().equals(R.class)) {
 
@@ -569,54 +548,60 @@ public final class DocxProcessUtil {
 
                 for (Object rChild : rContent) {
 
-                    rChild = ((JAXBElement<?>) rChild).getValue();
+                    if (rChild instanceof JAXBElement)
+                        rChild = ((JAXBElement<?>) rChild).getValue();
 
                     if (rChild.getClass().equals(Text.class)) {
                         ++index;
                         Text text = (Text) rChild;
                         String tmpText = text.getValue();
                         if (quesUnit == QuesUnit.QUES_BODY) {
+
                             // 过滤题干标题
                             if (tmpText.matches("^\\d{1,}\\.[\\s\\S]*")) {
-                                tmpText = tmpText.replaceFirst("\\d{1,}\\.", "");
-                                text.setValue(tmpText);
-                            } else {
-                                if (index == 1) {
-                                    tmpText = tmpText.replaceFirst("\\d{1,}", "");
-                                } else if (index == 2) {
-                                    tmpText = tmpText.replaceFirst("\\.", "");
-                                }
-                                text.setValue(tmpText);
                                 if (index == 2) {
-                                    break;
+                                    return p;
                                 }
+                                tmpText = tmpText.replaceFirst("\\d{1,}\\.","");
+                                text.setValue(tmpText);
+                            } else if(tmpText.matches("^\\d{1,}$")){
+                                text.setValue("");
+                            } else if(tmpText.contains(".")){
+                                text.setValue("");
+                                return p;
                             }
 
                         } else if (quesUnit == QuesUnit.QUES_OPTION) {
+
                             // 过滤选项标题
                             if (tmpText.matches("^[A-Z]\\.[\\s\\S]*")) {
-                                tmpText = tmpText.replaceFirst("[A-Z]\\.", "");
-                                text.setValue(tmpText);
-                            } else {
-                                if (index == 1) {
-                                    tmpText = tmpText.replaceFirst("[A-Z]", "");
-                                } else if (index == 2) {
-                                    tmpText = tmpText.replaceFirst("\\.", "");
-                                }
-                                text.setValue(tmpText);
                                 if (index == 2) {
-                                    break;
+                                    return p;
                                 }
+                                tmpText = tmpText.replaceFirst("[A-Z]\\.","");
+                                text.setValue(tmpText);
+                            } else if(tmpText.matches("^[A-Z]$")){
+                                text.setValue("");
+                            } else if(tmpText.contains(".")){
+                                text.setValue("");
+                                return p;
                             }
 
                         } else if (quesUnit == QuesUnit.QUES_ANSWER) {
+
                             // 过滤答案标题
-                            if (index <= 4) {
-                                tmpText = tmpText.replaceFirst("\\[", "").replaceFirst("\\]", "").replaceFirst("答案", "")
-                                        .replaceFirst("[:|:]", "");
-                                text.setValue(tmpText);
+                            if(tmpText.contains(":") || tmpText.contains(":")){
+                                if(tmpText.startsWith(":") || tmpText.startsWith(":")){
+                                    tmpText = tmpText.replaceFirst("[:|:]","");
+                                    text.setValue(tmpText);
+                                }else{
+                                    tmpText = tmpText.replaceFirst("\\[","").replaceFirst("\\]","").replaceFirst("答案","");
+                                    text.setValue(tmpText);
+                                }
+                                return p;
                             } else {
-                                break;
+                                tmpText = tmpText.replaceFirst("\\[","").replaceFirst("\\]","").replaceFirst("答案","");
+                                text.setValue(tmpText);
                             }
                         }
                     }
@@ -632,32 +617,27 @@ public final class DocxProcessUtil {
      * @param dataMap
      * @param fileName
      */
-    public static void exportWord(Map dataMap, String fileName, String templatePath) {
+    public static void exportWord(Map dataMap, String fileName, String templatePath)throws Exception {
         Writer out = null;
-        try {
-            // 创建配置实例
-            Configuration configuration = new Configuration(Configuration.VERSION_2_3_25);
-            // 设置编码
-            configuration.setDefaultEncoding("UTF-8");
-            // 设置ftl模板路径
-            configuration.setClassForTemplateLoading(DocxProcessUtil.class, "/");
-            // 获取模板
-            Template template = configuration.getTemplate(templatePath, ENCODING);
-            // 输出文件
-            File outFile = new File(TEMP_FILE_EXP + fileName + DOCX_SUFFIX);
-
-            // 将模板和数据模型合并生成文件
-            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), ENCODING));
-            // 生成文件
-            template.process(dataMap, out);
-
-            out.flush();
-
-        } catch (Exception e) {
-            e.printStackTrace();
-        } finally {
-            IOUtils.closeQuietly(out);
-        }
+        // 创建配置实例
+        Configuration configuration = new Configuration(Configuration.VERSION_2_3_25);
+        // 设置编码
+        configuration.setDefaultEncoding("UTF-8");
+        // 设置ftl模板路径
+        configuration.setClassForTemplateLoading(DocxProcessUtil.class, "/");
+        // 获取模板
+        Template template = configuration.getTemplate(templatePath, ENCODING);
+        // 输出文件
+        File outFile = new File(TEMP_FILE_EXP + fileName + DOCX_SUFFIX);
+
+        // 将模板和数据模型合并生成文件
+        out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), ENCODING));
+        // 生成文件
+        template.process(dataMap, out);
+
+        out.flush();
+
+        IOUtils.closeQuietly(out);
     }
 
     /**
@@ -666,7 +646,7 @@ public final class DocxProcessUtil {
      * @param dataMap
      * @param fileName
      */
-    public static void exportPaper(Map dataMap, String fileName) {
+    public static void exportPaper(Map dataMap, String fileName) throws Exception {
         exportWord(dataMap, fileName, PAPER_TEMPLATE);
     }
 
@@ -676,7 +656,7 @@ public final class DocxProcessUtil {
      * @param dataMap
      * @param fileName
      */
-    public static void exportAnswer(Map dataMap, String fileName) {
+    public static void exportAnswer(Map dataMap, String fileName) throws Exception {
         exportWord(dataMap, fileName, ANSWER_TEMPLATE);
     }
 
@@ -694,10 +674,12 @@ public final class DocxProcessUtil {
         // 以单个wordXml方式解析freemarker导出的文件
         FlatOpcXmlImporter flatOpcXmlImporter = new FlatOpcXmlImporter(mainFile);
         WordprocessingMLPackage wordMLPackage = (WordprocessingMLPackage) flatOpcXmlImporter.get();
+        RelationshipsPart relationshipsPart = wordMLPackage.getMainDocumentPart().getRelationshipsPart();
 
         for (WordprocessingMLPackage wp : wordMLPackages) {
+
             // 获取资源文件存储
-            PartStore partStore = wp.getSourcePartStore();
+            ZipPartStore partStore = (ZipPartStore) wp.getSourcePartStore();
             // 获取图片资源定义
             RelationshipsPart rp = wp.getMainDocumentPart().getRelationshipsPart();
             List<Relationship> rels = rp.getRelationshipsByType(Namespaces.IMAGE);
@@ -706,13 +688,15 @@ public final class DocxProcessUtil {
             for (Relationship relationship : rels) {
                 parts.add(rp.getPart(relationship));
             }
-            // 添加资源文件存储
-            wordMLPackage.setSourcePartStore(partStore);
             // 添加资源文件定义
             for (Part p : parts) {
-                wordMLPackage.getMainDocumentPart().addTargetPart(p, RelationshipsPart.AddPartBehaviour.REUSE_EXISTING,
-                        p.getSourceRelationship().getId());
+                String relId = p.getSourceRelationships().get(0).getId();
+                if(!relationshipsPart.isRelIdOccupied(relId)){
+                    copyImage(wordMLPackage,partStore,p);
+                }
             }
+            // 添加资源文件存储
+//            wordMLPackage.setSourcePartStore(partStore);
         }
         // 以word2007标准模式重新保存(zip包)
         OutputStream os = new java.io.FileOutputStream(filePath);
@@ -720,6 +704,19 @@ public final class DocxProcessUtil {
         IOUtils.closeQuietly(os);
     }
 
+    /**
+     * word合并时复制图片
+     * @param wordMLPackage
+     * @param partStore
+     * @param p
+     * @throws Exception
+     */
+    public static void copyImage(WordprocessingMLPackage wordMLPackage, ZipPartStore partStore, Part p)throws Exception{
+        byte [] bytes = partStore.getByteArray(p.getPartName().getName().substring(1)).getBytes();
+        BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes);
+        imagePart.getRelLast().setId(p.getSourceRelationships().get(0).getId());
+    }
+
     /**
      * 获取word二进制数据(空文档,只有样式和资源)
      *
@@ -774,15 +771,14 @@ public final class DocxProcessUtil {
                 .getRelationshipsByType(Namespaces.IMAGE);
         // 同步替换资源ID
         int index = 0;
-        String rldHeader = getRldNum();
         for (Relationship relationship : relationships) {
             String tmpId = relationship.getId();
+            String tmp = getRldNum() + (++index);
             for (Object obj : blips) {
                 if (obj.getClass().equals(CTBlip.class)) {
                     CTBlip ctBlip = (CTBlip) obj;
                     String tmpEmbed = ctBlip.getEmbed();
                     if (tmpId.equals(tmpEmbed)) {
-                        String tmp = rldHeader + (++index);
                         relationship.setId(tmp);
                         ctBlip.setEmbed(tmp);
                     }
@@ -824,20 +820,101 @@ public final class DocxProcessUtil {
      * @return
      * @throws Exception
      */
-    public static String html2Docx(WordprocessingMLPackage wordMLPackage,String html)throws Exception{
-        initPkgImage(wordMLPackage);
+    public static String html2Docx(WordprocessingMLPackage wordMLPackage,String html)throws Exception {
+        initTmpPackage(wordMLPackage);
         XHTMLImporterImpl XHTMLImporter = new XHTMLImporterImpl(wordMLPackage);
         String wordMl = "";
         wordMLPackage.getMainDocumentPart().getContent().addAll(
-                    XHTMLImporter.convert( html, null) );
+                    XHTMLImporter.convert( repairHtmlStr(html), null) );
         // 获取word文档中所有段落
         List<Object> pList = getAllElementFromObject(wordMLPackage.getMainDocumentPart(), P.class);
         for(Object p:pList){
             wordMl += XmlUtils.marshaltoString(p);
         }
 //            wordMl = formatPWordMl(wordMl);
+        initPkgImage(wordMLPackage);
         return wordMl;
     }
 
+    public static String repairHtmlStr(String htmlStr){
+        htmlStr = htmlStr.trim();
+        if(htmlStr.toLowerCase().contains("<!doctype html ")){
+            int index1 = htmlStr.toLowerCase().indexOf("<!doctype html ");
+            int index2 = htmlStr.indexOf('>',index1 + 1);
+            htmlStr = htmlStr.substring(0, index1) + htmlStr.substring(index2 + 1);
+        }
+        while(htmlStr.toLowerCase().contains("<br ")){
+            int index1 = htmlStr.toLowerCase().indexOf("<br ");
+            int index2 = htmlStr.toLowerCase().indexOf(">",index1 + 1);
+            htmlStr = htmlStr.substring(0, index1) + "<br/>" + htmlStr.substring(index2 + 1);
+        }
+        while(htmlStr.toLowerCase().endsWith("<br>") || htmlStr.toLowerCase().endsWith("<br/>")){
+            if(htmlStr.toLowerCase().endsWith("<br>")){
+                htmlStr = htmlStr.substring(0, htmlStr.length()-"<br>".length());
+            }else if(htmlStr.toLowerCase().endsWith("<br/>")){
+                htmlStr = htmlStr.substring(0, htmlStr.length()-"<br/>".length());
+            }
+        }
+        htmlStr = htmlStr.replace("<br>", "<br/>").replace("<BR>", "<br/>");
+
+        {//补全META标签
+            int imgIndex = indexOfRegex(htmlStr,"<((meta)|(META)) ");
+            while(imgIndex > 0){
+                int flag = htmlStr.indexOf(">", imgIndex);
+                if(htmlStr.charAt(flag - 1) != '/'){
+                    htmlStr = htmlStr.substring(0,flag) + "/" + htmlStr.substring(flag);
+                }
+                imgIndex = indexOfRegex(htmlStr,"<((meta)|(META)) ",flag);
+            }
+        }
 
+        {//补全img标签
+            int imgIndex = indexOfRegex(htmlStr,"<((img)|(IMG)) ");
+            while(imgIndex > 0){
+                int flag = htmlStr.indexOf(">", imgIndex);
+                if(htmlStr.charAt(flag - 1) != '/'){
+                    htmlStr = htmlStr.substring(0,flag) + "/" + htmlStr.substring(flag);
+                }
+                imgIndex = indexOfRegex(htmlStr,"<((img)|(IMG)) ",flag);
+            }
+        }
+        return htmlStr;
+    }
+
+    /**
+     * 从指定的位置开始查找第一个匹配正则表达式的字符串的位置
+     * @param str
+     * @param regex 正则表达式
+     * @param fromIndex 指定的起始位置
+     * @return
+     */
+    public static int indexOfRegex(String str,String regex,int fromIndex){
+        int index = indexOfRegex(str.substring(fromIndex),regex);
+        if(index < 0){
+            return -1;
+        }
+        return fromIndex + index;
+    }
+
+    /**
+     * 查找第一个匹配正则表达式的字符串的位置
+     * @param str
+     * @param regex 正则表达式
+     * @return
+     */
+    public static int indexOfRegex(String str,String regex){
+        Pattern p = Pattern.compile(regex);
+        Matcher m = p.matcher(str);
+        if(m.find()){
+            return m.start();
+        }else{
+            return -1;
+        }
+    }
+
+    public static void main(String[] args) {
+        for(QuesUnit quesUnit:QuesUnit.values()){
+            System.out.println(quesUnit.name()+"  "+quesUnit.getName());
+        }
+    }
 }

+ 3 - 2
cqb-paper/src/main/java/com/qmth/cqb/paper/dao/PaperRepo.java

@@ -21,8 +21,9 @@ public interface PaperRepo extends MongoRepository<Paper, String>, QueryByExampl
 
     Page<Paper> findByPaperStatus(PaperStatus paperStatus, Pageable pageable);
 
-    Paper findByName(String name);
+    List<Paper> findByNameAndOrgId(String name, String orgId);
 
-    Page<Paper> findByIdNotInAndCourseNoAndOrgId(Set<String> idSet, String courseNo, String orgId, Pageable page);
+    Page<Paper> findByIdNotInAndCourseNoAndOrgIdAndPaperType(Set<String> idSet, String courseNo, String orgId,
+            PaperType paperType, Pageable page);
 
 }

+ 30 - 27
cqb-paper/src/main/java/com/qmth/cqb/paper/model/PaperDetailUnit.java

@@ -1,15 +1,17 @@
 package com.qmth.cqb.paper.model;
 
-import cn.com.qmth.examcloud.common.dto.question.enums.QuesStructType;
-import com.qmth.cqb.question.model.Question;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.mapping.DBRef;
-
 import java.io.Serializable;
 import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.DBRef;
+
+import com.qmth.cqb.question.model.Question;
+
+import cn.com.qmth.examcloud.common.dto.question.enums.QuesStructType;
+
 public class PaperDetailUnit implements Serializable, Comparable<PaperDetailUnit> {
 
     private static final long serialVersionUID = -8854150484922002075L;
@@ -26,7 +28,7 @@ public class PaperDetailUnit implements Serializable, Comparable<PaperDetailUnit
 
     private Double score;// 小题分数
 
-    private List<Double> subScoreList;//对应套题的情况下,各子题的分数分布
+    private List<Double> subScoreList;// 对应套题的情况下,各子题的分数分布
 
     @DBRef
     private PaperDetail paperDetail;// 关联的大题
@@ -35,11 +37,10 @@ public class PaperDetailUnit implements Serializable, Comparable<PaperDetailUnit
 
     @DBRef
     private Question question;// 关联试题
-    
+
     /**
-     * 选择题下option的排序,按照number排序
-     * 一般:4,2,3,1
-     * 套题下的选择题:1,2,3,4;2,3,4,1;3,2,1,4  题与题之间按分号";"分隔
+     * 选择题下option的排序,按照number排序 一般:4,2,3,1 套题下的选择题:1,2,3,4;2,3,4,1;3,2,1,4
+     * 题与题之间按分号";"分隔
      */
     private String optionOrder;
 
@@ -77,20 +78,20 @@ public class PaperDetailUnit implements Serializable, Comparable<PaperDetailUnit
 
     public void setScore(Double score) {
         this.score = score;
-        //非套题或试题未设置时,不做额外处理
+        // 非套题或试题未设置时,不做额外处理
         if (questionType != QuesStructType.NESTED_ANSWER_QUESTION || question == null) {
             return;
         }
-        //当前分数设置为空时,同时设置子题分数为空
+        // 当前分数设置为空时,同时设置子题分数为空
         if (score == null) {
             subScoreList = null;
             return;
         }
-        //总分与子题分数之和相同,则不做额外处理
+        // 总分与子题分数之和相同,则不做额外处理
         if (subScoreList != null && subScoreList.size() > 0 && getSubScoreSum() == score) {
             return;
         }
-        //根据试题与总分设置情况重置子题分数
+        // 根据试题与总分设置情况重置子题分数
         if (question.getSubQuestions() != null) {
             initSubScoreList(score, question.getSubQuestions());
         }
@@ -118,20 +119,20 @@ public class PaperDetailUnit implements Serializable, Comparable<PaperDetailUnit
 
     public void setQuestion(Question question) {
         this.question = question;
-        //非套题或总分未设置时,不做额外处理
+        // 非套题或总分未设置时,不做额外处理
         if (questionType != QuesStructType.NESTED_ANSWER_QUESTION || score == null) {
             return;
         }
-        //当前试题或子题列表为空时,同时设置子题分数为空
+        // 当前试题或子题列表为空时,同时设置子题分数为空
         if (question == null || question.getSubQuestions() == null) {
             subScoreList = null;
             return;
         }
-        //当前试题子题数量与子题分数数量相同,不做额外处理
+        // 当前试题子题数量与子题分数数量相同,不做额外处理
         if (subScoreList != null && subScoreList.size() == question.getSubQuestions().size()) {
             return;
         }
-        //根据试题与总分设置情况重置子题分数
+        // 根据试题与总分设置情况重置子题分数
         initSubScoreList(score, question.getSubQuestions());
     }
 
@@ -155,19 +156,22 @@ public class PaperDetailUnit implements Serializable, Comparable<PaperDetailUnit
         return subScoreList;
     }
 
-	public String getOptionOrder() {
-		return optionOrder;
-	}
+    public String getOptionOrder() {
+        return optionOrder;
+    }
 
-	public void setOptionOrder(String optionOrder) {
-		this.optionOrder = optionOrder;
-	}
+    public void setOptionOrder(String optionOrder) {
+        this.optionOrder = optionOrder;
+    }
 
-	public void setSubScoreList(List<Double> subScoreList) {
+    public void setSubScoreList(List<Double> subScoreList) {
         this.subScoreList = subScoreList;
         if (subScoreList != null) {
             double totalScore = 0;
             for (Double score : subScoreList) {
+                if (score == null) {
+                    score = 0d;
+                }
                 totalScore += score;
             }
             this.score = totalScore;
@@ -190,8 +194,7 @@ public class PaperDetailUnit implements Serializable, Comparable<PaperDetailUnit
     }
 
     /**
-     * 根据预设总分自动拆解套题子题的分数分布
-     * 目前采取均分后累加到最后一题的做法
+     * 根据预设总分自动拆解套题子题的分数分布 目前采取均分后累加到最后一题的做法
      *
      * @param totalScore
      * @param questionList

+ 135 - 46
cqb-paper/src/main/java/com/qmth/cqb/paper/service/ExportPaperService.java

@@ -15,7 +15,9 @@ import com.qmth.cqb.question.model.QuesOption;
 import com.qmth.cqb.question.model.Question;
 import com.qmth.cqb.utils.BeanCopierUtil;
 import com.qmth.cqb.utils.CommonUtils;
+import com.qmth.cqb.utils.exception.PaperException;
 import com.qmth.cqb.utils.word.DocxProcessUtil;
+import org.apache.commons.lang3.StringUtils;
 import org.docx4j.XmlUtils;
 import org.docx4j.jaxb.Context;
 import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
@@ -25,6 +27,7 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import javax.servlet.http.HttpServletResponse;
+import javax.xml.bind.JAXBElement;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -63,7 +66,7 @@ public class ExportPaperService {
      * @param id
      * @return
      */
-    public Map initExportPaper(String id)throws Exception{
+    public Map initExportPaper(String id) throws Exception{
         //创建返回Map
         Map returnMap = new HashMap();
         //获取paper
@@ -72,8 +75,7 @@ public class ExportPaperService {
         paperService.formatPaper(paper,null);
 
         if(paper == null){
-            returnMap.put("errorInfo","该试卷不存在");
-            return returnMap;
+            throw new PaperException("该试卷不存在");
         }
 
         //创建paperDto
@@ -119,36 +121,27 @@ public class ExportPaperService {
      * 导出试卷
      * @param id
      */
-    public String exportPaper(String id) throws Exception {
+    public void exportPaper(String id) throws Exception {
         Map dataMap = initExportPaper(id);
-        if(dataMap.get("errorInfo")!=null){
-            return (String)dataMap.get("errorInfo");
+        if(dataMap.get("fileName") != null){
+            String fileName = (String)dataMap.get("fileName");
+            DocxProcessUtil.exportPaper(dataMap,fileName);
+            DocxProcessUtil.processImage(fileName,getPkgList(id));
         }
-        String fileName = (String)dataMap.get("fileName");
-        DocxProcessUtil.exportPaper(dataMap,fileName);
-        DocxProcessUtil.processImage(fileName,getPkgList(id));
-        return "success";
     }
 
     /**
      * 下载试卷
      * @param id
      */
-    public Map downloadPaper(String id, HttpServletResponse response){
-        Map dataMap = null;
-        try {
-            dataMap = initExportPaper(id);
-            if(dataMap.get("errorInfo")!=null){
-                return dataMap;
-            }
-            String fileName = (String)dataMap.get("fileName");
-            DocxProcessUtil.exportPaper(dataMap,fileName);
-            DocxProcessUtil.processImage(fileName,getPkgList(id));
-            DocxProcessUtil.processDownload(fileName,response);
-        } catch (Exception e) {
-            e.printStackTrace();
+    public void downloadPaper(String id, HttpServletResponse response) throws Exception {
+        Map dataMap = initExportPaper(id);
+        if (dataMap.get("fileName") != null) {
+            String fileName = (String) dataMap.get("fileName");
+            DocxProcessUtil.exportPaper(dataMap, fileName);
+            DocxProcessUtil.processImage(fileName, getPkgList(id));
+            DocxProcessUtil.processDownload(fileName, response);
         }
-        return dataMap;
     }
 
     /**
@@ -177,25 +170,33 @@ public class ExportPaperService {
                     int index = 0;
                     for(QuesOption quesOption:optionList){
                         quesOption.setOptionBodyWord(setOptionNum(quesOption.getOptionBodyWord(),getOptionNum(index)));
+                        index++;
                     }
                 }
                 List<Question> subQuesList = paperDetailUnit.getQuestion().getSubQuestions();
+                Question question = paperDetailUnit.getQuestion();
                 //套题序号
                 if(subQuesList != null && subQuesList.size() > 0){
+
+                    question.setQuesBodyWord(replaceQuesBlank(question.getQuesBodyWord(),subNum + 1));
+
                     for(Question subQues:subQuesList){
-                        subQues.setQuesBodyWord(setSubQuesNum(subQues.getQuesBodyWord(),++subNum));
+                        int curSubNum = ++subNum;
+                        subQues.setQuesBodyWord(setSubQuesNum(subQues.getQuesBodyWord(),curSubNum));
+                        subQues.setQuesBodyWord(replaceQuesBlank(subQues.getQuesBodyWord(),curSubNum));
                         List<QuesOption> subOptionList = subQues.getQuesOptions();
                         if(subOptionList != null && subOptionList.size() > 0){
-                            int index = 0;
+                            int sub_index = 0;
                             for(QuesOption quesOption:subOptionList){
-                                quesOption.setOptionBodyWord(setOptionNum(quesOption.getOptionBodyWord(),getOptionNum(index)));
-                                index++;
+                                quesOption.setOptionBodyWord(setOptionNum(quesOption.getOptionBodyWord(),getOptionNum(sub_index)));
+                                sub_index++;
                             }
                         }
                     }
                 }else{
-                    Question question = paperDetailUnit.getQuestion();
-                    question.setQuesBodyWord(setSubQuesNum(question.getQuesBodyWord(),++subNum));
+                    int curSubNum = ++subNum;
+                    question.setQuesBodyWord(setSubQuesNum(question.getQuesBodyWord(),curSubNum));
+                    question.setQuesBodyWord(replaceQuesBlank(question.getQuesBodyWord(),curSubNum));
                 }
             }
         }
@@ -230,14 +231,28 @@ public class ExportPaperService {
         String tmpStr = DocxProcessUtil.BODY_HEADER + quesBodyWordMl + DocxProcessUtil.BODY_TAIL;
         Body body = (Body)XmlUtils.unmarshalString(tmpStr,
                 Context.jc,Body.class);
-        P p = (P)body.getContent().get(0);
-        List<Object> pContent = p.getContent();
-        R run = new R();
-        Text text = new Text();
-        text.setValue(num+". ");
-        run.getContent().add(text);
-        pContent.add(0,run);
-        return DocxProcessUtil.formatPWordMl(XmlUtils.marshaltoString(p));
+        List<Object> pList = body.getContent();
+        int index = 0;
+        for(Object pObj:pList){
+            if(index > 0){
+                break;
+            }
+            P p = (P) pObj;
+            List<Object> pContent = p.getContent();
+            R run = new R();
+            Text text = new Text();
+            text.setValue(num+". ");
+            run.getContent().add(text);
+            pContent.add(0,run);
+            index++;
+        }
+        StringBuffer pWordMl = new StringBuffer();
+        for(Object pObj:pList){
+            if(pObj instanceof P){
+                pWordMl.append(DocxProcessUtil.formatPWordMl(XmlUtils.marshaltoString(pObj)));
+            }
+        }
+        return pWordMl.toString();
     }
 
     /**
@@ -251,14 +266,88 @@ public class ExportPaperService {
         String tmpStr = DocxProcessUtil.BODY_HEADER + optionWordMl + DocxProcessUtil.BODY_TAIL;
         Body body = (Body)XmlUtils.unmarshalString(tmpStr,
                 Context.jc,Body.class);
-        P p = (P)body.getContent().get(0);
-        List<Object> pContent = p.getContent();
-        R run = new R();
-        Text text = new Text();
-        text.setValue(num+". ");
-        run.getContent().add(text);
-        pContent.add(0,run);
-        return DocxProcessUtil.formatPWordMl(XmlUtils.marshaltoString(p));
+        List<Object> pList = body.getContent();
+        int index = 0;
+        for(Object pObj:pList){
+            if(index > 0){
+                break;
+            }
+            P p = (P) pObj;
+            List<Object> pContent = p.getContent();
+            R run = new R();
+            Text text = new Text();
+            text.setValue(num+". ");
+            run.getContent().add(text);
+            pContent.add(0,run);
+            index++;
+        }
+        StringBuffer pWordMl = new StringBuffer();
+        for(Object pObj:pList){
+            if(pObj instanceof P){
+                pWordMl.append(DocxProcessUtil.formatPWordMl(XmlUtils.marshaltoString(pObj)));
+            }
+        }
+        return pWordMl.toString();
+    }
+
+    /**
+     * 替换填空
+     * @param wordMl
+     * @param num
+     * @return
+     * @throws Exception
+     */
+    public String replaceQuesBlank(String wordMl,int num) throws Exception {
+        String tmpStr = DocxProcessUtil.BODY_HEADER + wordMl + DocxProcessUtil.BODY_TAIL;
+        Body body = (Body)XmlUtils.unmarshalString(tmpStr,
+                Context.jc,Body.class);
+        List<Object> pList = body.getContent();
+        int index = 0;
+        int cur = 0;
+        Map<Integer,String> curMap = new HashMap<Integer,String>();
+        for(Object pObj:pList){
+            if(pObj.getClass().equals(P.class)){
+                List<Object> pContent = ((P)pObj).getContent();
+                for(Object rObj:pContent){
+                    if(rObj.getClass().equals(R.class)){
+                        List<Object> rContent = ((R)rObj).getContent();
+                        for(Object tObj:rContent){
+                            if (tObj instanceof JAXBElement)
+                                tObj = ((JAXBElement<?>) tObj).getValue();
+                            if(tObj.getClass().equals(Text.class)){
+                                Text text = (Text)tObj;
+                                String str = text.getValue().trim();
+                                if(str.equals("###")){
+                                    text.setValue("______");
+                                }else if(str.matches("##\\d{1,}##")){
+                                    int curNum = num + index;
+                                    text.setValue("___"+(curNum)+"___");
+                                    index++;
+                                }else if(str.startsWith("#") || str.equals("___")){
+                                    curMap.put(cur,str);
+                                    text.setValue("");
+                                }else if(str.matches("^\\d{1,}$")){
+                                    String preStr = curMap.get(cur - 1);
+                                    if(!StringUtils.isEmpty(preStr) && preStr.startsWith("#")){
+                                        int curNum = num + index;
+                                        text.setValue("___"+(curNum)+"___");
+                                        index++;
+                                    }
+                                }
+                                cur++;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        StringBuffer pWordMl = new StringBuffer();
+        for(Object pObj:pList){
+            if(pObj instanceof P){
+                pWordMl.append(DocxProcessUtil.formatPWordMl(XmlUtils.marshaltoString(pObj)));
+            }
+        }
+        return pWordMl.toString();
     }
 
 }

+ 149 - 160
cqb-paper/src/main/java/com/qmth/cqb/paper/service/ImportPaperService.java

@@ -39,6 +39,7 @@ import com.qmth.cqb.utils.CommonUtils;
 import com.qmth.cqb.utils.enums.PaperStatus;
 import com.qmth.cqb.utils.enums.PaperType;
 import com.qmth.cqb.utils.enums.QuesUnit;
+import com.qmth.cqb.utils.exception.PaperException;
 import com.qmth.cqb.utils.word.DocxProcessUtil;
 
 import cn.com.qmth.examcloud.common.dto.question.enums.QuesStructType;
@@ -76,19 +77,13 @@ public class ImportPaperService {
      * @param file
      * @return
      */
-    public File getUploadFile(CommonsMultipartFile file) {
+    public File getUploadFile(CommonsMultipartFile file) throws Exception {
         String fileName = file.getOriginalFilename();
         File tempFile = new File(DocxProcessUtil.TEMP_FILE_IMP + fileName);
         OutputStream os = null;
-        try {
-            os = new FileOutputStream(tempFile);
-            IOUtils.copyLarge(file.getInputStream(), os);
-        } catch (Exception e) {
-            e.printStackTrace();
-            log.error("上传文件异常:" + e.getMessage());
-        } finally {
-            IOUtils.closeQuietly(os);
-        }
+        os = new FileOutputStream(tempFile);
+        IOUtils.copyLarge(file.getInputStream(), os);
+        IOUtils.closeQuietly(os);
         return tempFile;
     }
 
@@ -100,23 +95,22 @@ public class ImportPaperService {
      * @param file
      * @return
      */
-    public String ImportPaper(String paperName,
-                              String courseNo,
-                              String courseName,
-                              AccessUser user,
-                              File file) {
+    public Map<String, Object> ImportPaper(String paperName, String courseNo, String courseName, AccessUser user,
+            File file) throws Exception {
+        Map<String, Object> msgMap = new HashMap<String, Object>();
         String errorInfo = paperService.checkPaperName(paperName, user.getOrgId().toString());
         if (errorInfo == null) {
-            errorInfo = "";
-            errorInfo += processImportPaper(paperName, courseNo, courseName, user, file);
-            if (StringUtils.isEmpty(errorInfo)) {
-                return "success";
+            msgMap = processImportPaper(paperName, courseNo, courseName, user, file);
+            if (StringUtils.isEmpty((String) msgMap.get("msg"))) {
+                msgMap.put("msg", "success");
+                return msgMap;
             } else {
-                log.error("导入异常:" + errorInfo);
-                return errorInfo;
+                log.error("导入异常:" + (String) msgMap.get("msg"));
+                return msgMap;
             }
         } else {
-            return errorInfo;
+            msgMap.put("msg", errorInfo);
+            return msgMap;
         }
     }
 
@@ -128,13 +122,13 @@ public class ImportPaperService {
      * @param paperDetailUnits
      * @param importPaperCheck
      */
-    public void savePaper(Paper paper, List paperDetails, List paperDetailUnits, List questions,
+    public Paper savePaper(Paper paper, List paperDetails, List paperDetailUnits, List questions,
             ImportPaperCheck importPaperCheck) {
 
         Paper tempPaper = null;
 
         if (!StringUtils.isEmpty(importPaperCheck.errorInfo))
-            return;
+            return null;
 
         if (paper != null) {
             tempPaper = paperRepo.save(paper);
@@ -153,6 +147,8 @@ public class ImportPaperService {
         }
 
         paperService.formatPaper(tempPaper, null);
+
+        return tempPaper;
     }
 
     /**
@@ -165,150 +161,143 @@ public class ImportPaperService {
      * @param file
      * @return
      */
-    public String processImportPaper(String paperName, String courseNo, String courseName, AccessUser user, File file) {
-
+    public Map<String, Object> processImportPaper(String paperName, String courseNo, String courseName, AccessUser user,
+            File file) throws Exception {
+        Map<String, Object> msgMap = new HashMap<String, Object>();
         WordprocessingMLPackage wordMLPackage;
         WordprocessingMLPackage tmpWordMlPackage;
         WordprocessingMLPackage writePkg;
         ImportPaperCheck importPaperCheck = new ImportPaperCheck();
 
-        try {
-            wordMLPackage = WordprocessingMLPackage.load(file);
-            // 初始化图片路径
-            DocxProcessUtil.initPkgImage(wordMLPackage);
-            // 深拷贝临时pkg与最终写入数据库pkg
-            tmpWordMlPackage = DocxProcessUtil.getTmpPackage(wordMLPackage);
-            writePkg = DocxProcessUtil.getTmpPackage(wordMLPackage);
-
-            // 获取word文档中所有段落
-            List<Object> pList = DocxProcessUtil.getAllElementFromObject(wordMLPackage.getMainDocumentPart(), P.class);
-
-            // 创建试卷类
-            Paper paper = new Paper();
-
-            paper.setCourseNo(courseNo);
-
-            paper.setCourseName(courseName);
-
-            paper.setOrgId(user.getOrgId().toString());
-
-            paper.setCreator(user.getName());
-
-            // 设置试卷
-            initPaper(paper, paperName);
-
-            // 创建空大题类
-            PaperDetail paperDetail = null;
-
-            // 创建大题集合
-            List<PaperDetail> paperDetails = new ArrayList<PaperDetail>();
-
-            // 创建小题集合
-            List<PaperDetailUnit> paperDetailUnits = new ArrayList<PaperDetailUnit>();
-
-            // 创建试题集合
-            List<Question> questions = new ArrayList<Question>();
-
-            // 大题号
-            int mainQuesNum = 0;
-
-            // 小题号
-            int subQuesNum = 0;
-
-            for (int i = 0; i < pList.size(); i++) {
-                P p = (P) pList.get(i);
-                String pText = DocxProcessUtil.getPText(p);
-
-
-                if(StringUtils.isEmpty(pText)){
-                    // 跳过空白段落
-                    continue;
-
-                }else if (pText.startsWith("[试题分类]")) {
-                    // 处理大题头信息
-                    processMainQuesHeader(pList, importPaperCheck.index, importPaperCheck);
-
-                    // 校验大题头信息
-                    if (!checkQuesHeader(importPaperCheck)) {
-                        return importPaperCheck.errorInfo;
-                    }
-
-                    // 创建大题类
-                    paperDetail = new PaperDetail();
-
-                    // 设置大题类
-                    initQuesHeader(paper, paperDetail, paperDetails, ++mainQuesNum, importPaperCheck);
-
-                } else if (pText.matches("^\\d{1,}\\.[\\s\\S]*")
-                        || (isNested(importPaperCheck) && !pText.startsWith("["))) {
-                    // 处理试题
-
-                    // 创建小题类和试题类
-                    PaperDetailUnit paperDetailUnit = new PaperDetailUnit();
-                    Question question = new Question();
-
-                    // 初始化小题类和试题类
-                    initPaperDetail(paper, paperDetail, paperDetailUnit, question, ++subQuesNum, importPaperCheck);
-
-                    // 处理客观题
-                    if (importPaperCheck.quesType.equals("单选") || importPaperCheck.quesType.equals("多选")) {
-
-                        // 处理题干
-                        processQuesBody(pList, importPaperCheck.index, question, importPaperCheck, tmpWordMlPackage);
-                        // 处理选项
-                        processQuesOption(pList, importPaperCheck.index, subQuesNum, question, importPaperCheck,
-                                tmpWordMlPackage);
-                        // 处理尾信息
-                        processQuesTail(pList, importPaperCheck.index, subQuesNum, question, paperDetailUnit,
-                                importPaperCheck, tmpWordMlPackage, false);
-                        // 处理选择题的option--chenken 20170425
-                        processSelectOption(question);
-                    } else if (importPaperCheck.quesType.equals("套题")) {
-                        // 处理套题
-                        processNestedQues(pList, importPaperCheck.index, question, paperDetailUnit, importPaperCheck,
-                                tmpWordMlPackage);
-                    } else {
-                        // 处理其他题型
-                        processQuesBody(pList, importPaperCheck.index, question, importPaperCheck, tmpWordMlPackage);
-                        processQuesTail(pList, importPaperCheck.index, subQuesNum, question, paperDetailUnit,
-                                importPaperCheck, tmpWordMlPackage, false);
-                    }
-                    // 设置WordMlPackage二进制数据
-                    setPkgByte(question, writePkg);
-                    // 设置question与Unit集合数据
-                    question.setCourseNo(paper.getCourseNo());
-                    question.setCourseName(paper.getCourseName());
-                    question.setOrgId(user.getOrgId().toString());
-                    questions.add(question);
-                    paperDetailUnits.add(paperDetailUnit);
+        wordMLPackage = WordprocessingMLPackage.load(file);
+        // 初始化图片路径
+        DocxProcessUtil.initPkgImage(wordMLPackage);
+        // 深拷贝临时pkg与最终写入数据库pkg
+        tmpWordMlPackage = DocxProcessUtil.getTmpPackage(wordMLPackage);
+        writePkg = DocxProcessUtil.getTmpPackage(wordMLPackage);
+
+        // 获取word文档中所有段落
+        List<Object> pList = DocxProcessUtil.getAllElementFromObject(wordMLPackage.getMainDocumentPart(), P.class);
+
+        // 创建试卷类
+        Paper paper = new Paper();
+
+        paper.setCourseNo(courseNo);
+
+        paper.setCourseName(courseName);
+
+        paper.setOrgId(user.getOrgId().toString());
+
+        paper.setCreator(user.getName());
+
+        // 设置试卷
+        initPaper(paper, paperName);
+
+        // 创建空大题类
+        PaperDetail paperDetail = null;
+
+        // 创建大题集合
+        List<PaperDetail> paperDetails = new ArrayList<PaperDetail>();
+
+        // 创建小题集合
+        List<PaperDetailUnit> paperDetailUnits = new ArrayList<PaperDetailUnit>();
+
+        // 创建试题集合
+        List<Question> questions = new ArrayList<Question>();
+
+        // 大题号
+        int mainQuesNum = 0;
+
+        // 小题号
+        int subQuesNum = 0;
+
+        for (int i = 0; i < pList.size(); i++) {
+            P p = (P) pList.get(i);
+            String pText = DocxProcessUtil.getPText(p);
 
-                    // 设置当前索引,防止多余循环
-                    i = importPaperCheck.index - 1;
+            if (StringUtils.isEmpty(pText)) {
+                // 跳过空白段落
+                continue;
+
+            } else if (pText.startsWith("[试题分类]")) {
+                // 处理大题头信息
+                processMainQuesHeader(pList, importPaperCheck.index, importPaperCheck);
+
+                // 校验大题头信息
+                if (!checkQuesHeader(importPaperCheck)) {
+                    throw new PaperException(importPaperCheck.errorInfo);
                 }
-                if (!StringUtils.isEmpty(importPaperCheck.errorInfo)) {
-                    return importPaperCheck.errorInfo;
+
+                // 创建大题类
+                paperDetail = new PaperDetail();
+
+                // 设置大题类
+                initQuesHeader(paper, paperDetail, paperDetails, ++mainQuesNum, importPaperCheck);
+
+            } else if (pText.matches("^\\d{1,}\\.[\\s\\S]*")
+                    || (isNested(importPaperCheck) && !pText.startsWith("["))) {
+                // 处理试题
+
+                // 创建小题类和试题类
+                PaperDetailUnit paperDetailUnit = new PaperDetailUnit();
+                Question question = new Question();
+
+                // 初始化小题类和试题类
+                initPaperDetail(paper, paperDetail, paperDetailUnit, question, ++subQuesNum, importPaperCheck);
+
+                // 处理客观题
+                if (importPaperCheck.quesType.equals("单选") || importPaperCheck.quesType.equals("多选")) {
+
+                    // 处理题干
+                    processQuesBody(pList, importPaperCheck.index, question, importPaperCheck, tmpWordMlPackage);
+                    // 处理选项
+                    processQuesOption(pList, importPaperCheck.index, subQuesNum, question, importPaperCheck,
+                            tmpWordMlPackage);
+                    // 处理尾信息
+                    processQuesTail(pList, importPaperCheck.index, subQuesNum, question, paperDetailUnit,
+                            importPaperCheck, tmpWordMlPackage, false);
+                    // 处理选择题的option--chenken 20170425
+                    processSelectOption(question);
+                } else if (importPaperCheck.quesType.equals("套题")) {
+                    // 处理套题
+                    processNestedQues(pList, importPaperCheck.index, question, paperDetailUnit, importPaperCheck,
+                            tmpWordMlPackage);
+                } else {
+                    // 处理其他题型
+                    processQuesBody(pList, importPaperCheck.index, question, importPaperCheck, tmpWordMlPackage);
+                    processQuesTail(pList, importPaperCheck.index, subQuesNum, question, paperDetailUnit,
+                            importPaperCheck, tmpWordMlPackage, false);
                 }
+                // 设置WordMlPackage二进制数据
+                setPkgByte(question, writePkg);
+                // 设置question与Unit集合数据
+                question.setCourseNo(paper.getCourseNo());
+                question.setCourseName(paper.getCourseName());
+                question.setOrgId(user.getOrgId().toString());
+                questions.add(question);
+                paperDetailUnits.add(paperDetailUnit);
+
+                // 设置当前索引,防止多余循环
+                i = importPaperCheck.index - 1;
             }
-            if(paperDetails.size() == 0){
-                importPaperCheck.setErrorInfo("导入文件格式有误!");
-                log.error("导入处理异常:格式错误");
-                return importPaperCheck.errorInfo;
+            if (!StringUtils.isEmpty(importPaperCheck.errorInfo)) {
+                throw new PaperException(importPaperCheck.errorInfo);
             }
-            paper.setPaperDetailCount(mainQuesNum);
-            // 保存导入试卷信息
-            savePaper(paper, paperDetails, paperDetailUnits, questions, importPaperCheck);
-
-        } catch (Exception e) {
-            e.printStackTrace();
-            importPaperCheck.setErrorInfo(e.getMessage());
-            log.error("导入处理异常:" + e.getMessage());
-        } finally {
-            wordMLPackage = null;
-            tmpWordMlPackage = null;
-            writePkg = null;
-            FileUtils.deleteQuietly(file);
         }
-        return importPaperCheck.errorInfo;
+        if (paperDetails.size() == 0) {
+            importPaperCheck.setErrorInfo("导入文件格式有误!");
+            throw new PaperException("导入文件格式有误!");
+        }
+        paper.setPaperDetailCount(mainQuesNum);
+        // 保存导入试卷信息
+        paper = savePaper(paper, paperDetails, paperDetailUnits, questions, importPaperCheck);
+        wordMLPackage = null;
+        tmpWordMlPackage = null;
+        writePkg = null;
+        FileUtils.deleteQuietly(file);
+        msgMap.put("msg", importPaperCheck.errorInfo);
+        msgMap.put("paper", paper);
+        return msgMap;
     }
 
     /**
@@ -472,7 +461,7 @@ public class ImportPaperService {
             P pBody = (P) pList.get(i);
             String tmpText = DocxProcessUtil.getPText(pBody);
 
-            if (StringUtils.isEmpty(tmpText)) {
+            if (StringUtils.isEmpty(tmpText) && DocxProcessUtil.isText(pBody)) {
                 // 跳过空白段落
                 continue;
             } else if (tmpText.matches("^\\d{1,}\\.[\\s\\S]*")) {
@@ -529,7 +518,7 @@ public class ImportPaperService {
             P pOption = (P) pList.get(i);
             String tmpText = DocxProcessUtil.getPText(pOption);
 
-            if (StringUtils.isEmpty(tmpText)) {
+            if (StringUtils.isEmpty(tmpText) && DocxProcessUtil.isText(pOption)) {
                 // 跳过空白段落
                 continue;
             } else if (tmpText.matches("^[a-zA-Z]\\.[\\s\\S]*")) {
@@ -594,7 +583,7 @@ public class ImportPaperService {
         for (i = index; i < pList.size(); i++) {
             P pAnswer = (P) pList.get(i);
             String tmpText = DocxProcessUtil.getPText(pAnswer);
-            if (StringUtils.isEmpty(tmpText)) {
+            if (StringUtils.isEmpty(tmpText) && DocxProcessUtil.isText(pAnswer)) {
                 // 跳过空白段落
                 continue;
             } else if (tmpText.startsWith("[答案]")) {

+ 55 - 42
cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperDetailService.java

@@ -3,90 +3,103 @@ package com.qmth.cqb.paper.service;
 import java.util.List;
 
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Example;
 import org.springframework.stereotype.Service;
 
 import com.qmth.cqb.paper.dao.PaperDetailRepo;
+import com.qmth.cqb.paper.dao.PaperRepo;
 import com.qmth.cqb.paper.model.Paper;
 import com.qmth.cqb.paper.model.PaperDetail;
 import com.qmth.cqb.paper.model.PaperDetailUnit;
 
+import cn.com.qmth.examcloud.common.uac.entity.AccessUser;
+
 @Service
 public class PaperDetailService {
-	
-	
-	@Autowired
-	PaperDetailRepo paperDetailRepo;
-	
-	@Autowired
-	PaperDetailUnitService unitService;
-	
-	
-	/**
-	 * 根据Id获得对应所有小题
-	 * @param id
-	 * @return
-	 */
-	public List<PaperDetailUnit> getUnitsByPaperDetailId(String id){	
-		return unitService.getUnitsByPaperDetail(paperDetailRepo.findOne(id));
-	}
+
+    @Autowired
+    PaperDetailRepo paperDetailRepo;
+
+    @Autowired
+    PaperDetailUnitService unitService;
+
+    @Autowired
+    PaperRepo paperRepo;
+
+    /**
+     * 根据Id获得对应所有小题
+     * 
+     * @param id
+     * @return
+     */
+    public List<PaperDetailUnit> getUnitsByPaperDetailId(String id) {
+        return unitService.getUnitsByPaperDetail(paperDetailRepo.findOne(id));
+    }
 
     /**
      * 按ID查询大题
+     * 
      * @param id
      * @return
      */
-    public PaperDetail findById(String id){
+    public PaperDetail findById(String id) {
         return paperDetailRepo.findOne(id);
     }
 
     /**
      * 保存大题
+     * 
      * @param pd
      * @return
      */
-    public PaperDetail savePaperDetail(PaperDetail pd){
+    public PaperDetail savePaperDetail(PaperDetail pd, String paperId, AccessUser user) {
+        Paper paper = paperRepo.findOne(paperId);
+        paper.setLastModifyName(user.getName());
+        paper = paperRepo.save(paper);
+        pd.setPaper(paper);
         return paperDetailRepo.save(pd);
     }
 
     /**
      * 删除大题
+     * 
      * @param id
      * @return
      */
-    public void deletePaperDetail(String id){
-    	paperDetailRepo.delete(id);
+    public void deletePaperDetail(String id) {
+        paperDetailRepo.delete(id);
     }
-    
+
     /**
      * 查询同一个试卷对象对应大题
+     * 
      * @param paper
      * @return
      */
-    public List<PaperDetail> getPaperDetailsByPaper(Paper paper){
-    	return paperDetailRepo.findByPaper(paper);
+    public List<PaperDetail> getPaperDetailsByPaper(Paper paper) {
+        return paperDetailRepo.findByPaper(paper);
     }
-    
+
     /**
      * 删除试卷大题
+     * 
      * @param paper
      */
-     public void deletePaperDetailsByPaper(Paper paper){
-    	List<PaperDetail> details = getPaperDetailsByPaper(paper);
-    	unitService.deleteUnitsByPaperDetails(details);
-    	paperDetailRepo.delete(details);
+    public void deletePaperDetailsByPaper(Paper paper) {
+        List<PaperDetail> details = getPaperDetailsByPaper(paper);
+        unitService.deleteUnitsByPaperDetails(details);
+        paperDetailRepo.delete(details);
     }
 
-	/**
-	 * 批量删除试卷大题
-	 * @param papers
-	 */
-	public void deletePaperDetailsByPapers(List<Paper> papers){
-		for(Paper paper:papers){
-			List<PaperDetail> details = getPaperDetailsByPaper(paper);
-			unitService.deleteUnitsByPaperDetails(details);
-			paperDetailRepo.delete(details);
-		}
-	}
+    /**
+     * 批量删除试卷大题
+     * 
+     * @param papers
+     */
+    public void deletePaperDetailsByPapers(List<Paper> papers) {
+        for (Paper paper : papers) {
+            List<PaperDetail> details = getPaperDetailsByPaper(paper);
+            unitService.deleteUnitsByPaperDetails(details);
+            paperDetailRepo.delete(details);
+        }
+    }
 }
-

+ 24 - 10
cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperService.java

@@ -151,15 +151,29 @@ public class PaperService {
      * @param paperExp
      * @return
      */
-    public Paper savePaper(PaperExp paperExp, AccessUser user) {
+    public Map<String, Object> savePaper(PaperExp paperExp, AccessUser user) {
+        Map<String, Object> msgMap = new HashMap<String, Object>();
         Paper oldPaper = paperRepo.findOne(paperExp.getId());
         if (oldPaper != null) {
+            String oldName = oldPaper.getName().trim();
             oldPaper.setTitle(paperExp.getTitle());
-            oldPaper.setName(paperExp.getName());
-            oldPaper.setLastModifyName(user.getLoginName());
-            return paperRepo.save(oldPaper);
+            oldPaper.setName(paperExp.getName().trim());
+            oldPaper.setLastModifyName(user.getName());
+            if (!oldName.equals(paperExp.getName().trim())) {// 假如改变了试卷名称 则要效验试卷名称唯一性
+                String msg = this.checkPaperName(paperExp.getName().trim(), user.getOrgId().toString());
+                if (msg == null) {
+                    paperRepo.save(oldPaper);
+                    msgMap.put("msg", "success");
+                } else {
+                    msgMap.put("msg", msg);
+                }
+            } else {
+                paperRepo.save(oldPaper);
+                msgMap.put("msg", "success");
+            }
+
         }
-        return null;
+        return msgMap;
     }
 
     /**
@@ -416,8 +430,8 @@ public class PaperService {
         List<PaperDetailExp> paperDetailExpList = paperExp.getPaperDetails();
         for (PaperDetailExp paperDetail : paperDetailExpList) {
             // 大题序号
-            paperDetail.setCnNum(CommonUtils.toCHNum(paperDetail.getNumber()));
             paperDetail.setNumber(++mainNum);
+            paperDetail.setCnNum(CommonUtils.toCHNum(paperDetail.getNumber()));
             // 小题序号
             if (paperDetail != null && paperDetail.getPaperDetailUnits() != null
                     && paperDetail.getPaperDetailUnits().size() > 0) {
@@ -434,7 +448,7 @@ public class PaperService {
                                 subQues.setQuesParams(params);
                                 quesService.formatQuesUnit(subQues);
                             }
-                            String quesBodyHtml = relaceRuestionIdx(paperDetailUnit.getQuestion().getQuesBody(), index);
+                            String quesBodyHtml = relaceQuestionIdx(paperDetailUnit.getQuestion().getQuesBody(), index);
                             paperDetailUnit.getQuestion().setQuesBody(quesBodyHtml);
                         } else {
                             paperDetailUnit.setNumber(++subNum);
@@ -669,7 +683,7 @@ public class PaperService {
 
     }
 
-    private String relaceRuestionIdx(String str, int baseIdx) {
+    private String relaceQuestionIdx(String str, int baseIdx) {
         StringBuffer sb = new StringBuffer("");
         Pattern pattern = Pattern.compile("##(\\d+)##");
 
@@ -695,8 +709,8 @@ public class PaperService {
             selectedIds.add(id);
         }
         Pageable page = new PageRequest(curPage - 1, pageSize);
-        return paperRepo.findByIdNotInAndCourseNoAndOrgId(selectedIds, paperSearchInfo.getCourseNo(),
-                paperSearchInfo.getOrgId(), page);
+        return paperRepo.findByIdNotInAndCourseNoAndOrgIdAndPaperType(selectedIds, paperSearchInfo.getCourseNo(),
+                paperSearchInfo.getOrgId(), PaperType.IMPORT, page);
     }
 
 }

+ 11 - 1
cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperStructService.java

@@ -70,6 +70,16 @@ public class PaperStructService {
      * @return
      */
     public PaperStruct save(PaperStruct paperStruct, AccessUser user) {
+        if (StringUtils.isNotBlank(paperStruct.getId())) {
+            PaperStruct oldPaperStruct = paperStructRepo.findOne(paperStruct.getId());
+            PaperStruct rps = null;
+            if (oldPaperStruct != null && !paperStruct.getName().equals(oldPaperStruct.getName())) {// 那么就是更新操作
+                rps = this.checkNameUnique(paperStruct.getName(), user.getOrgId().toString());
+            }
+            if (rps != null) {
+                return null;
+            }
+        }
         List<PaperDetailStruct> paperDetailStructs = paperStruct.getPaperDetailStructs();
         int number = 0;
         for (PaperDetailStruct paperDetailStruct : paperDetailStructs) {
@@ -94,7 +104,7 @@ public class PaperStructService {
         }
         paperStruct.setDetailCount(paperDetailStructs.size());
         paperStruct.setOrgId(user.getOrgId().toString());
-        paperStruct.setCreator(user.getLoginName());
+        paperStruct.setCreator(user.getName());
         paperStruct.setCreateTime(CommonUtils.getCurDateTime());
         return paperStructRepo.save(paperStruct);
     }

+ 13 - 1
cqb-paper/src/main/java/com/qmth/cqb/paper/web/ExportPaperController.java

@@ -2,6 +2,8 @@ package com.qmth.cqb.paper.web;
 
 import com.qmth.cqb.paper.service.ExportPaperService;
 import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -17,6 +19,8 @@ import javax.servlet.http.HttpServletResponse;
 @RequestMapping("${api_cqb}/")
 public class ExportPaperController {
 
+    protected static final Logger log = LoggerFactory.getLogger(ExportPaperController.class);
+
     @Autowired
     ExportPaperService exportPaperService;
 
@@ -28,6 +32,14 @@ public class ExportPaperController {
     @ApiOperation(value="导出试卷",notes="导出试卷")
     @GetMapping(value = "/paper/export/{id}")
     public void getPaperById(@PathVariable String id, HttpServletResponse response){
-        exportPaperService.downloadPaper(id,response);
+        log.info("导出开始");
+        try {
+            exportPaperService.downloadPaper(id,response);
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("导出异常:"+e.getMessage());
+        }finally {
+            log.info("导出结束");
+        }
     }
 }

+ 31 - 17
cqb-paper/src/main/java/com/qmth/cqb/paper/web/ImportPaperController.java

@@ -18,8 +18,6 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.multipart.commons.CommonsMultipartFile;
 
-import com.qmth.cqb.flow.model.DataMapModel;
-import com.qmth.cqb.flow.model.WorkFlowModel;
 import com.qmth.cqb.flow.service.ComProcessService;
 import com.qmth.cqb.flow.service.DataMapModelService;
 import com.qmth.cqb.paper.dao.PaperRepo;
@@ -46,12 +44,13 @@ public class ImportPaperController {
 
     @Autowired
     PaperService paperService;
-    
+
     @Autowired
     ComProcessService comProcessService;
-    
+
     @Autowired
     DataMapModelService dataMapModelService;
+
     /**
      * 导入试卷
      * 
@@ -61,20 +60,33 @@ public class ImportPaperController {
      */
     @ApiOperation(value = "导入试卷", notes = "导入试卷")
     @PostMapping(value = "/importPaper")
-    public ResponseEntity importPaper(HttpServletRequest request, @RequestParam String paperName,
-            @RequestParam String courseNo, @RequestParam String courseName,
-            @RequestParam("file") CommonsMultipartFile file) {
+    public ResponseEntity importPaper(HttpServletRequest request, 
+                                        @RequestParam String paperName,
+                                        @RequestParam String courseNo, 
+                                        @RequestParam String courseName,
+                                        @RequestParam("file") CommonsMultipartFile file) {
         AccessUser user = (AccessUser) request.getAttribute("accessUser");
         log.info("导入开始");
-        File tempFile = importPaperService.getUploadFile(file);
-        String returnStr  = importPaperService.ImportPaper(paperName, courseNo, courseName, user, tempFile);
-        log.info("导入结束");
-        if (returnStr.equals("success")) {
-            return new ResponseEntity(returnStr, HttpStatus.OK);
-        } else {
-            Map map = new HashMap();
-            map.put("errorMsg", returnStr);
+        File tempFile = null;
+        Map<String, Object> msgMap = new HashMap<String, Object>();
+        Map map = new HashMap();
+        try {
+            tempFile = importPaperService.getUploadFile(file);
+            msgMap = importPaperService.ImportPaper(paperName, courseNo, courseName, user, tempFile);
+            if (("success").equals(msgMap.get("msg"))) {
+                return new ResponseEntity(msgMap, HttpStatus.OK);
+            } else {
+                map.put("errorMsg", msgMap.get("msg"));
+                log.info("导入异常:" + msgMap.get("msg"));
+                return new ResponseEntity(map, HttpStatus.INTERNAL_SERVER_ERROR);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            map.put("errorMsg", e.getMessage());
+            log.info("导入异常:" + e.getMessage());
             return new ResponseEntity(map, HttpStatus.INTERNAL_SERVER_ERROR);
+        } finally {
+            log.info("导入结束");
         }
     }
 
@@ -87,8 +99,10 @@ public class ImportPaperController {
      */
     @ApiOperation(value = "保存导入类型空白试卷", notes = "保存导入类型空白试卷")
     @PostMapping(value = "/importPaper/saveBlankPaper/{courseNo}/{courseName}/{paperName}")
-    public ResponseEntity saveBlankPaper(HttpServletRequest request, @PathVariable String courseNo,
-            @PathVariable String courseName, @PathVariable String paperName) {
+    public ResponseEntity saveBlankPaper(HttpServletRequest request, 
+                                        @PathVariable String courseNo,
+                                        @PathVariable String courseName, 
+                                        @PathVariable String paperName) {
         AccessUser user = (AccessUser) request.getAttribute("accessUser");
         Map<String, Object> returnMap = importPaperService.saveBlankPaper(courseNo, courseName, paperName, user);
         if (returnMap.get("msg").equals("success")) {

+ 40 - 6
cqb-paper/src/main/java/com/qmth/cqb/paper/web/PaperController.java

@@ -16,6 +16,7 @@ import com.qmth.cqb.question.service.QuesService;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.domain.Example;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.DeleteMapping;
@@ -38,7 +39,9 @@ import com.qmth.cqb.paper.model.Paper;
 import com.qmth.cqb.paper.model.PaperSearchInfo;
 import com.qmth.cqb.paper.service.PaperService;
 import com.qmth.cqb.question.model.Question;
+import com.qmth.cqb.utils.BeanCopierUtil;
 import com.qmth.cqb.utils.StringSimilarityUtils;
+import com.qmth.cqb.utils.enums.PaperType;
 
 import cn.com.qmth.examcloud.common.dto.question.enums.QuesStructType;
 import cn.com.qmth.examcloud.common.uac.entity.AccessUser;
@@ -89,7 +92,13 @@ public class PaperController {
     public ResponseEntity savePaperById(HttpServletRequest request,
                                         @RequestBody PaperExp paper) {
         AccessUser user = (AccessUser) request.getAttribute("accessUser");
-        return new ResponseEntity(paperService.savePaper(paper,user), HttpStatus.OK);
+        Map<String,Object> msgMap = paperService.savePaper(paper,user);
+        if("success".equals(msgMap.get("msg"))){
+            return new ResponseEntity(msgMap, HttpStatus.OK);
+        } else {
+            return new ResponseEntity(msgMap, HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+      
     }
 
     /**
@@ -342,12 +351,18 @@ public class PaperController {
 
         int length = allPaperDetailUnitList.size();
         for (int i = 0; i < length - 1; i++) {
+            PaperDetailUnitExp paperDetailUnitExp1 = allPaperDetailUnitList.get(i);
+            String quesText1 = quesService.getExtractText(paperDetailUnitExp1.getQuestion());
+            if(StringUtils.isEmpty(quesText1)){
+                continue;
+            }
             for (int j = i + 1; j < length; j++) {
-                PaperDetailUnitExp paperDetailUnitExp1 = allPaperDetailUnitList.get(i);
                 PaperDetailUnitExp paperDetailUnitExp2 = allPaperDetailUnitList.get(j);
-                double similarity = StringSimilarityUtils.getSimilarityWithCosinesBySeg(
-                        quesService.getExtractText(paperDetailUnitExp1.getQuestion()),
-                        quesService.getExtractText(paperDetailUnitExp2.getQuestion()));
+                String quesText2 = quesService.getExtractText(paperDetailUnitExp2.getQuestion());
+                if(StringUtils.isEmpty(quesText2)){
+                    continue;
+                }
+                double similarity = StringSimilarityUtils.getSimilarityWithCosinesBySeg(quesText1,quesText2);
                 if (similarity > reduplicateSimilarity) {
                     boolean found = false;
                     for (int k = 0; k < reduplicateId.size(); k++) {
@@ -458,9 +473,28 @@ public class PaperController {
         if(ids !=null && ids.length > 0){
             return new ResponseEntity(paperService.getImportPapersNotInIds(paperSearchInfo,ids,curPage, pageSize), HttpStatus.OK);
         } else {
-            return new ResponseEntity(paperService.getImportPapersNotSuccess(paperSearchInfo, curPage, pageSize), HttpStatus.OK);
+            return new ResponseEntity(paperService.getImportPapers(paperSearchInfo, curPage, pageSize), HttpStatus.OK);
         }
       
     }
 
+    
+    /**
+     * 
+     * @param request
+     * @param paperSearchInfo
+     * @return
+     */
+    @ApiOperation(value = "查询该课程的所有导入试卷", notes = "查询该课程的所有导入试卷")
+    @GetMapping(value = "/importPaper/course")
+    public ResponseEntity getImportPapersByCourseNo( HttpServletRequest request, 
+                                            @ModelAttribute PaperSearchInfo paperSearchInfo) {
+        AccessUser user = (AccessUser) request.getAttribute("accessUser");
+        paperSearchInfo.setOrgId(user.getOrgId().toString());
+        paperService.formatPaperSearchInfo(paperSearchInfo);
+        Paper importPaper = BeanCopierUtil.copyProperties(paperSearchInfo, Paper.class);
+        importPaper.setPaperType(PaperType.IMPORT);
+        return new ResponseEntity(paperRepo.findAll(Example.of(importPaper)), HttpStatus.OK);
+      
+    }
 }

+ 12 - 6
cqb-paper/src/main/java/com/qmth/cqb/paper/web/PaperDetailController.java

@@ -2,6 +2,8 @@ package com.qmth.cqb.paper.web;
 
 import java.util.List;
 
+import javax.servlet.http.HttpServletRequest;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
@@ -13,12 +15,14 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import com.qmth.cqb.paper.dao.PaperDetailRepo;
 import com.qmth.cqb.paper.dao.PaperRepo;
 import com.qmth.cqb.paper.model.PaperDetail;
 import com.qmth.cqb.paper.model.PaperDetailUnit;
 import com.qmth.cqb.paper.service.PaperDetailService;
 import com.qmth.cqb.paper.service.PaperService;
 
+import cn.com.qmth.examcloud.common.uac.entity.AccessUser;
 import io.swagger.annotations.ApiOperation;
 
 /**
@@ -33,9 +37,9 @@ public class PaperDetailController {
 
     @Autowired
     PaperService paperService;
-
+    
     @Autowired
-    PaperRepo paperRepo;
+    PaperDetailRepo paperDetailRepo;
 
     /**
      * 获取大题对应的小题
@@ -69,9 +73,11 @@ public class PaperDetailController {
      */
     @ApiOperation(value = "更新试卷中的大题", notes = "更新试卷中的大题")
     @PostMapping(value = "/updatePaperDetail/{paperId}")
-    public ResponseEntity updatePaperDetail(@PathVariable String paperId, @RequestBody PaperDetail pd) {
-        pd.setPaper(paperRepo.findOne(paperId));
-        PaperDetail paperDetail = paperDetailService.savePaperDetail(pd);
+    public ResponseEntity updatePaperDetail( HttpServletRequest request,
+                                             @PathVariable String paperId, 
+                                             @RequestBody PaperDetail pd) {
+        AccessUser user = (AccessUser) request.getAttribute("accessUser");
+        PaperDetail paperDetail = paperDetailService.savePaperDetail(pd,paperId,user);
         return new ResponseEntity(paperDetail, HttpStatus.OK);
 
     }
@@ -85,7 +91,7 @@ public class PaperDetailController {
     @ApiOperation(value = "新增大题", notes = "新增大题")
     @PostMapping(value = "/paperDetail")
     public ResponseEntity addPaperDetail(@RequestBody PaperDetail pd) {
-        PaperDetail paperDetail = paperDetailService.savePaperDetail(pd);
+        PaperDetail paperDetail = paperDetailRepo.save(pd);
         return new ResponseEntity(paperDetail, HttpStatus.OK);
     }
 

+ 6 - 1
cqb-paper/src/main/java/com/qmth/cqb/paper/web/PaperStructController.java

@@ -90,7 +90,12 @@ public class PaperStructController {
     public ResponseEntity updatePaperStruct(HttpServletRequest request, @RequestBody PaperStruct ps) {
         AccessUser user = (AccessUser) request.getAttribute("accessUser");
         PaperStruct paperStruct = paperStructService.save(ps, user);
-        return new ResponseEntity(paperStruct, HttpStatus.OK);
+        if (paperStruct == null) {
+            return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
+        } else {
+            return new ResponseEntity(paperStruct, HttpStatus.OK);
+        }
+
     }
 
     /**

+ 16 - 11
cqb-question-resource/src/main/java/com/qmth/cqb/question/service/QuesService.java

@@ -71,7 +71,7 @@ public class QuesService {
             } else {
                 for (int i = 0; i < quesOptions.size(); i++) {
                     saveQuesOptions.get(i).setOptionBody(quesOptions.get(i).getOptionBody());
-                    //设置正确答案(chenken-2017.4.24)
+                    // 设置正确答案(chenken-2017.4.24)
                     saveQuesOptions.get(i).setIsCorrect(quesOptions.get(i).getIsCorrect());
                 }
             }
@@ -127,8 +127,7 @@ public class QuesService {
             updateQuesWord(saveQues);
             return quesRepo.save(saveQues);
         }
-        
-        
+
     }
 
     /**
@@ -249,7 +248,8 @@ public class QuesService {
             question.setQuesAnswerWord(null);
             question.setQuesAnswerAnalysisWord(null);
             question.setQuesPkg(new byte[0]);
-            String newQuesBody = question.getQuesBody().replaceAll("<span>", "").replaceAll("</span>", "").replaceAll("###", "______");
+            String newQuesBody = question.getQuesBody().replaceAll("<span>", "").replaceAll("</span>", "")
+                    .replaceAll("###", "______");
             question.setQuesBody(newQuesBody);
             if (question.getQuesOptions() != null && question.getQuesOptions().size() > 0) {
                 question.getQuesOptions().stream().forEach(quesOption -> {
@@ -284,10 +284,12 @@ public class QuesService {
     public void updateQuesWordUnit(WordprocessingMLPackage wordMLPackage, Question question) throws Exception {
         String quesBody = StringEscapeUtils.unescapeHtml4(question.getQuesBody());
         String quesAnswer = StringEscapeUtils.unescapeHtml4(question.getQuesAnswer());
-        question.setQuesBodyWord(DocxProcessUtil.html2Docx(wordMLPackage, quesBody));
-        DocxProcessUtil.initTmpPackage(wordMLPackage);
-        question.setQuesAnswerWord(DocxProcessUtil.html2Docx(wordMLPackage, quesAnswer));
-        DocxProcessUtil.initTmpPackage(wordMLPackage);
+        if(!StringUtils.isEmpty(quesBody)){
+            question.setQuesBodyWord(DocxProcessUtil.html2Docx(wordMLPackage, quesBody));
+        }
+        if(!StringUtils.isEmpty(quesAnswer)){
+            question.setQuesAnswerWord(DocxProcessUtil.html2Docx(wordMLPackage, quesAnswer));
+        }
         List<QuesOption> quesOptions = question.getQuesOptions();
         if (quesOptions != null && quesOptions.size() > 0) {
             for (QuesOption quesOption : quesOptions) {
@@ -307,14 +309,17 @@ public class QuesService {
      */
     public String getExtractText(Question question) {
         StringBuilder quesText = new StringBuilder();
-        quesText.append(DocxProcessUtil.getTextInHtml(question.getQuesBody()));
+        if (question != null && !StringUtils.isEmpty(question.getQuesBody())) {
+            quesText.append(DocxProcessUtil.getTextInHtml(question.getQuesBody()));
+        }
         List<QuesOption> quesOptionList = question.getQuesOptions();
         if (quesOptionList != null && quesOptionList.size() > 0) {
             for (QuesOption quesOption : quesOptionList) {
-                quesText.append(DocxProcessUtil.getTextInHtml(quesOption.getOptionBody()));
+                if (!StringUtils.isEmpty(quesOption.getOptionBody())) {
+                    quesText.append(DocxProcessUtil.getTextInHtml(quesOption.getOptionBody()));
+                }
             }
         }
         return quesText.toString();
     }
-
 }

+ 1 - 1
cqb-starter/src/main/resources/log4j2.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<Configuration status="WARN">
+<Configuration status="info">
     <Appenders>
         <Console name="Console" target="SYSTEM_OUT" follow="true">
             <PatternLayout charset="UTF-8">