Pārlūkot izejas kodu

机考代码修改

weiwenhai 7 gadi atpakaļ
vecāks
revīzija
610cde92b6

+ 134 - 134
cqb-paper/src/main/java/com/qmth/cqb/paper/model/computerTestModel/ComputerTestPaper.java

@@ -1,134 +1,134 @@
-package com.qmth.cqb.paper.model.computerTestModel;
-
-import java.util.List;
-
-import com.qmth.cqb.paper.model.Paper;
-
-/**
- * @author  	chenken
- * @date    	2017年7月25日 上午9:39:11
- * @company 	QMTH
- * @description ComputerTestPaper.java
- */
-public class ComputerTestPaper {
-	
-	/**
-	 * 试卷编号
-	 */
-	private String id;
-	/**
-	 * 试卷名称
-	 */
-	private String name;
-	/**
-	 * 课程code
-	 */
-	private String courseCode;
-	/**
-	 * 试卷类型   A、B卷
-	 */
-	private String groupCode;
-	/**
-	 * 课程名称
-	 */
-	private String courseName;
-	/**
-	 * 总分
-	 */
-	private double totalScore;
-	/**
-	 * 1:含有音视频
-	 * 0:不含有音视频
-	 */
-	private Integer hasVideo;
-	/**
-	 * 大题数量
-	 */
-	private int detailCount;
-	/**
-	 * 大题集合
-	 */
-	private List<ComputerTestPaperDetail> details;
-	
-	public ComputerTestPaper(){
-		
-	}
-	
-	public ComputerTestPaper(Paper paper,String groupCode){
-		this.id = paper.getId();
-		this.name = paper.getName();
-		this.courseCode = paper.getCourse().getCode();
-		this.courseName = paper.getCourse().getName();
-		this.totalScore = paper.getTotalScore();
-		this.detailCount = paper.getPaperDetailCount();
-		if(paper.getHasAudio()==null||!paper.getHasAudio()){
-			this.hasVideo = 0;
-		}else{
-			this.hasVideo = 1;
-		}
-		this.groupCode = groupCode;
-	}
-	
-	public String getId() {
-		return id;
-	}
-	public void setId(String id) {
-		this.id = id;
-	}
-	public String getName() {
-		return name;
-	}
-	public void setName(String name) {
-		this.name = name;
-	}
-	public double getTotalScore() {
-		return totalScore;
-	}
-	public void setTotalScore(double totalScore) {
-		this.totalScore = totalScore;
-	}
-	public Integer getHasVideo() {
-		return hasVideo;
-	}
-	public void setHasVideo(Integer hasVideo) {
-		this.hasVideo = hasVideo;
-	}
-	public int getDetailCount() {
-		return detailCount;
-	}
-	public void setDetailCount(int detailCount) {
-		this.detailCount = detailCount;
-	}
-	public List<ComputerTestPaperDetail> getDetails() {
-		return details;
-	}
-	public void setDetails(List<ComputerTestPaperDetail> details) {
-		this.details = details;
-	}
-
-	public String getCourseCode() {
-		return courseCode;
-	}
-
-	public void setCourseCode(String courseCode) {
-		this.courseCode = courseCode;
-	}
-
-	public String getCourseName() {
-		return courseName;
-	}
-
-	public void setCourseName(String courseName) {
-		this.courseName = courseName;
-	}
-
-	public String getGroupCode() {
-		return groupCode;
-	}
-
-	public void setGroupCode(String groupCode) {
-		this.groupCode = groupCode;
-	}
-	
-}
-
+package com.qmth.cqb.paper.model.computerTestModel;
+
+import java.util.List;
+
+import com.qmth.cqb.paper.model.Paper;
+
+/**
+ * @author  	chenken
+ * @date    	2017年7月25日 上午9:39:11
+ * @company 	QMTH
+ * @description ComputerTestPaper.java
+ */
+public class ComputerTestPaper {
+	
+	/**
+	 * 试卷编号
+	 */
+	private String id;
+	/**
+	 * 试卷名称
+	 */
+	private String name;
+	/**
+	 * 课程code
+	 */
+	private String courseCode;
+	/**
+	 * 试卷类型   A、B卷
+	 */
+	private transient String  groupCode;
+	/**
+	 * 课程名称
+	 */
+	private String courseName;
+	/**
+	 * 总分
+	 */
+	private double totalScore;
+	/**
+	 * 1:含有音视频
+	 * 0:不含有音视频
+	 */
+	private Integer hasVideo;
+	/**
+	 * 大题数量
+	 */
+	private int detailCount;
+	/**
+	 * 大题集合
+	 */
+	private List<ComputerTestPaperDetail> details;
+	
+	public ComputerTestPaper(){
+		
+	}
+	
+	public ComputerTestPaper(Paper paper,String groupCode){
+		this.id = paper.getId();
+		this.name = paper.getName();
+		this.courseCode = paper.getCourse().getCode();
+		this.courseName = paper.getCourse().getName();
+		this.totalScore = paper.getTotalScore();
+		this.detailCount = paper.getPaperDetailCount();
+		if(paper.getHasAudio()==null||!paper.getHasAudio()){
+			this.hasVideo = 0;
+		}else{
+			this.hasVideo = 1;
+		}
+		this.groupCode = groupCode;
+	}
+	
+	public String getId() {
+		return id;
+	}
+	public void setId(String id) {
+		this.id = id;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public double getTotalScore() {
+		return totalScore;
+	}
+	public void setTotalScore(double totalScore) {
+		this.totalScore = totalScore;
+	}
+	public Integer getHasVideo() {
+		return hasVideo;
+	}
+	public void setHasVideo(Integer hasVideo) {
+		this.hasVideo = hasVideo;
+	}
+	public int getDetailCount() {
+		return detailCount;
+	}
+	public void setDetailCount(int detailCount) {
+		this.detailCount = detailCount;
+	}
+	public List<ComputerTestPaperDetail> getDetails() {
+		return details;
+	}
+	public void setDetails(List<ComputerTestPaperDetail> details) {
+		this.details = details;
+	}
+
+	public String getCourseCode() {
+		return courseCode;
+	}
+
+	public void setCourseCode(String courseCode) {
+		this.courseCode = courseCode;
+	}
+
+	public String getCourseName() {
+		return courseName;
+	}
+
+	public void setCourseName(String courseName) {
+		this.courseName = courseName;
+	}
+
+	public String getGroupCode() {
+		return groupCode;
+	}
+
+	public void setGroupCode(String groupCode) {
+		this.groupCode = groupCode;
+	}
+	
+}
+

+ 1073 - 1057
cqb-paper/src/main/java/com/qmth/cqb/paper/service/export/ExportPaperAbstractService.java

@@ -1,1057 +1,1073 @@
-package com.qmth.cqb.paper.service.export;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-import javax.servlet.http.HttpServletResponse;
-import javax.xml.bind.JAXBElement;
-
-import main.java.com.UpYun;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.docx4j.XmlUtils;
-import org.docx4j.jaxb.Context;
-import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
-import org.docx4j.wml.Body;
-import org.docx4j.wml.P;
-import org.docx4j.wml.R;
-import org.docx4j.wml.Text;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-
-import cn.com.qmth.examcloud.common.dto.core.enums.CourseLevel;
-import cn.com.qmth.examcloud.common.dto.question.enums.QuesStructType;
-import cn.com.qmth.examcloud.common.uac.entity.AccessUser;
-import cn.com.qmth.examcloud.common.util.excel.ExcelWriter;
-
-import com.google.gson.Gson;
-import com.qmth.cqb.paper.dao.PaperDetailRepo;
-import com.qmth.cqb.paper.dao.PaperDetailUnitRepo;
-import com.qmth.cqb.paper.dao.PaperRepo;
-import com.qmth.cqb.paper.dto.ObjectiveQuestionStructure;
-import com.qmth.cqb.paper.dto.PaperDetailExp;
-import com.qmth.cqb.paper.dto.PaperDetailUnitExp;
-import com.qmth.cqb.paper.dto.PaperExp;
-import com.qmth.cqb.paper.dto.SubjectiveQuestionStructure;
-import com.qmth.cqb.paper.model.ExamFile;
-import com.qmth.cqb.paper.model.ExamPaper;
-import com.qmth.cqb.paper.model.ExportStructure;
-import com.qmth.cqb.paper.model.ExtractConfig;
-import com.qmth.cqb.paper.model.Paper;
-import com.qmth.cqb.paper.model.PaperDetail;
-import com.qmth.cqb.paper.model.PaperDetailUnit;
-import com.qmth.cqb.paper.model.QuestionTypeNum;
-import com.qmth.cqb.paper.model.computerTestModel.Block;
-import com.qmth.cqb.paper.model.computerTestModel.ComputerTestOption;
-import com.qmth.cqb.paper.model.computerTestModel.ComputerTestPaper;
-import com.qmth.cqb.paper.model.computerTestModel.ComputerTestPaperDetail;
-import com.qmth.cqb.paper.model.computerTestModel.ComputerTestQuestion;
-import com.qmth.cqb.paper.model.computerTestModel.Section;
-import com.qmth.cqb.paper.model.computerTestModel.Sections;
-import com.qmth.cqb.paper.service.ExamFileService;
-import com.qmth.cqb.paper.service.PaperDetailService;
-import com.qmth.cqb.paper.service.PaperService;
-import com.qmth.cqb.question.dao.QuesRepo;
-import com.qmth.cqb.question.model.QuesOption;
-import com.qmth.cqb.question.model.Question;
-import com.qmth.cqb.question.model.QuestionAudio;
-import com.qmth.cqb.question.service.QuestionAudioService;
-import com.qmth.cqb.utils.BeanCopierUtil;
-import com.qmth.cqb.utils.CommonUtils;
-import com.qmth.cqb.utils.FileDisposeUtil;
-import com.qmth.cqb.utils.enums.ExamFileType;
-import com.qmth.cqb.utils.exception.PaperException;
-import com.qmth.cqb.utils.word.DocxProcessUtil;
-
-import freemarker.template.Configuration;
-import freemarker.template.Template;
-
-/**
- * 
- * @author  	chenken
- * @date    	2017年7月15日 下午4:00:24
- * @company 	QMTH
- * @description 导出、上传文件service 父类
- */
-public abstract class ExportPaperAbstractService {
-	
-	@Autowired
-	PaperRepo paperRepo;
-
-	@Autowired
-	PaperService paperService;
-
-	@Autowired
-	PaperDetailRepo paperDetailRepo;
-
-	@Autowired
-	PaperDetailUnitRepo paperDetailUnitRepo;
-	
-	@Autowired
-	ExamFileService examFileService;
-
-	@Autowired
-	private PaperDetailService paperDetailService;
-	
-	@Autowired
-	private QuestionAudioService questionAudioService;
-	
-	@Autowired
-	QuesRepo quesRepo;
-
-	public static final String FILL_BLANK_QUESTION_FLAG = "###";
-	
-	public static final String TEMP_FILE_EXP = "docxExport/";
-	
-	/**
-	 * Word文件后缀
-	 */
-	public static final String DOCX_SUFFIX = ".docx";
-	/**
-	 * Excel文件后缀
-	 */
-	public static final String EXCEL_SUFFIX = ".xlsx";
-	/**
-	 * ZIP文件后缀
-	 */
-	public static final String ZIP_SUFFIX = ".zip";
-	
-	public static final String ENCODING = "UTF-8";
-	
-	/**
-	 * 下划线
-	 */
-	private static final String UNDERSCORE = "_";
-
-	//陕西师范模板
-	protected static Template SXSF_TEMPLATE_PAPER;
-	protected static Template SXSF_TEMPLATE_ANSWER;
-	
-	//电子科大模板
-	protected static Template DZKD_TEMPLATE_PAPER;
-	protected static Template DZKD_TEMPLATE_ANSWER;
-	
-	//华中科技大学模板
-	protected static Template HZKJ_TEMPLATE_PAPER;
-	protected static Template HZKJ_TEMPLATE_ANSWER;
-	
-	//山东大学
-	protected static Template SDDX_TEMPLATE_PAPER;
-	protected static Template SDDX_TEMPLATE_ANSWER;
-	
-	//天津大学
-	protected static Template TJDX_TEMPLATE_PAPER;
-	protected static Template TJDX_TEMPLATE_ANSWER;
-	
-	//石油大学模板
-	protected static Template SYDX_TEMPLATE_PAPER;
-	protected static Template SYDX_TEMPLATE_ANSWER;
-
-	@Value("${upyun.bucketName}")
-	protected String bucketName;
-	
-	@Value("${upyun.userName}")
-	protected String userName;
-	
-	@Value("${upyun.password}")
-	protected String password;
-	
-	@Value("${upyun.uploadUrl}")
-	protected String uploadUrl;
-	
-	@Value("${upyun.downloadUrl}")
-	protected String downloadUrl;
-	
-	public static Configuration CONFIGURATION;
-	
-	static {
-		try {
-			CONFIGURATION = new Configuration(Configuration.VERSION_2_3_25);
-			// 设置编码
-			CONFIGURATION.setDefaultEncoding(ENCODING);
-			// 设置ftl模板路径
-			CONFIGURATION.setClassForTemplateLoading(DocxProcessUtil.class, "/");
-			
-			SXSF_TEMPLATE_PAPER = CONFIGURATION.getTemplate("sxsf_paper_template.ftl", ENCODING);
-			SXSF_TEMPLATE_ANSWER = CONFIGURATION.getTemplate("sxsf_answer_template.ftl", ENCODING);
-			
-			DZKD_TEMPLATE_PAPER = CONFIGURATION.getTemplate("dzkd_paper_template.ftl", ENCODING);
-			DZKD_TEMPLATE_ANSWER = CONFIGURATION.getTemplate("dzkd_answer_template.ftl", ENCODING);
-			
-			HZKJ_TEMPLATE_PAPER = CONFIGURATION.getTemplate("hzkj_paper_template.ftl", ENCODING);
-			HZKJ_TEMPLATE_ANSWER = CONFIGURATION.getTemplate("hzkj_answer_template.ftl", ENCODING);
-			
-			SDDX_TEMPLATE_PAPER = CONFIGURATION.getTemplate("sddx_paper_template.ftl", ENCODING);
-			SDDX_TEMPLATE_ANSWER = CONFIGURATION.getTemplate("sddx_answer_template.ftl", ENCODING);
-			
-			TJDX_TEMPLATE_PAPER = CONFIGURATION.getTemplate("tjdx_paper_template.ftl", ENCODING);
-			TJDX_TEMPLATE_ANSWER = CONFIGURATION.getTemplate("tjdx_answer_template.ftl", ENCODING);
-			
-			SYDX_TEMPLATE_PAPER = CONFIGURATION.getTemplate("sydx_paper_template.ftl", ENCODING);
-			SYDX_TEMPLATE_ANSWER = CONFIGURATION.getTemplate("sydx_answer_template.ftl", ENCODING);
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
-	}
-	
-	/**
-	 * 下载试卷相关文件
-	 * @param id
-	 * @param response
-	 * @throws Exception
-	 */
-	public abstract void downloadPaper(String paperId, HttpServletResponse response)throws Exception;
-	
-	/**
-	 * 上传试卷相关文件
-	 * @param orgName
-	 * @param examName
-	 * @param paperId
-	 * @throws Exception
-	 */
-    public abstract void uploadFile(ExtractConfig extractConfig,String paperId,ExportStructure exportStructure,AccessUser accessUser)  throws Exception;
-	
-	/**
-	 * 公共方法
-	 * 初始化导出试卷DTO
-	 * @param id
-	 * @return
-	 */
-	public PaperExp initExportPaper(String paperId) throws Exception {
-		Paper paper = paperRepo.findOne(paperId);
-		paperService.formatPaper(paper, null);
-		if (paper == null) {
-			throw new PaperException("该试卷不存在");
-		}
-		// 创建paperDto
-		PaperExp paperExp = BeanCopierUtil.copyProperties(paper, PaperExp.class);
-		paperExp.setCourseLevel(paper.getLevel()==null?CourseLevel.ALL.getName():paper.getLevel().getName());
-		List<PaperDetailExp> objectiveDetails = new ArrayList<PaperDetailExp>();// 客观题
-		List<PaperDetailExp> subjectiveDetails = new ArrayList<PaperDetailExp>();// 主观题
-		double objectiveScore = 0;
-		double subjectiveScore = 0;
-		paperExp.setTitle(CommonUtils.PAPER_TITLE);
-		paperExp.setSubTitle(CommonUtils.PAPER_SUB_TITLE);
-		// 获取大题
-		List<PaperDetail> paperDetails = paperDetailRepo.findByPaper(paper);
-		int objectNumber = 1;// 客观题大题序号
-		int objetcUnitSum = 0;
-		for (int i = 0; i < paperDetails.size(); i++) {
-			PaperDetailExp paperDetailExp = BeanCopierUtil.copyProperties(paperDetails.get(i), PaperDetailExp.class);
-			List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo.findByPaperDetailOrderByNumber(paperDetails.get(i));
-			// 把大题分类 :客观题和主观题
-			List<PaperDetailUnitExp> paperDetailUnitExps = BeanCopierUtil.copyPropertiesOfList(paperDetailUnits,PaperDetailUnitExp.class);
-			// 选择题,套题下选择题 选项顺序重新排列
-			paperService.reorderChoicequestionOption(paperDetailUnitExps);
-			paperDetailExp.setPaperDetailUnits(paperDetailUnitExps);
-			boolean isSubjective = false;// 判断主观题和客观题
-			if (paperDetailUnits.get(0).getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
-				for (Question ques : paperDetailUnits.get(0).getQuestion().getSubQuestions()) {
-					if (ques.getQuestionType() == QuesStructType.TEXT_ANSWER_QUESTION) {
-						isSubjective = true;
-						break;
-					}
-				}
-			} else if (paperDetailUnits.get(0).getQuestionType() == QuesStructType.TEXT_ANSWER_QUESTION
-					 ||paperDetailUnits.get(0).getQuestionType() == QuesStructType.FILL_BLANK_QUESTION) {
-				isSubjective = true;
-			}
-			if (isSubjective) {
-				subjectiveDetails.add(paperDetailExp);
-				subjectiveScore += paperDetailExp.getScore();
-			}else{
-				objectiveDetails.add(paperDetailExp);
-				paperDetailExp.setNumber(objectNumber);
-				paperDetailExp.setCnNum(CommonUtils.toCHNum(objectNumber));
-				objectiveScore += paperDetailExp.getScore();
-				objetcUnitSum += paperDetailExp.getUnitCount();
-				objectNumber++;
-			}
-			setExpTitle(paperDetailExp);
-		}
-
-		paperExp.setObjectiveDetails(objectiveDetails);
-		paperExp.setSubjectiveDetails(subjectiveDetails);
-		paperExp.setObjectiveScore(objectiveScore);
-		paperExp.setSubjectiveScore(subjectiveScore);
-		if (objectiveDetails.size() > 0) {
-			setUnitExpNumber(objectiveDetails, 0);
-			appendScoreToQuestionBody(objectiveDetails);
-		}
-		if (subjectiveDetails.size() > 0) {
-			for (PaperDetailExp subDetail : subjectiveDetails) {
-				subDetail.setNumber(objectNumber);
-				subDetail.setCnNum(CommonUtils.toCHNum(objectNumber));
-				objectNumber++;
-			}
-			setUnitExpNumber(subjectiveDetails, objetcUnitSum);
-			appendScoreToQuestionBody(subjectiveDetails);
-		}
-		return paperExp;
-	}
-
-	public void setExpTitle(PaperDetailExp paperDetailExp) {
-		String title = "";
-		String totalScore = BigDecimal.valueOf(paperDetailExp.getScore()).stripTrailingZeros().toPlainString();
-		QuesStructType type = paperDetailExp.getPaperDetailUnits().get(0).getQuestionType();
-		String questionScore = checkPaperDetailUnitScore(paperDetailExp);
-		String scoreString = questionScore==null?"":"每小题"+questionScore+"分";
-		if (type == QuesStructType.SINGLE_ANSWER_QUESTION) {
-			paperDetailExp.setName("单项选择题");
-			title = "(本大题共" + paperDetailExp.getUnitCount() + "小题,"
-					+ scoreString + "共" + totalScore + "分)。"
-					+ "在每小题列出的四个备选中只有一个符合题目要求的,请将其选出并将“答题卡”的相应代码涂黑,错涂、多涂或未涂均无分";
-		} else if (type == QuesStructType.BOOL_ANSWER_QUESTION) {
-			paperDetailExp.setName("判断题");
-			title = "(本大题共" + paperDetailExp.getUnitCount() + "小题,"+ scoreString + "共" + totalScore+ "分。正确的填涂A、错误填涂B。错涂、多涂或未涂均无分)";
-		} else if (type == QuesStructType.FILL_BLANK_QUESTION) {
-			paperDetailExp.setName("填空题");
-			int blankNum = 0;
-			for (PaperDetailUnitExp unit:paperDetailExp.getPaperDetailUnits()){
-				String tempStr = unit.getQuestion().getQuesBody().replaceAll(FILL_BLANK_QUESTION_FLAG, "");
-				int lenTimes = (unit.getQuestion().getQuesBody().length() - tempStr.length()) / FILL_BLANK_QUESTION_FLAG.length();// 出现的次数
-				blankNum += lenTimes;
-			}
-			title = "(本大题共"+blankNum+"个空格,将每空答在答题卡 “1—" +blankNum+"”相应的序号上。"+"共"+totalScore + "分)";
-		} else {
-			title = "(本大题共"+paperDetailExp.getUnitCount()+"小题,"+scoreString+"共"+totalScore+"分)";
-		}
-		paperDetailExp.setTitle(title);
-	}
-
-	/**
-	 * 校验大题下的小题分数是不是一样
-	 * 
-	 * @param paperDetailExp
-	 * @return  如果分数一样,返回分数
-	 * 			如果分数不一样,返回 null
-	 */
-	protected String checkPaperDetailUnitScore(PaperDetailExp paperDetailExp) {
-		List<PaperDetailUnitExp> paperDetailUnitExps = paperDetailExp.getPaperDetailUnits();
-		Set<Double> scoreSet = new HashSet<Double>();
-		for (PaperDetailUnitExp unitExp : paperDetailUnitExps) {
-			if(unitExp.getQuestionType()==QuesStructType.NESTED_ANSWER_QUESTION){
-				List<Double> subScoreList =  unitExp.getSubScoreList();
-				for(Double score:subScoreList){
-					scoreSet.add(score);
-				}
-			}else{
-				scoreSet.add(unitExp.getScore());
-			}
-		}
-		if(scoreSet.size() == 1){
-			return scoreSet.iterator().next()+"";
-		}
-		return null;
-	}
-
-	protected void setUnitExpNumber(List<PaperDetailExp> paperDetails,int startIndxt) throws Exception {
-		int subNum = startIndxt;
-		for (PaperDetailExp paperDetail : paperDetails) {
-			List<PaperDetailUnitExp> paperDetailUnitExpList = paperDetail.getPaperDetailUnits();
-			//对大题下的小题进行排序
-			Collections.sort(paperDetailUnitExpList);
-			for (PaperDetailUnitExp paperDetailUnit:paperDetailUnitExpList) {
-				List<QuesOption> optionList = paperDetailUnit.getQuestion().getQuesOptions();
-				if (optionList != null && optionList.size() > 0) {
-					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) {
-						int curSubNum = ++subNum;
-						subQues.setQuesBodyWord(setSubQuesNum(subQues.getQuesBodyWord(),curSubNum));
-						subQues.setQuesAnswerWord(setSubQuesNum(subQues.getQuesAnswerWord(),curSubNum));
-						subQues.setQuesBodyWord(replaceQuesBlank(subQues.getQuesBodyWord(),curSubNum));
-						List<QuesOption> subOptionList = subQues.getQuesOptions();
-						if (subOptionList != null && subOptionList.size() > 0) {
-							int sub_index = 0;
-							for (QuesOption quesOption : subOptionList) {
-								quesOption.setOptionBodyWord(setOptionNum(quesOption.getOptionBodyWord(),getOptionNum(sub_index)));
-								sub_index++;
-							}
-						}
-					}
-				} else {
-					int curSubNum = ++subNum;
-					question.setQuesBodyWord(setSubQuesNum(question.getQuesBodyWord(), curSubNum));
-					question.setQuesAnswerWord(setSubQuesNum(question.getQuesAnswerWord(),curSubNum));
-					question.setQuesBodyWord(replaceQuesBlank(question.getQuesBodyWord(),curSubNum));
-				}
-			}
-		}
-	}
-	
-	/**
-     * 替换填空
-     * 将###替换为下划线_______
-     * @param wordMl
-     * @param num
-     * @return
-     * @throws Exception
-     */
-	protected 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();
-                                str = str.replaceAll("###","______");
-                                text.setValue(str);
-                                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();
-    }
-	
-	/**
-	 * 将数字1,2,3,4转化成A,B,C,D
-	 * @param number
-	 * @return
-	 */
-    protected String getOptionNum(int number){
-        char optionNum = (char)(65 + number);
-        return String.valueOf(optionNum);
-    }
-
-    /**
-     * 获取当前试卷下所有试题WordPkg
-     * @param id
-     * @return
-     */
-    protected List<WordprocessingMLPackage> getPkgList(String id){
-        Paper paper = paperRepo.findOne(id);
-        List<WordprocessingMLPackage> wordMLPackages = paperDetailUnitRepo.findByPaper(paper)
-                .stream().map(PaperDetailUnit::getQuestion).collect(Collectors.toList())
-                .stream().map(Question::getPkgObj).collect(Collectors.toList());
-        return wordMLPackages;
-    }
-
-    /**
-     * 设置题号
-     * @param quesBodyWordMl
-     * @param num
-     * @return
-     * @throws Exception
-     */
-    public String setSubQuesNum(String quesBodyWordMl,int num) throws Exception {
-        String tmpStr = DocxProcessUtil.BODY_HEADER + quesBodyWordMl + DocxProcessUtil.BODY_TAIL;
-        Body body = (Body)XmlUtils.unmarshalString(tmpStr,Context.jc,Body.class);
-        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 optionWordMl
-     * @param num
-     * @return
-     * @throws Exception
-     */
-    public String setOptionNum(String optionWordMl,String num) throws Exception {
-        String tmpStr = DocxProcessUtil.BODY_HEADER + optionWordMl + DocxProcessUtil.BODY_TAIL;
-        Body body = (Body)XmlUtils.unmarshalString(tmpStr,Context.jc,Body.class);
-        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 details
-     * @throws Exception
-     */
-    protected void appendScoreToQuestionBody(List<PaperDetailExp> details) throws Exception{
-    	for(PaperDetailExp paperDetailExp:details){
-    		if(checkPaperDetailUnitScore(paperDetailExp)==null){
-    			for(PaperDetailUnitExp paperDetailUnit:paperDetailExp.getPaperDetailUnits()){
-    				Question question = paperDetailUnit.getQuestion();
-    				String questionBodyWord = appendScoreToQuestionBody(question.getQuesBodyWord(),paperDetailUnit.getScore());
-    				question.setQuesBodyWord(questionBodyWord);
-    			}
-    		}
-    	}
-    }
-    
-    /**
-     * 在题干上设置分数
-     * @throws Exception 
-     */
-    protected String appendScoreToQuestionBody(String quesBodyWordMl,double score) throws Exception{
-    	String tmpStr = DocxProcessUtil.BODY_HEADER + quesBodyWordMl + DocxProcessUtil.BODY_TAIL;
-        Body body = (Body)XmlUtils.unmarshalString(tmpStr,Context.jc,Body.class);
-        List<Object> pList = body.getContent();
-        int index = 0;
-        for(Object pObj:pList){
-            if(index < pList.size()-1){
-                break;
-            }
-            P p = (P) pObj;
-            List<Object> pContent = p.getContent();
-            R run = new R();
-            Text text = new Text();
-            int scoreInt = (int)score;
-            text.setValue("("+scoreInt+"分)");
-            run.getContent().add(text);
-            pContent.add(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 paperId
-     * @param currNum
-     * ObjectId("591ead1290994d57cd453464")
-     * @throws IOException 
-     */
-    protected void uploadComputerTestFile(ExtractConfig extractConfig,AccessUser accessUser) throws IOException{
-    	List<ComputerTestPaper>  computerTestPaperList = buildComputerTestPapers(extractConfig);
-    	String currentTimeStr = CommonUtils.getCurNum();
-    	for(int i = 0;i<computerTestPaperList.size();i++){
-    		ComputerTestPaper computerTestPaper = computerTestPaperList.get(i);
-    		String jsonDirectoryName = currentTimeStr+UNDERSCORE+ExamFileType.COMPUTERTEST_PACKAGE.name()+UNDERSCORE+i;
-    		String jsonDirectoryPath = TEMP_FILE_EXP + File.separator + jsonDirectoryName;
-    		//新建文件夹
-    		File dirFile = new File(jsonDirectoryPath);
-    		if(!dirFile.exists()){
-    			dirFile.mkdirs();
-    		}
-    		//将computerTestPaper对象生成JSON文件存放在jsonDirectoryPath中
-    		makeComputerTestPaperToJsonFile(extractConfig,computerTestPaper,jsonDirectoryPath);
-			//下载试卷中的音频文件到jsonDirectoryPath文件夹中
-			downloadQuestionAudio(computerTestPaper,jsonDirectoryPath);
-			//将文件夹打包成zip压缩包放在docxExport下
-			FileDisposeUtil.fileToZip(jsonDirectoryPath,"docxExport",jsonDirectoryName);
-			//上传zip压缩包到又拍云
-			File zipFile = new File(TEMP_FILE_EXP+jsonDirectoryName+ZIP_SUFFIX);
-			String zipUpyunFilePath = uploadUrl+extractConfig.getOrgId()+"/"+jsonDirectoryName+ZIP_SUFFIX;
-			UpYun upyun = new UpYun(bucketName,userName,password);
-			upyun.writeFile(zipUpyunFilePath,zipFile,true);
-			//保存数据库记录
-			examFileService.saveExamFile(new ExamFile(extractConfig,zipUpyunFilePath,ExamFileType.COMPUTERTEST_PACKAGE,computerTestPaper.getName(),ZIP_SUFFIX),accessUser);
-			//删除本地生成的文件
-			zipFile.delete();
-			FileUtils.deleteQuietly(dirFile);
-    	}
-    }
-    
-    /**
-     * 将computerTestPaper对象生成JSON文件存放在jsonDirectoryPath中
-     * @param extractConfig
-     * @param computerTestPaper
-     * @param jsonDirectoryPath
-     */
-    private void makeComputerTestPaperToJsonFile(ExtractConfig extractConfig,ComputerTestPaper computerTestPaper,String jsonDirectoryPath){
-		//创建新的JSON文件
-		File file = new File(jsonDirectoryPath+File.separator+extractConfig.getCourseCode()+".json");
-		//将对象转成 json对象
-		Gson gson = new Gson();
-		String strJSON = gson.toJson(computerTestPaper);
-		//生成文件流写入JSON文件
-		FileOutputStream outputStream;
-		try {
-			outputStream = new FileOutputStream(file);
-			byte b[] = strJSON.getBytes();
-			outputStream.write(b);
-			outputStream.close();
-		} catch (FileNotFoundException e) {
-			e.printStackTrace();
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-    }
-    
-    /**
-     * 下载题目音频文件
-     * @param computerTestPaper
-     */
-    private void downloadQuestionAudio(ComputerTestPaper computerTestPaper,String jsonDirectoryPath){
-    	List<ComputerTestPaperDetail> details = computerTestPaper.getDetails();
-		for(ComputerTestPaperDetail detail:details){
-			List<ComputerTestQuestion> questions = detail.getQuestions();
-			for(ComputerTestQuestion question:questions){
-				getBodyAndOptionAudioFile(question,question.getBody(),jsonDirectoryPath);
-				List<ComputerTestOption> options = question.getOptions();
-				for(ComputerTestOption option:options){
-					getBodyAndOptionAudioFile(question,option.getBody(),jsonDirectoryPath);
-				}
-				//子题音频处理
-				//List<ComputerTestQuestion> subQuestions = question.getSubQuestions();
-			}
-		}
-    }
-    
-    private void getBodyAndOptionAudioFile(ComputerTestQuestion computerTestQuestion,Sections bodySections,String jsonDirectoryPath){
-    	List<Section> sectionList = bodySections.getSections();
-		for(Section section:sectionList){
-			List<Block> blocks = section.getBlocks();
-			for(Block block:blocks){
-				if("audio".equals(block.getType())){
-					PaperDetailUnit paperDetailUnit = paperDetailUnitRepo.findById(computerTestQuestion.getId());
-					QuestionAudio audio = questionAudioService.findByQuestionIdAndFileName(paperDetailUnit.getQuestion().getId(),block.getValue());
-					if(audio!=null){
-						FileDisposeUtil.saveUrlAs(downloadUrl+audio.getFileUrl(),jsonDirectoryPath+File.separator+block.getValue());
-						
-						
-					}
-				}
-			}
-		}
-    }
-    
-    /**
-     * 构建机考数据包实体类
-     * @param extractConfig
-     * @return
-     */
-    private List<ComputerTestPaper> buildComputerTestPapers(ExtractConfig extractConfig){
-    	List<ExamPaper> examPapers = extractConfig.getExamPaperList();
-    	List<ComputerTestPaper> computerTestPapers = new ArrayList<ComputerTestPaper>();
-    	//循环得到试卷
-    	for(ExamPaper examPaper:examPapers){
-    		
-    		Paper paper = examPaper.getPaper();
-    		//得到所有旧对象的大题对象
-    		List<PaperDetail> paperDetails = paperService.findPaperDetailsById(paper.getId());
-    		//通过 paper 对象 ,生成新的  ComputerTestPaper 对象
-    		ComputerTestPaper computerTestPaper = new ComputerTestPaper(paper,examPaper.getGroupCode());
-    		List<ComputerTestPaperDetail> details = new ArrayList<ComputerTestPaperDetail>();
-    		//遍历所有旧大题对象,得到小题对象的集合
-    		for(PaperDetail paperDetail:paperDetails){
-    			List<PaperDetailUnit> paperDetailUnits = paperDetailService.getUnitsByPaperDetailId(paperDetail.getId());
-    			ComputerTestPaperDetail computerTestPaperDetail = new ComputerTestPaperDetail(paperDetail);
-    			List<ComputerTestQuestion> questions = new ArrayList<ComputerTestQuestion>();
-    			//遍历所有的小题对象
-    			for(int i = 0;i<paperDetailUnits.size();i++){
-    				PaperDetailUnit paperDetailUnit = paperDetailUnits.get(i);
-    				//根据旧的小题对象,生成新的小题对象
-    				ComputerTestQuestion  computerTestQuestion = new ComputerTestQuestion(paperDetailUnit);
-    				//设置小题题号
-    				computerTestQuestion.setNumber(i+1);
-    				//得到小题题干
-    				computerTestQuestion.setBody(getBody(paperDetailUnit.getQuestion()));
-    				//得到小题所有选项
-    				computerTestQuestion.setOptions(getOption(paperDetailUnit.getQuestion()));
-    				//查询小题中的 套题
-    				List<Question> subQuestionsList = paperDetailUnit.getQuestion().getSubQuestions();
-    				//判断这个小题中是否有套题
-    				if(subQuestionsList!=null&&subQuestionsList.size()>0){
-    					List<ComputerTestQuestion> subQuestions = new ArrayList<ComputerTestQuestion>();
-    					//遍历每个套题
-    					for(int j = 0;j<subQuestionsList.size();j++){
-    						Question subQuestion = subQuestionsList.get(j);
-        					ComputerTestQuestion subcomputerTestQuestion = new ComputerTestQuestion(subQuestion);
-        					//设置套题中小题题号
-        					subcomputerTestQuestion.setNumber(j+1);
-        					subcomputerTestQuestion.setBody(getBody(subQuestion));
-        					subcomputerTestQuestion.setOptions(getOption(subQuestion));
-        					subQuestions.add(subcomputerTestQuestion);
-    					}
-        				computerTestQuestion.setSubQuestions(subQuestions);
-    				}
-    				questions.add(computerTestQuestion);
-    			}
-    			computerTestPaperDetail.setQuestions(questions);
-    			details.add(computerTestPaperDetail);
-    		}
-    		computerTestPaper.setDetails(details);
-    		computerTestPapers.add(computerTestPaper);
-    	}
-    	return computerTestPapers;
-    }
-
-	private Sections getBody(Question question){
-    	Sections body = new Sections();
-		List<Section> sections = new ArrayList<Section>(); 
-		//得到小题题干
-		String questionBodyString = question.getQuesBody();
-		//得到小题题干行数
-		String[] questionRowStrings = questionBodyString.split("</p>");
-		for(int i = 0;i<questionRowStrings.length;i++){
-			Section section = new Section();
-			//将小题题干拆分为Block集合
-			section.setBlocks(disposeQuestionBodyOrOption(questionRowStrings[i]));
-			sections.add(section);
-		}
-		body.setSections(sections);
-		return body;
-    }
-    
-    private List<ComputerTestOption> getOption(Question question){
-    	//得到小题选项
-		List<QuesOption> quesOptions = question.getQuesOptions();
-		List<ComputerTestOption> options = new ArrayList<ComputerTestOption>();
-		//遍历小题选项
-		if(quesOptions!=null&&quesOptions.size()>0){
-			for(QuesOption quesOption: quesOptions){
-				ComputerTestOption option = new ComputerTestOption();
-				option.setNumber(new Integer(quesOption.getNumber()));
-				option.setCorrect(quesOption.getIsCorrect()==1?true:false);
-				Sections body = new Sections();
-				
-				List<Section> sections = new ArrayList<Section>();
-				//得到小题选项
-				String optionString = quesOption.getOptionBody();
-				String[] optionStrings = optionString.split("</p>");
-				for(int i = 0;i<optionStrings.length;i++){
-					Section section = new Section();
-					section.setBlocks(disposeQuestionBodyOrOption(optionStrings[i]));
-					sections.add(section);
-				}
-				body.setSections(sections);
-				option.setBody(body);
-				options.add(option);
-			}
-		}
-		return options;
-    }
-      
-    private List<Block> disposeQuestionBodyOrOption(String questionRow) {
-    	List<Block> blocks = new ArrayList<Block>();
-    	//去掉每行里面的<p>,<span>,</span>标签
-    	questionRow = questionRow.replaceAll("<p>", "")
-			    				 .replaceAll("</p>", "")
-			    				 .replaceAll("<span>", "")
-			    				 .replaceAll("</span>", "")
-			    				 .replaceAll("</a>", "");
-		String[] questionRowStrings = questionRow.split("<|/>|>");
-    	for(int i = 0;i<questionRowStrings.length;i++){
-    		Block block = new Block();
-			//判断是否有图片
-			if(questionRowStrings[i].startsWith("img")){
-				questionRowStrings[i] = "<"+questionRowStrings[i]+">";
-				Map<String, Object> param  = new HashMap<String, Object>();
-				//需要继续做截取,取到Parma
-				block.setType("image");
-				//获取图片的路径
-				List<String> strSrcList = getImg(questionRowStrings[i], "src");
-				if(strSrcList.size()>0){
-					String strSrc = strSrcList.get(0).replaceAll("src=\"", "").replaceAll("\"", "");
-					block.setValue(strSrc);
-				}
-				//获取图片的高度
-				List<String> strHeightList = getImg(questionRowStrings[i], "height");
-				if(strHeightList.size()>0){
-					String strHeight = strHeightList.get(0).replaceAll("height=\"", "").replaceAll("\"", "");
-					param.put("height", strHeight);
-				}
-				//获取图片的宽度
-				List<String> strWidthList = getImg(questionRowStrings[i], "width");
-				if(strHeightList.size()>0){
-					String strWidth = strWidthList.get(0).replaceAll("width=\"", "").replaceAll("\"", "");
-					param.put("width", strWidth);
-				}
-				block.setParam(param);
-				blocks.add(block);
-			}else if(questionRowStrings[i].startsWith("a")
-					&&questionRowStrings[i].contains("id")
-					&&questionRowStrings[i].contains("name")){	//处理音频
-				questionRowStrings[i] = "<"+questionRowStrings[i]+">";
-				block.setType("audio");
-				block.setValue(getAudioName(questionRowStrings[i]));
-				blocks.add(block);
-			}else{
-				block.setType("text");
-				questionRowStrings[i] = questionRowStrings[i].replaceAll("&nbsp;","");
-				block.setValue(questionRowStrings[i]);
-				blocks.add(block);
-			}
-    	}
-		return blocks;
-	}
-
-	/**
-     * 获取图片里面的路径,长度,宽度
-     * @param s
-     * @param str
-     * @return
-     */
-    private List<String> getImg(String s,String str)
-    {
-        String regex;
-        List<String> list = new ArrayList<String>();
-        regex = str + "=\"(.*?)\"";
-        Pattern pa = Pattern.compile(regex, Pattern.DOTALL);
-        Matcher ma = pa.matcher(s);
-        while (ma.find())
-        {
-            list.add(ma.group());
-        }
-        return list;
-    }
-
-    private String getAudioName(String questionStr){
-    	Pattern pattern = Pattern.compile("a.*");
-		Matcher matcher = pattern.matcher(questionStr);
-		while(matcher.find()){
-		      String result = matcher.group();
-		      String idstr = "id=\".*?\"";
-		      Pattern pattern02 = Pattern.compile(idstr);
-		      Matcher matcher02 = pattern02.matcher(result);
-		      while(matcher02.find()){
-		    	  return matcher02.group().replaceAll("id=\"", "").replaceAll("\"", "");
-		      }
-		}
-		return "";
-    }
-    
-	/**
-     * 生成试卷或答案Word,上传至又拍云
-     * @param orgName
-     * @param dataMap
-     * @param extractConfig
-     * @param paperId
-     * @param accessUser
-     */
-    protected void uploadPaperOrAnswerFile(PaperExp paperExp,ExtractConfig extractConfig,AccessUser accessUser,String currNum,Template template,ExamFileType examFileType){
-    	String paperfileName = currNum+examFileType.name()+DOCX_SUFFIX;
-    	try {
-			DocxProcessUtil.exportWord(paperExp,paperfileName,template);
-			DocxProcessUtil.processImage(paperfileName,getPkgList(paperExp.getId()));
-			File file  = new File(TEMP_FILE_EXP+paperfileName);
-			String paperFilePath = uploadUrl+extractConfig.getOrgId()+"/"+paperfileName;
-            UpYun upyun = new UpYun(bucketName,userName,password);
-			upyun.writeFile(paperFilePath,file,true);
-			examFileService.saveExamFile(new ExamFile(paperExp.getId(),extractConfig,paperFilePath,examFileType,DOCX_SUFFIX),accessUser);
-			file.delete();
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
-    }
-    
-    /**
-     * 生成试卷结构,上传至又拍云
-     */
-    protected void uploadPaperStructure(PaperExp paperExp,ExtractConfig extractConfig,AccessUser accessUser,String currNum,List<QuestionTypeNum> questionTypeNums) {
-    	exportObjectiveQuestionStructures(paperExp,extractConfig,accessUser,currNum,questionTypeNums);
-    	exportSubjectiveQuestionStructures(paperExp,extractConfig,accessUser,currNum);
-	}
-    
-    /**
-     * 获得客观题导出结构,并上传至又拍云
-     * @param paperExp
-     * @return
-     */
-    protected void exportObjectiveQuestionStructures(PaperExp paperExp,ExtractConfig extractConfig,AccessUser accessUser,String currNum,List<QuestionTypeNum> questionTypeNums){
-    	String objectiveFilename = currNum+ExamFileType.PAPER_STRUCTURE_OBJECTIVE.name()+EXCEL_SUFFIX;
-    	List<PaperDetailExp> objectiveDetails = paperExp.getObjectiveDetails();
-    	//根据试卷结构导出设置中的数量补齐客观题
-    	fillObjectiveQuestions(objectiveDetails,questionTypeNums);
-    	List<ObjectiveQuestionStructure> objectiveQuestionStructureList = new ArrayList<ObjectiveQuestionStructure>();
-    	for(PaperDetailExp paperDetailExp:objectiveDetails){
-    		for(PaperDetailUnitExp unit:paperDetailExp.getPaperDetailUnits()){
-    			objectiveQuestionStructureList.add(new ObjectiveQuestionStructure(paperExp,paperDetailExp,unit));
-    		}
-    	}
-    	ExcelWriter objectiveExcelExporter = new ExcelWriter(ObjectiveQuestionStructure.class); 
-		try {
-			File file = new File(TEMP_FILE_EXP+objectiveFilename);
-			FileOutputStream out = new FileOutputStream(file);
-			objectiveExcelExporter.write(objectiveFilename,objectiveQuestionStructureList,out);
-			String objectiveFilePath = uploadUrl+extractConfig.getOrgId()+"/"+objectiveFilename;
-            UpYun upyun = new UpYun(bucketName,userName,password);
-			upyun.writeFile(objectiveFilePath,file,true);
-			examFileService.saveExamFile(new ExamFile(paperExp.getId(),extractConfig,objectiveFilePath,ExamFileType.PAPER_STRUCTURE_OBJECTIVE,EXCEL_SUFFIX),accessUser);
-			file.delete();
-		} catch (FileNotFoundException e) {
-			e.printStackTrace();
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-    }
-    
-    /**
-     * 根据试卷结构导出设置中的数量补齐客观题
-     * @param objectiveDetails
-     * @param questionTypeNums
-     */
-    public void fillObjectiveQuestions(List<PaperDetailExp> objectiveDetails,List<QuestionTypeNum> questionTypeNums) {
-    	for(PaperDetailExp paperDetailExp:objectiveDetails){
-    		List<PaperDetailUnitExp> paperDetailUnits = paperDetailExp.getPaperDetailUnits();
-    		//1.将大题中的小题排序
-    		Collections.sort(paperDetailUnits);
-    		//2.将小题的number重新设置
-    		for(int i = 0;i<paperDetailUnits.size();i++){
-    			PaperDetailUnitExp paperDetailUnitExp = paperDetailUnits.get(i);
-    			paperDetailUnitExp.setNumber(i+1);
-    		}
-    		//3.根据试卷结构导出设置中的数量补齐客观题
-    		QuesStructType type = paperDetailUnits.get(0).getQuestionType();
-    		int unitSize = paperDetailUnits.size();
-    		for(QuestionTypeNum questionTypeNum:questionTypeNums){
-    			if(type==questionTypeNum.getQuestionType()){
-    				int length = questionTypeNum.getQuantity()-unitSize;
-    				for(int i = 0;i<length;i++){
-    					PaperDetailUnitExp paperDetailUnitExp = new PaperDetailUnitExp();
-    					paperDetailUnitExp.setQuestionType(type);
-    					paperDetailUnitExp.setScore((double) 0);
-    					paperDetailUnitExp.setNumber(unitSize+(i+1));
-    					Question question = new Question();
-    					question.setQuesAnswer("#");
-    					paperDetailUnitExp.setQuestion(question);
-    					paperDetailUnits.add(paperDetailUnitExp);
-    				}
-    			}
-    		}
-    	}
-	}
-
-	/**
-     * 检查客观题数量是否小于试卷结构导出设置的数量
-     * @param paperExp
-     * @param objectiveDetails
-     * @param questionTypeNums
-     * @return
-     */
-    protected void checkObjectiveDetailsNum(PaperExp paperExp,List<PaperDetailExp> objectiveDetails,List<QuestionTypeNum> questionTypeNums) {
-	   for(PaperDetailExp paperDetailExp:objectiveDetails){
-			for(QuestionTypeNum typeNum:questionTypeNums){
-				QuesStructType quesStructType = paperDetailExp.getPaperDetailUnits().get(0).getQuestionType();
-				if(typeNum.getQuestionType()==quesStructType){
-					if(paperDetailExp.getUnitCount()>typeNum.getQuantity()){
-						throw new RuntimeException("课程最大题量超出设定范围,请核实后重新设置导出规则!");
-					}
-				}
-			}
-		}
-    }
-
-   	/**
-     * 获得主观题导出结构,并上传至又拍云
-     * @param paperExp
-     * @return
-     */
-    protected void exportSubjectiveQuestionStructures(PaperExp paperExp,ExtractConfig extractConfig,AccessUser accessUser,String currNum){
-    	String subjectiveFileName = currNum+ExamFileType.PAPER_STRUCTURE_SUBJECTIVE.name()+EXCEL_SUFFIX;
-    	List<PaperDetailExp> subjectiveDetails = paperExp.getSubjectiveDetails();
-    	List<SubjectiveQuestionStructure> subjectiveQuestionStructureList = new ArrayList<SubjectiveQuestionStructure>();
-    	for(PaperDetailExp paperDetailExp:subjectiveDetails){
-    		for(PaperDetailUnitExp unit:paperDetailExp.getPaperDetailUnits()){
-    			subjectiveQuestionStructureList.add(new SubjectiveQuestionStructure(paperExp,paperDetailExp,unit));
-    		}
-    	}
-    	ExcelWriter subjectiveExcelExporter = new ExcelWriter(SubjectiveQuestionStructure.class); 
-		try {
-			File file = new File(TEMP_FILE_EXP+subjectiveFileName);
-			FileOutputStream out = new FileOutputStream(file);
-			subjectiveExcelExporter.write(subjectiveFileName,subjectiveQuestionStructureList,out);
-			String subjectiveFilePath = uploadUrl+extractConfig.getOrgId()+"/"+subjectiveFileName;
-            UpYun upyun = new UpYun(bucketName,userName,password);
-			upyun.writeFile(subjectiveFilePath,file,true);
-			examFileService.saveExamFile(new ExamFile(paperExp.getId(),extractConfig,subjectiveFilePath,ExamFileType.PAPER_STRUCTURE_SUBJECTIVE,EXCEL_SUFFIX),accessUser);
-			file.delete();
-		} catch (FileNotFoundException e) {
-			e.printStackTrace();
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-    }
-    
-}
+package com.qmth.cqb.paper.service.export;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.bind.JAXBElement;
+
+import main.java.com.UpYun;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.docx4j.XmlUtils;
+import org.docx4j.jaxb.Context;
+import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
+import org.docx4j.wml.Body;
+import org.docx4j.wml.P;
+import org.docx4j.wml.R;
+import org.docx4j.wml.Text;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.domain.Example;
+
+import cn.com.qmth.examcloud.common.dto.core.enums.CourseLevel;
+import cn.com.qmth.examcloud.common.dto.question.enums.QuesStructType;
+import cn.com.qmth.examcloud.common.uac.entity.AccessUser;
+import cn.com.qmth.examcloud.common.util.excel.ExcelWriter;
+
+import com.google.gson.Gson;
+import com.google.gson.annotations.Expose;
+import com.qmth.cqb.paper.dao.AudioTimeConfigRepo;
+import com.qmth.cqb.paper.dao.PaperDetailRepo;
+import com.qmth.cqb.paper.dao.PaperDetailUnitRepo;
+import com.qmth.cqb.paper.dao.PaperRepo;
+import com.qmth.cqb.paper.dto.ObjectiveQuestionStructure;
+import com.qmth.cqb.paper.dto.PaperDetailExp;
+import com.qmth.cqb.paper.dto.PaperDetailUnitExp;
+import com.qmth.cqb.paper.dto.PaperExp;
+import com.qmth.cqb.paper.dto.SubjectiveQuestionStructure;
+import com.qmth.cqb.paper.model.AudioTimeConfig;
+import com.qmth.cqb.paper.model.ExamFile;
+import com.qmth.cqb.paper.model.ExamPaper;
+import com.qmth.cqb.paper.model.ExportStructure;
+import com.qmth.cqb.paper.model.ExtractConfig;
+import com.qmth.cqb.paper.model.Paper;
+import com.qmth.cqb.paper.model.PaperDetail;
+import com.qmth.cqb.paper.model.PaperDetailUnit;
+import com.qmth.cqb.paper.model.QuestionTypeNum;
+import com.qmth.cqb.paper.model.computerTestModel.Block;
+import com.qmth.cqb.paper.model.computerTestModel.ComputerTestOption;
+import com.qmth.cqb.paper.model.computerTestModel.ComputerTestPaper;
+import com.qmth.cqb.paper.model.computerTestModel.ComputerTestPaperDetail;
+import com.qmth.cqb.paper.model.computerTestModel.ComputerTestQuestion;
+import com.qmth.cqb.paper.model.computerTestModel.Section;
+import com.qmth.cqb.paper.model.computerTestModel.Sections;
+import com.qmth.cqb.paper.service.ExamFileService;
+import com.qmth.cqb.paper.service.PaperDetailService;
+import com.qmth.cqb.paper.service.PaperService;
+import com.qmth.cqb.question.dao.QuesRepo;
+import com.qmth.cqb.question.model.QuesOption;
+import com.qmth.cqb.question.model.Question;
+import com.qmth.cqb.question.model.QuestionAudio;
+import com.qmth.cqb.question.service.QuestionAudioService;
+import com.qmth.cqb.utils.BeanCopierUtil;
+import com.qmth.cqb.utils.CommonUtils;
+import com.qmth.cqb.utils.FileDisposeUtil;
+import com.qmth.cqb.utils.enums.ExamFileType;
+import com.qmth.cqb.utils.exception.PaperException;
+import com.qmth.cqb.utils.word.DocxProcessUtil;
+
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+
+/**
+ * 
+ * @author  	chenken
+ * @date    	2017年7月15日 下午4:00:24
+ * @company 	QMTH
+ * @description 导出、上传文件service 父类
+ */
+public abstract class ExportPaperAbstractService {
+	
+	@Autowired
+	PaperRepo paperRepo;
+
+	@Autowired
+	PaperService paperService;
+
+	@Autowired
+	PaperDetailRepo paperDetailRepo;
+
+	@Autowired
+	PaperDetailUnitRepo paperDetailUnitRepo;
+	
+	@Autowired
+	ExamFileService examFileService;
+
+	@Autowired
+	private PaperDetailService paperDetailService;
+	
+	@Autowired
+	private QuestionAudioService questionAudioService;
+	
+	@Autowired
+	QuesRepo quesRepo;
+	
+	@Autowired
+	AudioTimeConfigRepo audioTimeConfigRepo;
+
+	public static final String FILL_BLANK_QUESTION_FLAG = "###";
+	
+	public static final String TEMP_FILE_EXP = "docxExport/";
+	
+	/**
+	 * Word文件后缀
+	 */
+	public static final String DOCX_SUFFIX = ".docx";
+	/**
+	 * Excel文件后缀
+	 */
+	public static final String EXCEL_SUFFIX = ".xlsx";
+	/**
+	 * ZIP文件后缀
+	 */
+	public static final String ZIP_SUFFIX = ".zip";
+	
+	public static final String ENCODING = "UTF-8";
+	
+	/**
+	 * 下划线
+	 */
+	private static final String UNDERSCORE = "_";
+
+	//陕西师范模板
+	protected static Template SXSF_TEMPLATE_PAPER;
+	protected static Template SXSF_TEMPLATE_ANSWER;
+	
+	//电子科大模板
+	protected static Template DZKD_TEMPLATE_PAPER;
+	protected static Template DZKD_TEMPLATE_ANSWER;
+	
+	//华中科技大学模板
+	protected static Template HZKJ_TEMPLATE_PAPER;
+	protected static Template HZKJ_TEMPLATE_ANSWER;
+	
+	//山东大学
+	protected static Template SDDX_TEMPLATE_PAPER;
+	protected static Template SDDX_TEMPLATE_ANSWER;
+	
+	//天津大学
+	protected static Template TJDX_TEMPLATE_PAPER;
+	protected static Template TJDX_TEMPLATE_ANSWER;
+	
+	//石油大学模板
+	protected static Template SYDX_TEMPLATE_PAPER;
+	protected static Template SYDX_TEMPLATE_ANSWER;
+
+	@Value("${upyun.bucketName}")
+	protected String bucketName;
+	
+	@Value("${upyun.userName}")
+	protected String userName;
+	
+	@Value("${upyun.password}")
+	protected String password;
+	
+	@Value("${upyun.uploadUrl}")
+	protected String uploadUrl;
+	
+	@Value("${upyun.downloadUrl}")
+	protected String downloadUrl;
+	
+	public static Configuration CONFIGURATION;
+	
+	static {
+		try {
+			CONFIGURATION = new Configuration(Configuration.VERSION_2_3_25);
+			// 设置编码
+			CONFIGURATION.setDefaultEncoding(ENCODING);
+			// 设置ftl模板路径
+			CONFIGURATION.setClassForTemplateLoading(DocxProcessUtil.class, "/");
+			
+			SXSF_TEMPLATE_PAPER = CONFIGURATION.getTemplate("sxsf_paper_template.ftl", ENCODING);
+			SXSF_TEMPLATE_ANSWER = CONFIGURATION.getTemplate("sxsf_answer_template.ftl", ENCODING);
+			
+			DZKD_TEMPLATE_PAPER = CONFIGURATION.getTemplate("dzkd_paper_template.ftl", ENCODING);
+			DZKD_TEMPLATE_ANSWER = CONFIGURATION.getTemplate("dzkd_answer_template.ftl", ENCODING);
+			
+			HZKJ_TEMPLATE_PAPER = CONFIGURATION.getTemplate("hzkj_paper_template.ftl", ENCODING);
+			HZKJ_TEMPLATE_ANSWER = CONFIGURATION.getTemplate("hzkj_answer_template.ftl", ENCODING);
+			
+			SDDX_TEMPLATE_PAPER = CONFIGURATION.getTemplate("sddx_paper_template.ftl", ENCODING);
+			SDDX_TEMPLATE_ANSWER = CONFIGURATION.getTemplate("sddx_answer_template.ftl", ENCODING);
+			
+			TJDX_TEMPLATE_PAPER = CONFIGURATION.getTemplate("tjdx_paper_template.ftl", ENCODING);
+			TJDX_TEMPLATE_ANSWER = CONFIGURATION.getTemplate("tjdx_answer_template.ftl", ENCODING);
+			
+			SYDX_TEMPLATE_PAPER = CONFIGURATION.getTemplate("sydx_paper_template.ftl", ENCODING);
+			SYDX_TEMPLATE_ANSWER = CONFIGURATION.getTemplate("sydx_answer_template.ftl", ENCODING);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+	
+	/**
+	 * 下载试卷相关文件
+	 * @param id
+	 * @param response
+	 * @throws Exception
+	 */
+	public abstract void downloadPaper(String paperId, HttpServletResponse response)throws Exception;
+	
+	/**
+	 * 上传试卷相关文件
+	 * @param orgName
+	 * @param examName
+	 * @param paperId
+	 * @throws Exception
+	 */
+    public abstract void uploadFile(ExtractConfig extractConfig,String paperId,ExportStructure exportStructure,AccessUser accessUser)  throws Exception;
+	
+	/**
+	 * 公共方法
+	 * 初始化导出试卷DTO
+	 * @param id
+	 * @return
+	 */
+	public PaperExp initExportPaper(String paperId) throws Exception {
+		Paper paper = paperRepo.findOne(paperId);
+		paperService.formatPaper(paper, null);
+		if (paper == null) {
+			throw new PaperException("该试卷不存在");
+		}
+		// 创建paperDto
+		PaperExp paperExp = BeanCopierUtil.copyProperties(paper, PaperExp.class);
+		paperExp.setCourseLevel(paper.getLevel()==null?CourseLevel.ALL.getName():paper.getLevel().getName());
+		List<PaperDetailExp> objectiveDetails = new ArrayList<PaperDetailExp>();// 客观题
+		List<PaperDetailExp> subjectiveDetails = new ArrayList<PaperDetailExp>();// 主观题
+		double objectiveScore = 0;
+		double subjectiveScore = 0;
+		paperExp.setTitle(CommonUtils.PAPER_TITLE);
+		paperExp.setSubTitle(CommonUtils.PAPER_SUB_TITLE);
+		// 获取大题
+		List<PaperDetail> paperDetails = paperDetailRepo.findByPaper(paper);
+		int objectNumber = 1;// 客观题大题序号
+		int objetcUnitSum = 0;
+		for (int i = 0; i < paperDetails.size(); i++) {
+			PaperDetailExp paperDetailExp = BeanCopierUtil.copyProperties(paperDetails.get(i), PaperDetailExp.class);
+			List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo.findByPaperDetailOrderByNumber(paperDetails.get(i));
+			// 把大题分类 :客观题和主观题
+			List<PaperDetailUnitExp> paperDetailUnitExps = BeanCopierUtil.copyPropertiesOfList(paperDetailUnits,PaperDetailUnitExp.class);
+			// 选择题,套题下选择题 选项顺序重新排列
+			paperService.reorderChoicequestionOption(paperDetailUnitExps);
+			paperDetailExp.setPaperDetailUnits(paperDetailUnitExps);
+			boolean isSubjective = false;// 判断主观题和客观题
+			if (paperDetailUnits.get(0).getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
+				for (Question ques : paperDetailUnits.get(0).getQuestion().getSubQuestions()) {
+					if (ques.getQuestionType() == QuesStructType.TEXT_ANSWER_QUESTION) {
+						isSubjective = true;
+						break;
+					}
+				}
+			} else if (paperDetailUnits.get(0).getQuestionType() == QuesStructType.TEXT_ANSWER_QUESTION
+					 ||paperDetailUnits.get(0).getQuestionType() == QuesStructType.FILL_BLANK_QUESTION) {
+				isSubjective = true;
+			}
+			if (isSubjective) {
+				subjectiveDetails.add(paperDetailExp);
+				subjectiveScore += paperDetailExp.getScore();
+			}else{
+				objectiveDetails.add(paperDetailExp);
+				paperDetailExp.setNumber(objectNumber);
+				paperDetailExp.setCnNum(CommonUtils.toCHNum(objectNumber));
+				objectiveScore += paperDetailExp.getScore();
+				objetcUnitSum += paperDetailExp.getUnitCount();
+				objectNumber++;
+			}
+			setExpTitle(paperDetailExp);
+		}
+
+		paperExp.setObjectiveDetails(objectiveDetails);
+		paperExp.setSubjectiveDetails(subjectiveDetails);
+		paperExp.setObjectiveScore(objectiveScore);
+		paperExp.setSubjectiveScore(subjectiveScore);
+		if (objectiveDetails.size() > 0) {
+			setUnitExpNumber(objectiveDetails, 0);
+			appendScoreToQuestionBody(objectiveDetails);
+		}
+		if (subjectiveDetails.size() > 0) {
+			for (PaperDetailExp subDetail : subjectiveDetails) {
+				subDetail.setNumber(objectNumber);
+				subDetail.setCnNum(CommonUtils.toCHNum(objectNumber));
+				objectNumber++;
+			}
+			setUnitExpNumber(subjectiveDetails, objetcUnitSum);
+			appendScoreToQuestionBody(subjectiveDetails);
+		}
+		return paperExp;
+	}
+
+	public void setExpTitle(PaperDetailExp paperDetailExp) {
+		String title = "";
+		String totalScore = BigDecimal.valueOf(paperDetailExp.getScore()).stripTrailingZeros().toPlainString();
+		QuesStructType type = paperDetailExp.getPaperDetailUnits().get(0).getQuestionType();
+		String questionScore = checkPaperDetailUnitScore(paperDetailExp);
+		String scoreString = questionScore==null?"":"每小题"+questionScore+"分";
+		if (type == QuesStructType.SINGLE_ANSWER_QUESTION) {
+			paperDetailExp.setName("单项选择题");
+			title = "(本大题共" + paperDetailExp.getUnitCount() + "小题,"
+					+ scoreString + "共" + totalScore + "分)。"
+					+ "在每小题列出的四个备选中只有一个符合题目要求的,请将其选出并将“答题卡”的相应代码涂黑,错涂、多涂或未涂均无分";
+		} else if (type == QuesStructType.BOOL_ANSWER_QUESTION) {
+			paperDetailExp.setName("判断题");
+			title = "(本大题共" + paperDetailExp.getUnitCount() + "小题,"+ scoreString + "共" + totalScore+ "分。正确的填涂A、错误填涂B。错涂、多涂或未涂均无分)";
+		} else if (type == QuesStructType.FILL_BLANK_QUESTION) {
+			paperDetailExp.setName("填空题");
+			int blankNum = 0;
+			for (PaperDetailUnitExp unit:paperDetailExp.getPaperDetailUnits()){
+				String tempStr = unit.getQuestion().getQuesBody().replaceAll(FILL_BLANK_QUESTION_FLAG, "");
+				int lenTimes = (unit.getQuestion().getQuesBody().length() - tempStr.length()) / FILL_BLANK_QUESTION_FLAG.length();// 出现的次数
+				blankNum += lenTimes;
+			}
+			title = "(本大题共"+blankNum+"个空格,将每空答在答题卡 “1—" +blankNum+"”相应的序号上。"+"共"+totalScore + "分)";
+		} else {
+			title = "(本大题共"+paperDetailExp.getUnitCount()+"小题,"+scoreString+"共"+totalScore+"分)";
+		}
+		paperDetailExp.setTitle(title);
+	}
+
+	/**
+	 * 校验大题下的小题分数是不是一样
+	 * 
+	 * @param paperDetailExp
+	 * @return  如果分数一样,返回分数
+	 * 			如果分数不一样,返回 null
+	 */
+	protected String checkPaperDetailUnitScore(PaperDetailExp paperDetailExp) {
+		List<PaperDetailUnitExp> paperDetailUnitExps = paperDetailExp.getPaperDetailUnits();
+		Set<Double> scoreSet = new HashSet<Double>();
+		for (PaperDetailUnitExp unitExp : paperDetailUnitExps) {
+			if(unitExp.getQuestionType()==QuesStructType.NESTED_ANSWER_QUESTION){
+				List<Double> subScoreList =  unitExp.getSubScoreList();
+				for(Double score:subScoreList){
+					scoreSet.add(score);
+				}
+			}else{
+				scoreSet.add(unitExp.getScore());
+			}
+		}
+		if(scoreSet.size() == 1){
+			return scoreSet.iterator().next()+"";
+		}
+		return null;
+	}
+
+	protected void setUnitExpNumber(List<PaperDetailExp> paperDetails,int startIndxt) throws Exception {
+		int subNum = startIndxt;
+		for (PaperDetailExp paperDetail : paperDetails) {
+			List<PaperDetailUnitExp> paperDetailUnitExpList = paperDetail.getPaperDetailUnits();
+			//对大题下的小题进行排序
+			Collections.sort(paperDetailUnitExpList);
+			for (PaperDetailUnitExp paperDetailUnit:paperDetailUnitExpList) {
+				List<QuesOption> optionList = paperDetailUnit.getQuestion().getQuesOptions();
+				if (optionList != null && optionList.size() > 0) {
+					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) {
+						int curSubNum = ++subNum;
+						subQues.setQuesBodyWord(setSubQuesNum(subQues.getQuesBodyWord(),curSubNum));
+						subQues.setQuesAnswerWord(setSubQuesNum(subQues.getQuesAnswerWord(),curSubNum));
+						subQues.setQuesBodyWord(replaceQuesBlank(subQues.getQuesBodyWord(),curSubNum));
+						List<QuesOption> subOptionList = subQues.getQuesOptions();
+						if (subOptionList != null && subOptionList.size() > 0) {
+							int sub_index = 0;
+							for (QuesOption quesOption : subOptionList) {
+								quesOption.setOptionBodyWord(setOptionNum(quesOption.getOptionBodyWord(),getOptionNum(sub_index)));
+								sub_index++;
+							}
+						}
+					}
+				} else {
+					int curSubNum = ++subNum;
+					question.setQuesBodyWord(setSubQuesNum(question.getQuesBodyWord(), curSubNum));
+					question.setQuesAnswerWord(setSubQuesNum(question.getQuesAnswerWord(),curSubNum));
+					question.setQuesBodyWord(replaceQuesBlank(question.getQuesBodyWord(),curSubNum));
+				}
+			}
+		}
+	}
+	
+	/**
+     * 替换填空
+     * 将###替换为下划线_______
+     * @param wordMl
+     * @param num
+     * @return
+     * @throws Exception
+     */
+	protected 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();
+                                str = str.replaceAll("###","______");
+                                text.setValue(str);
+                                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();
+    }
+	
+	/**
+	 * 将数字1,2,3,4转化成A,B,C,D
+	 * @param number
+	 * @return
+	 */
+    protected String getOptionNum(int number){
+        char optionNum = (char)(65 + number);
+        return String.valueOf(optionNum);
+    }
+
+    /**
+     * 获取当前试卷下所有试题WordPkg
+     * @param id
+     * @return
+     */
+    protected List<WordprocessingMLPackage> getPkgList(String id){
+        Paper paper = paperRepo.findOne(id);
+        List<WordprocessingMLPackage> wordMLPackages = paperDetailUnitRepo.findByPaper(paper)
+                .stream().map(PaperDetailUnit::getQuestion).collect(Collectors.toList())
+                .stream().map(Question::getPkgObj).collect(Collectors.toList());
+        return wordMLPackages;
+    }
+
+    /**
+     * 设置题号
+     * @param quesBodyWordMl
+     * @param num
+     * @return
+     * @throws Exception
+     */
+    public String setSubQuesNum(String quesBodyWordMl,int num) throws Exception {
+        String tmpStr = DocxProcessUtil.BODY_HEADER + quesBodyWordMl + DocxProcessUtil.BODY_TAIL;
+        Body body = (Body)XmlUtils.unmarshalString(tmpStr,Context.jc,Body.class);
+        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 optionWordMl
+     * @param num
+     * @return
+     * @throws Exception
+     */
+    public String setOptionNum(String optionWordMl,String num) throws Exception {
+        String tmpStr = DocxProcessUtil.BODY_HEADER + optionWordMl + DocxProcessUtil.BODY_TAIL;
+        Body body = (Body)XmlUtils.unmarshalString(tmpStr,Context.jc,Body.class);
+        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 details
+     * @throws Exception
+     */
+    protected void appendScoreToQuestionBody(List<PaperDetailExp> details) throws Exception{
+    	for(PaperDetailExp paperDetailExp:details){
+    		if(checkPaperDetailUnitScore(paperDetailExp)==null){
+    			for(PaperDetailUnitExp paperDetailUnit:paperDetailExp.getPaperDetailUnits()){
+    				Question question = paperDetailUnit.getQuestion();
+    				String questionBodyWord = appendScoreToQuestionBody(question.getQuesBodyWord(),paperDetailUnit.getScore());
+    				question.setQuesBodyWord(questionBodyWord);
+    			}
+    		}
+    	}
+    }
+    
+    /**
+     * 在题干上设置分数
+     * @throws Exception 
+     */
+    protected String appendScoreToQuestionBody(String quesBodyWordMl,double score) throws Exception{
+    	String tmpStr = DocxProcessUtil.BODY_HEADER + quesBodyWordMl + DocxProcessUtil.BODY_TAIL;
+        Body body = (Body)XmlUtils.unmarshalString(tmpStr,Context.jc,Body.class);
+        List<Object> pList = body.getContent();
+        int index = 0;
+        for(Object pObj:pList){
+            if(index < pList.size()-1){
+                break;
+            }
+            P p = (P) pObj;
+            List<Object> pContent = p.getContent();
+            R run = new R();
+            Text text = new Text();
+            int scoreInt = (int)score;
+            text.setValue("("+scoreInt+"分)");
+            run.getContent().add(text);
+            pContent.add(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 paperId
+     * @param currNum
+     * ObjectId("591ead1290994d57cd453464")
+     * @throws IOException 
+     */
+    protected void uploadComputerTestFile(ExtractConfig extractConfig,AccessUser accessUser) throws IOException{
+    	List<ComputerTestPaper>  computerTestPaperList = buildComputerTestPapers(extractConfig);
+    	String currentTimeStr = CommonUtils.getCurNum();
+    	for(int i = 0;i<computerTestPaperList.size();i++){
+    		ComputerTestPaper computerTestPaper = computerTestPaperList.get(i);
+    		String jsonDirectoryName = currentTimeStr+UNDERSCORE+ExamFileType.COMPUTERTEST_PACKAGE.name()+UNDERSCORE+i;
+    		String jsonDirectoryPath = TEMP_FILE_EXP + File.separator + jsonDirectoryName;
+    		//新建文件夹
+    		File dirFile = new File(jsonDirectoryPath);
+    		if(!dirFile.exists()){
+    			dirFile.mkdirs();
+    		}
+    		//将computerTestPaper对象生成JSON文件存放在jsonDirectoryPath中
+    		makeComputerTestPaperToJsonFile(extractConfig,computerTestPaper,jsonDirectoryPath);
+			//下载试卷中的音频文件到jsonDirectoryPath文件夹中
+			downloadQuestionAudio(computerTestPaper,jsonDirectoryPath,extractConfig.getExamId()+"");
+			//将文件夹打包成zip压缩包放在docxExport下
+			FileDisposeUtil.fileToZip(jsonDirectoryPath,"docxExport",jsonDirectoryName);
+			//上传zip压缩包到又拍云
+			File zipFile = new File(TEMP_FILE_EXP+jsonDirectoryName+ZIP_SUFFIX);
+			String zipUpyunFilePath = uploadUrl+extractConfig.getOrgId()+"/"+jsonDirectoryName+ZIP_SUFFIX;
+			UpYun upyun = new UpYun(bucketName,userName,password);
+			upyun.writeFile(zipUpyunFilePath,zipFile,true);
+			//保存数据库记录
+			examFileService.saveExamFile(new ExamFile(extractConfig,zipUpyunFilePath,ExamFileType.COMPUTERTEST_PACKAGE,computerTestPaper.getName(),ZIP_SUFFIX),accessUser);
+			//删除本地生成的文件
+			zipFile.delete();
+			FileUtils.deleteQuietly(dirFile);
+    	}
+    }
+    
+    /**
+     * 将computerTestPaper对象生成JSON文件存放在jsonDirectoryPath中
+     * @param extractConfig
+     * @param computerTestPaper
+     * @param jsonDirectoryPath
+     */
+    private void makeComputerTestPaperToJsonFile(ExtractConfig extractConfig,ComputerTestPaper computerTestPaper,String jsonDirectoryPath){
+		//创建新的JSON文件
+		File file = new File(jsonDirectoryPath+File.separator+extractConfig.getCourseCode()+".json");
+		//将对象转成 json对象
+		Gson gson = new Gson();
+		String strJSON = gson.toJson(computerTestPaper);
+		//生成文件流写入JSON文件
+		FileOutputStream outputStream;
+		try {
+			outputStream = new FileOutputStream(file);
+			byte b[] = strJSON.getBytes();
+			outputStream.write(b);
+			outputStream.close();
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+    }
+    
+    /**
+     * 下载题目音频文件
+     * @param computerTestPaper
+     */
+    private void downloadQuestionAudio(ComputerTestPaper computerTestPaper,String jsonDirectoryPath,String examId){
+    	List<ComputerTestPaperDetail> details = computerTestPaper.getDetails();
+		for(ComputerTestPaperDetail detail:details){
+			List<ComputerTestQuestion> questions = detail.getQuestions();
+			for(ComputerTestQuestion question:questions){
+				getBodyAndOptionAudioFile(question,question.getBody(),jsonDirectoryPath,computerTestPaper,examId);
+				List<ComputerTestOption> options = question.getOptions();
+				for(ComputerTestOption option:options){
+					getBodyAndOptionAudioFile(question,option.getBody(),jsonDirectoryPath,computerTestPaper,examId);
+				}
+				//子题音频处理
+				//List<ComputerTestQuestion> subQuestions = question.getSubQuestions();
+			}
+		}
+    }
+    
+    private void getBodyAndOptionAudioFile(ComputerTestQuestion computerTestQuestion,Sections bodySections,String jsonDirectoryPath,ComputerTestPaper computerTestPaper,String examId){
+    	List<Section> sectionList = bodySections.getSections();
+		for(Section section:sectionList){
+			List<Block> blocks = section.getBlocks();
+			for(Block block:blocks){
+				if("audio".equals(block.getType())){
+					PaperDetailUnit paperDetailUnit = paperDetailUnitRepo.findById(computerTestQuestion.getId());
+					QuestionAudio audio = questionAudioService.findByQuestionIdAndFileName(paperDetailUnit.getQuestion().getId(),block.getValue());
+					if(audio!=null){
+						FileDisposeUtil.saveUrlAs(downloadUrl+audio.getFileUrl(),jsonDirectoryPath+File.separator+block.getValue());
+						AudioTimeConfig audioTime = new AudioTimeConfig();
+						audioTime.setCourseCode(computerTestPaper.getCourseCode());
+						audioTime.setExamId(examId);
+						audioTime.setGroupCode(computerTestPaper.getGroupCode());
+						audioTime.setPaperDetailUnit(paperDetailUnit);
+						AudioTimeConfig audioTimeConfig = audioTimeConfigRepo.findOne(Example.of(audioTime));
+						if(audioTimeConfig!=null){
+							block.setPlayTime(audioTimeConfig.getPlayTime());
+						}
+					}
+				}
+			}
+		}
+    }
+    
+    /**
+     * 构建机考数据包实体类
+     * @param extractConfig
+     * @return
+     */
+    private List<ComputerTestPaper> buildComputerTestPapers(ExtractConfig extractConfig){
+    	List<ExamPaper> examPapers = extractConfig.getExamPaperList();
+    	List<ComputerTestPaper> computerTestPapers = new ArrayList<ComputerTestPaper>();
+    	//循环得到试卷
+    	for(ExamPaper examPaper:examPapers){
+    		
+    		Paper paper = examPaper.getPaper();
+    		//得到所有旧对象的大题对象
+    		List<PaperDetail> paperDetails = paperService.findPaperDetailsById(paper.getId());
+    		//通过 paper 对象 ,生成新的  ComputerTestPaper 对象
+    		ComputerTestPaper computerTestPaper = new ComputerTestPaper(paper,examPaper.getGroupCode());
+    		List<ComputerTestPaperDetail> details = new ArrayList<ComputerTestPaperDetail>();
+    		//遍历所有旧大题对象,得到小题对象的集合
+    		for(PaperDetail paperDetail:paperDetails){
+    			List<PaperDetailUnit> paperDetailUnits = paperDetailService.getUnitsByPaperDetailId(paperDetail.getId());
+    			ComputerTestPaperDetail computerTestPaperDetail = new ComputerTestPaperDetail(paperDetail);
+    			List<ComputerTestQuestion> questions = new ArrayList<ComputerTestQuestion>();
+    			//遍历所有的小题对象
+    			for(int i = 0;i<paperDetailUnits.size();i++){
+    				PaperDetailUnit paperDetailUnit = paperDetailUnits.get(i);
+    				//根据旧的小题对象,生成新的小题对象
+    				ComputerTestQuestion  computerTestQuestion = new ComputerTestQuestion(paperDetailUnit);
+    				//设置小题题号
+    				computerTestQuestion.setNumber(i+1);
+    				//得到小题题干
+    				computerTestQuestion.setBody(getBody(paperDetailUnit.getQuestion()));
+    				//得到小题所有选项
+    				computerTestQuestion.setOptions(getOption(paperDetailUnit.getQuestion()));
+    				//查询小题中的 套题
+    				List<Question> subQuestionsList = paperDetailUnit.getQuestion().getSubQuestions();
+    				//判断这个小题中是否有套题
+    				if(subQuestionsList!=null&&subQuestionsList.size()>0){
+    					List<ComputerTestQuestion> subQuestions = new ArrayList<ComputerTestQuestion>();
+    					//遍历每个套题
+    					for(int j = 0;j<subQuestionsList.size();j++){
+    						Question subQuestion = subQuestionsList.get(j);
+        					ComputerTestQuestion subcomputerTestQuestion = new ComputerTestQuestion(subQuestion);
+        					//设置套题中小题题号
+        					subcomputerTestQuestion.setNumber(j+1);
+        					subcomputerTestQuestion.setBody(getBody(subQuestion));
+        					subcomputerTestQuestion.setOptions(getOption(subQuestion));
+        					subQuestions.add(subcomputerTestQuestion);
+    					}
+        				computerTestQuestion.setSubQuestions(subQuestions);
+    				}
+    				questions.add(computerTestQuestion);
+    			}
+    			computerTestPaperDetail.setQuestions(questions);
+    			details.add(computerTestPaperDetail);
+    		}
+    		computerTestPaper.setDetails(details);
+    		computerTestPapers.add(computerTestPaper);
+    	}
+    	return computerTestPapers;
+    }
+
+	private Sections getBody(Question question){
+    	Sections body = new Sections();
+		List<Section> sections = new ArrayList<Section>(); 
+		//得到小题题干
+		String questionBodyString = question.getQuesBody();
+		//得到小题题干行数
+		String[] questionRowStrings = questionBodyString.split("</p>");
+		for(int i = 0;i<questionRowStrings.length;i++){
+			Section section = new Section();
+			//将小题题干拆分为Block集合
+			section.setBlocks(disposeQuestionBodyOrOption(questionRowStrings[i]));
+			sections.add(section);
+		}
+		body.setSections(sections);
+		return body;
+    }
+    
+    private List<ComputerTestOption> getOption(Question question){
+    	//得到小题选项
+		List<QuesOption> quesOptions = question.getQuesOptions();
+		List<ComputerTestOption> options = new ArrayList<ComputerTestOption>();
+		//遍历小题选项
+		if(quesOptions!=null&&quesOptions.size()>0){
+			for(QuesOption quesOption: quesOptions){
+				ComputerTestOption option = new ComputerTestOption();
+				option.setNumber(new Integer(quesOption.getNumber()));
+				option.setCorrect(quesOption.getIsCorrect()==1?true:false);
+				Sections body = new Sections();
+				
+				List<Section> sections = new ArrayList<Section>();
+				//得到小题选项
+				String optionString = quesOption.getOptionBody();
+				String[] optionStrings = optionString.split("</p>");
+				for(int i = 0;i<optionStrings.length;i++){
+					Section section = new Section();
+					section.setBlocks(disposeQuestionBodyOrOption(optionStrings[i]));
+					sections.add(section);
+				}
+				body.setSections(sections);
+				option.setBody(body);
+				options.add(option);
+			}
+		}
+		return options;
+    }
+      
+    private List<Block> disposeQuestionBodyOrOption(String questionRow) {
+    	List<Block> blocks = new ArrayList<Block>();
+    	//去掉每行里面的<p>,<span>,</span>标签
+    	questionRow = questionRow.replaceAll("<p>", "")
+			    				 .replaceAll("</p>", "")
+			    				 .replaceAll("<span>", "")
+			    				 .replaceAll("</span>", "")
+			    				 .replaceAll("</a>", "");
+		String[] questionRowStrings = questionRow.split("<|/>|>");
+    	for(int i = 0;i<questionRowStrings.length;i++){
+    		Block block = new Block();
+			//判断是否有图片
+			if(questionRowStrings[i].startsWith("img")){
+				questionRowStrings[i] = "<"+questionRowStrings[i]+">";
+				Map<String, Object> param  = new HashMap<String, Object>();
+				//需要继续做截取,取到Parma
+				block.setType("image");
+				//获取图片的路径
+				List<String> strSrcList = getImg(questionRowStrings[i], "src");
+				if(strSrcList.size()>0){
+					String strSrc = strSrcList.get(0).replaceAll("src=\"", "").replaceAll("\"", "");
+					block.setValue(strSrc);
+				}
+				//获取图片的高度
+				List<String> strHeightList = getImg(questionRowStrings[i], "height");
+				if(strHeightList.size()>0){
+					String strHeight = strHeightList.get(0).replaceAll("height=\"", "").replaceAll("\"", "");
+					param.put("height", strHeight);
+				}
+				//获取图片的宽度
+				List<String> strWidthList = getImg(questionRowStrings[i], "width");
+				if(strHeightList.size()>0){
+					String strWidth = strWidthList.get(0).replaceAll("width=\"", "").replaceAll("\"", "");
+					param.put("width", strWidth);
+				}
+				block.setParam(param);
+				blocks.add(block);
+			}else if(questionRowStrings[i].startsWith("a")
+					&&questionRowStrings[i].contains("id")
+					&&questionRowStrings[i].contains("name")){	//处理音频
+				questionRowStrings[i] = "<"+questionRowStrings[i]+">";
+				block.setType("audio");
+				block.setValue(getAudioName(questionRowStrings[i]));
+				blocks.add(block);
+			}else{
+				block.setType("text");
+				questionRowStrings[i] = questionRowStrings[i].replaceAll("&nbsp;","");
+				block.setValue(questionRowStrings[i]);
+				blocks.add(block);
+			}
+    	}
+		return blocks;
+	}
+
+	/**
+     * 获取图片里面的路径,长度,宽度
+     * @param s
+     * @param str
+     * @return
+     */
+    private List<String> getImg(String s,String str)
+    {
+        String regex;
+        List<String> list = new ArrayList<String>();
+        regex = str + "=\"(.*?)\"";
+        Pattern pa = Pattern.compile(regex, Pattern.DOTALL);
+        Matcher ma = pa.matcher(s);
+        while (ma.find())
+        {
+            list.add(ma.group());
+        }
+        return list;
+    }
+
+    private String getAudioName(String questionStr){
+    	Pattern pattern = Pattern.compile("a.*");
+		Matcher matcher = pattern.matcher(questionStr);
+		while(matcher.find()){
+		      String result = matcher.group();
+		      String idstr = "id=\".*?\"";
+		      Pattern pattern02 = Pattern.compile(idstr);
+		      Matcher matcher02 = pattern02.matcher(result);
+		      while(matcher02.find()){
+		    	  return matcher02.group().replaceAll("id=\"", "").replaceAll("\"", "");
+		      }
+		}
+		return "";
+    }
+    
+	/**
+     * 生成试卷或答案Word,上传至又拍云
+     * @param orgName
+     * @param dataMap
+     * @param extractConfig
+     * @param paperId
+     * @param accessUser
+     */
+    protected void uploadPaperOrAnswerFile(PaperExp paperExp,ExtractConfig extractConfig,AccessUser accessUser,String currNum,Template template,ExamFileType examFileType){
+    	String paperfileName = currNum+examFileType.name()+DOCX_SUFFIX;
+    	try {
+			DocxProcessUtil.exportWord(paperExp,paperfileName,template);
+			DocxProcessUtil.processImage(paperfileName,getPkgList(paperExp.getId()));
+			File file  = new File(TEMP_FILE_EXP+paperfileName);
+			String paperFilePath = uploadUrl+extractConfig.getOrgId()+"/"+paperfileName;
+            UpYun upyun = new UpYun(bucketName,userName,password);
+			upyun.writeFile(paperFilePath,file,true);
+			examFileService.saveExamFile(new ExamFile(paperExp.getId(),extractConfig,paperFilePath,examFileType,DOCX_SUFFIX),accessUser);
+			file.delete();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+    }
+    
+    /**
+     * 生成试卷结构,上传至又拍云
+     */
+    protected void uploadPaperStructure(PaperExp paperExp,ExtractConfig extractConfig,AccessUser accessUser,String currNum,List<QuestionTypeNum> questionTypeNums) {
+    	exportObjectiveQuestionStructures(paperExp,extractConfig,accessUser,currNum,questionTypeNums);
+    	exportSubjectiveQuestionStructures(paperExp,extractConfig,accessUser,currNum);
+	}
+    
+    /**
+     * 获得客观题导出结构,并上传至又拍云
+     * @param paperExp
+     * @return
+     */
+    protected void exportObjectiveQuestionStructures(PaperExp paperExp,ExtractConfig extractConfig,AccessUser accessUser,String currNum,List<QuestionTypeNum> questionTypeNums){
+    	String objectiveFilename = currNum+ExamFileType.PAPER_STRUCTURE_OBJECTIVE.name()+EXCEL_SUFFIX;
+    	List<PaperDetailExp> objectiveDetails = paperExp.getObjectiveDetails();
+    	//根据试卷结构导出设置中的数量补齐客观题
+    	fillObjectiveQuestions(objectiveDetails,questionTypeNums);
+    	List<ObjectiveQuestionStructure> objectiveQuestionStructureList = new ArrayList<ObjectiveQuestionStructure>();
+    	for(PaperDetailExp paperDetailExp:objectiveDetails){
+    		for(PaperDetailUnitExp unit:paperDetailExp.getPaperDetailUnits()){
+    			objectiveQuestionStructureList.add(new ObjectiveQuestionStructure(paperExp,paperDetailExp,unit));
+    		}
+    	}
+    	ExcelWriter objectiveExcelExporter = new ExcelWriter(ObjectiveQuestionStructure.class); 
+		try {
+			File file = new File(TEMP_FILE_EXP+objectiveFilename);
+			FileOutputStream out = new FileOutputStream(file);
+			objectiveExcelExporter.write(objectiveFilename,objectiveQuestionStructureList,out);
+			String objectiveFilePath = uploadUrl+extractConfig.getOrgId()+"/"+objectiveFilename;
+            UpYun upyun = new UpYun(bucketName,userName,password);
+			upyun.writeFile(objectiveFilePath,file,true);
+			examFileService.saveExamFile(new ExamFile(paperExp.getId(),extractConfig,objectiveFilePath,ExamFileType.PAPER_STRUCTURE_OBJECTIVE,EXCEL_SUFFIX),accessUser);
+			file.delete();
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+    }
+    
+    /**
+     * 根据试卷结构导出设置中的数量补齐客观题
+     * @param objectiveDetails
+     * @param questionTypeNums
+     */
+    public void fillObjectiveQuestions(List<PaperDetailExp> objectiveDetails,List<QuestionTypeNum> questionTypeNums) {
+    	for(PaperDetailExp paperDetailExp:objectiveDetails){
+    		List<PaperDetailUnitExp> paperDetailUnits = paperDetailExp.getPaperDetailUnits();
+    		//1.将大题中的小题排序
+    		Collections.sort(paperDetailUnits);
+    		//2.将小题的number重新设置
+    		for(int i = 0;i<paperDetailUnits.size();i++){
+    			PaperDetailUnitExp paperDetailUnitExp = paperDetailUnits.get(i);
+    			paperDetailUnitExp.setNumber(i+1);
+    		}
+    		//3.根据试卷结构导出设置中的数量补齐客观题
+    		QuesStructType type = paperDetailUnits.get(0).getQuestionType();
+    		int unitSize = paperDetailUnits.size();
+    		for(QuestionTypeNum questionTypeNum:questionTypeNums){
+    			if(type==questionTypeNum.getQuestionType()){
+    				int length = questionTypeNum.getQuantity()-unitSize;
+    				for(int i = 0;i<length;i++){
+    					PaperDetailUnitExp paperDetailUnitExp = new PaperDetailUnitExp();
+    					paperDetailUnitExp.setQuestionType(type);
+    					paperDetailUnitExp.setScore((double) 0);
+    					paperDetailUnitExp.setNumber(unitSize+(i+1));
+    					Question question = new Question();
+    					question.setQuesAnswer("#");
+    					paperDetailUnitExp.setQuestion(question);
+    					paperDetailUnits.add(paperDetailUnitExp);
+    				}
+    			}
+    		}
+    	}
+	}
+
+	/**
+     * 检查客观题数量是否小于试卷结构导出设置的数量
+     * @param paperExp
+     * @param objectiveDetails
+     * @param questionTypeNums
+     * @return
+     */
+    protected void checkObjectiveDetailsNum(PaperExp paperExp,List<PaperDetailExp> objectiveDetails,List<QuestionTypeNum> questionTypeNums) {
+	   for(PaperDetailExp paperDetailExp:objectiveDetails){
+			for(QuestionTypeNum typeNum:questionTypeNums){
+				QuesStructType quesStructType = paperDetailExp.getPaperDetailUnits().get(0).getQuestionType();
+				if(typeNum.getQuestionType()==quesStructType){
+					if(paperDetailExp.getUnitCount()>typeNum.getQuantity()){
+						throw new RuntimeException("课程最大题量超出设定范围,请核实后重新设置导出规则!");
+					}
+				}
+			}
+		}
+    }
+
+   	/**
+     * 获得主观题导出结构,并上传至又拍云
+     * @param paperExp
+     * @return
+     */
+    protected void exportSubjectiveQuestionStructures(PaperExp paperExp,ExtractConfig extractConfig,AccessUser accessUser,String currNum){
+    	String subjectiveFileName = currNum+ExamFileType.PAPER_STRUCTURE_SUBJECTIVE.name()+EXCEL_SUFFIX;
+    	List<PaperDetailExp> subjectiveDetails = paperExp.getSubjectiveDetails();
+    	List<SubjectiveQuestionStructure> subjectiveQuestionStructureList = new ArrayList<SubjectiveQuestionStructure>();
+    	for(PaperDetailExp paperDetailExp:subjectiveDetails){
+    		for(PaperDetailUnitExp unit:paperDetailExp.getPaperDetailUnits()){
+    			subjectiveQuestionStructureList.add(new SubjectiveQuestionStructure(paperExp,paperDetailExp,unit));
+    		}
+    	}
+    	ExcelWriter subjectiveExcelExporter = new ExcelWriter(SubjectiveQuestionStructure.class); 
+		try {
+			File file = new File(TEMP_FILE_EXP+subjectiveFileName);
+			FileOutputStream out = new FileOutputStream(file);
+			subjectiveExcelExporter.write(subjectiveFileName,subjectiveQuestionStructureList,out);
+			String subjectiveFilePath = uploadUrl+extractConfig.getOrgId()+"/"+subjectiveFileName;
+            UpYun upyun = new UpYun(bucketName,userName,password);
+			upyun.writeFile(subjectiveFilePath,file,true);
+			examFileService.saveExamFile(new ExamFile(paperExp.getId(),extractConfig,subjectiveFilePath,ExamFileType.PAPER_STRUCTURE_SUBJECTIVE,EXCEL_SUFFIX),accessUser);
+			file.delete();
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+    }
+    
+}
+